Что делает команда git abuse
Перейти к содержимому

Что делает команда git abuse

  • автор:

Переписывание истории репозитория кода, или почему иногда можно git push -f

Одно из первых наставлений, которое молодой падаван получает вместе с доступом к git-репозиториям, звучит так: «никогда не ешь жёлтый снег делай git push -f ». Поскольку это одна из сотен максим, которые нужно усвоить начинающему инженеру-разработчику ПО, никто не тратит время на уточнение, почему именно так нельзя делать. Это как младенцы и огонь: «спички детям не игрушки» и баста. Но мы растём и развиваемся как люди и как профессионалы, и однажды вопрос «а почему, собственно?» встаёт в полный рост. Эта статья написана по мотивам внутреннего митапа на тему: «Когда можно и нужно переписывать историю коммитов», который я проводил, когда работал в компании FunCorp.

Я слышал, что умение ответить на этот вопрос на собеседовании в некоторых компаниях является критерием прохождения собеседования на сеньорские позиции. Но чтобы лучше понять ответ на него, нужно разобраться, почему вообще плохо переписывание истории?

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

На самом низком уровне git-репо представляет собой набор объектов и указателей на них. Каждый объект имеет свой уникальный 40-значный хэш (20 байт, записанные в 16-ричной системе), который вычисляется на основе содержимого объекта.

Основные типы объектов — это blob (просто содержимое файла), tree (набор указателей на blobs и другие trees) и commit. Объект типа commit представляет собой только указатель на tree, на предыдущий коммит и служебную информацию: дата/время, автор и комментарий.

Где здесь ветки и тэги, которыми мы привыкли оперировать? А они не являются объектами, они являются просто указателями: ветка указывает на последний коммит в ней, тэг — на произвольный коммит в репо. То есть когда мы в IDE или GUI-клиенте видим красиво нарисованные веточки с кружочками-коммитами на них — они строятся на лету, пробегая по цепочкам коммитов от концов веток вниз к «корню». Самый первый коммит в репо не имеет предыдущего, вместо указателя там null.

Важный для понимания момент: один и тот же коммит может фигурировать в нескольких ветках одновременно. Коммиты не копируются при создании новой ветки, она просто начинает «расти» с того места, где был HEAD в момент отдачи команды git checkout -b .

Итак, почему же переписывание истории репозитория вредно?

Во-первых, и это очевидно, при загрузке новой истории в репозитории, с которым работает команда инженеров, другие люди могут просто потерять свои изменения. Команда git push -f удаляет из ветки на сервере все коммиты, которых нет в локальной версии, и записывает новые.

Почему-то мало кто знает, что довольно давно у команды git push существует «безопасный» ключ —force-with-lease , который заставляет команду завершиться с ошибкой, если в удалённом репозитории есть коммиты, добавленные другими пользователями. Я всегда рекомендую использовать его вместо -f/—force .

Update 2023: начиная с git версии 2.30 появился дополнительный ключ —force-if-includes , которая проверяет, что текущая вершина ветки на сервере достижима из рефлога локальной ветки, т.е. что все изменения, присутствующие на сервере, интегрированы в локальную версию.

Вторая причина, по которой команда git push -f считается вредной, заключается в том, что при попытке слияния (merge) ветки с переписанной историей с ветками, где она сохранилась (точнее, сохранились коммиты, удалённые из переписанной истории), мы получим адское число конфликтов (по числу коммитов, собственно). На это есть простой ответ: если аккуратно соблюдать Gitflow или Gitlab Flow, то такие ситуации, скорее всего, даже не возникнут.

И наконец есть неприятная побочка переписывания истории: те коммиты, которые как бы удаляются при этом из ветки, на самом деле, никуда не исчезают и просто остаются навечно висеть в репо. Мелочь, но неприятно. К счастью, эту проблему разработчики git тоже предусмотрели, введя команду сборки мусора git gc —prune . Большинство git-хостингов, как минимум GitHub и GitLab, время от времени производят эту операцию в фоне.

Итак, развеяв опасения перед изменением истории репозитория, можно, наконец, перейти к главному вопросу: зачем оно нужно и когда оправдано?

На самом деле, я уверен, что практически каждый из более-менее активных пользователей git хоть раз, да изменял историю, когда вдруг оказывалось, что в последнем коммите что-то пошло не так: вкралась досадная опечатка в код, сделал коммит не от того пользователя (с личного e-mail вместо рабочего или наоборот), забыл добавить новый файл (если вы, как я, любите пользоваться git commit -a ). Даже изменение описания коммита приводит к необходимости его перезаписи, ведь хэш считается и от описания тоже!

Но это тривиальный случай. Давайте рассмотрим более интересные.

Допустим, вы сделали большую фичу, которую пилили несколько дней, отсылая ежедневно результаты работы в репозиторий на сервере (4-5 коммитов), и отправили свои изменения на ревью. Двое-трое неутомимых ревьюверов закидали вас крупными и мелкими рекомендациями правок, а то и вовсе нашли косяки (ещё 4-5 коммитов). Затем QA нашли несколько краевых случаев, тоже требующих исправлений (ещё 2-3 коммита). И наконец при интеграции выяснились какие-то несовместимости или попадали автотесты, которые тоже надо пофиксить.

Если теперь нажать, не глядя, кнопку Merge, то в главную ветку (у многих она по старинке называется master) вольются полтора десятка коммитов типа «My feature, day 1», «Day 2», «Fix tests», «Fix review» и т.д. От этого, конечно, помогает режим squash, который сейчас есть и в GitHub, и в GitLab, но с ним надо быть осторожными: во-первых, он может заменить описание коммита на что-то непредсказуемое, а во-вторых — заменить автора фичи на того, кто нажал кнопку Merge (у нас это вообще робот, помогающий релиз-инженеру собрать сегодняшний деплой). Поэтому самым простым будет перед окончательной интеграцией в релиз схлопнуть все коммиты ветки в один при помощи git rebase .

Но бывает также, что к код-ревью вы уже подошли с историей репо, напоминающей салат «Оливье». Такое бывает, если фича пилилась несколько недель, ибо была плохо декомпозирована или, хотя за это в приличных коллективах бьют канделябром, требования изменились в процессе разработки. Вот, например, реальный merge request, который приехал ко мне на ревью две недели назад:

У меня рука машинально потянулась к кнопке «Report abuse», потому что как ещё можно охарактеризовать реквест из 50 коммитов с почти 2000 изменённых строк? И как его, спрашивается, ревьюить?

Честно говоря, у меня ушло два дня просто на то, чтобы заставить себя приступить к этому ревью. И это нормальная реакция для инженера; кто-то в подобной ситуации, просто не глядя, жмёт Approve, понимая, что за разумное время всё равно не сможет сделать работу по обзору этого изменения с достаточным качеством.

Но есть способ облегчить жизнь товарищу. Помимо предварительной работы по лучшей декомпозиции задачи, уже после завершения написания основного кода можно привести историю его написания в более логичный вид, разбив на атомарные коммиты с зелёными тестами в каждом: «создал новый сервис и транспортный уровень для него», «построил модели и написал проверку инвариантов», «добавил валидацию и обработку исключений», «написал тесты».
Каждый из таких коммитов можно ревьюить по отдельности (и GitHub, и GitLab это умеют) и делать это набегами в моменты переключения между своими задачами или в перерывах.

Сделать это всё нам поможет всё тот же git rebase с ключом —interactive . В качестве параметра надо передать ему хэш коммита, начиная с которого нужно будет переписать историю. Если речь о последних 50 коммитах, как в примере на картинке, можно написать git rebase —interactive HEAD~50 (подставьте вместо “50” вашу цифру).

Кстати, если вы в процессе работы над задачей подливали к себе ветку master, то сначала надо будет сделать rebase на эту ветку, чтобы merge-коммиты и коммиты из мастера не путались у вас под ногами.

Вооружившись знаниями о внутреннем устройстве git-репозитория, понять принцип действия rebase на master будет несложно. Эта команда берёт все коммиты в нашей ветке и меняет родителя первого из них на последний коммит в ветке master. См. схему:

Иллюстрации взяты из книги Pro Git

Если изменения в C4 и C3 конфликтуют, то после разрешения конфликтов коммит C4 изменит своё содержание, поэтому он переименован на второй схеме в C4’.

Таким образом, вы получите ветку, состоящую только из ваших изменений, и растущую из вершины master. Само собой, master должен быть актуальным. Можно просто использовать версию с сервера: git pull —rebase origin/master (как известно, git pull равносилен git fetch && git merge , а ключ —rebase заставит git сделать rebase вместо merge).

Вернёмся наконец к git rebase —interactive . Его делали программисты для программистов, и понимая, какой стресс люди будут испытывать в процессе, постарались максимально сохранить нервы пользователя и избавить его от необходимости чрезмерно напрягаться. Вот что вы увидите на экране:

Это репозиторий популярного пакета Guzzle. Похоже, что rebase ему не помешал бы…

В текстовом редакторе открывается сформированный файл. Внизу вас ожидает подробная справка о том, что тут вообще делать. Далее в режиме простого редактирования вы решаете, что делать с коммитами в вашей ветке. Всё просто, как палка: pick — оставить как есть, reword — поменять описание коммита, squash — слить воедино с предыдущим (процесс работает снизу вверх, то есть предыдущий — это который строчкой ниже), drop — вообще удалить, edit — и это самое интересное — остановиться и замереть. После того, как git встретит команду edit, он встанет в позицию, когда изменения в коммите уже добавлены в режим staged. Вы можете поменять всё, что угодно в этом коммите, добавить поверх него ещё несколько, и после этого скомандовать git rebase —continue , чтобы продолжить процесс rebase.

Да, и кстати, вы можете поменять коммиты местами. Возможно, это создаст конфликты, но в целом процесс rebase редко обходится совсем уж без конфликтов. Как говорится, снявши голову, по волосам не плачут.

Если вы запутались и кажется, что всё пропало, у вас есть кнопка аварийного катапультирования git rebase —abort , которая немедленно вернёт всё как было.

Вы можете повторять rebase несколько раз, затрагивая только части истории, и оставляя остальные нетронутыми при помощи pick, придавая своей истории всё более и более законченный вид, как гончар кувшину. Хорошим тоном, как я уже написал выше, будет сделать так, что тесты в каждом коммите будут зелёными (для этого отлично помогает edit и на следующем проходе — squash).

Ещё одна фигура высшего пилотажа, полезная в случае, если надо несколько изменений в одном и том же файле разложить по разным коммитам — git add —patch . Она бывает полезна и сама по себе, но в сочетании с директивой edit она позволит вам разделить один коммит на несколько, причём сделать это на уровне отдельных строк, чего не позволяет, если я не ошибаюсь, ни один GUI-клиент и ни одна IDE.

Убедившись ещё раз, что всё в порядке, вы наконец можете со спокойной душой сделать то, с чего начался этот туториал: git push —force . Ой, то есть, разумеется, —force-with-lease !

Поначалу вы, скорее всего, будете тратить на этот процесс (включая первоначальный rebase на master) час, а то и два, если фича реально развесистая. Но даже это намного лучше, чем ждать два дня, когда ревьювер заставит себя наконец взяться за ваш реквест, и ещё пару дней, пока он сквозь него продерётся. В будущем же вы, скорее всего, будете укладываться в 30-40 минут. Особенно помогают в этом продукты линейки IntelliJ со встроенным инструментом разрешения конфликтов.

Последнее, от чего хочется предостеречь, — не переписывайте историю ветки в процессе код-ревью. Помните, что добросовестный ревьюер возможно клонирует ваш код к себе локально, чтобы иметь возможность смотреть на него через IDE и запускать тесты.

Спасибо за внимание всем, кто дочитал до конца! Надеюсь, что статья будет полезна не только вам, но и коллегам, которым ваш код попадает на ревью. Если у вас есть клёвые хаки для git — делитесь ими в комментариях!

Что делает команда git abuse

Управляйте проектами и согласовывайте цели всех команд для достижения результатов

Управление ИТ-услугами

Помогите своим командам разработчиков и ИТ-специалистов, а также бизнес-командам предоставлять услуги высокого качества на высокой скорости

Agile и DevOps

Создайте организацию по agile-разработке программного обеспечения, являющуюся передовой во всех аспектах, будь то исследование, поставка или эксплуатация

ПО РАЗМЕРУ КОМАНДЫ

ПО ПРОФИЛЮ КОМАНДЫ

Разработка программного обеспечения

По отрасли

Новости

Atlassian Together

Возможно, вам будет полезно

Надежность и безопасность Atlassian
Разбор примеров клиентов

Обучение

Документация на продукт

Ресурсы для разработчиков

Поддержка

Программа миграции Atlassian

Сервисы корпоративного уровня

Покупка и лицензирование

Интегрируйте

Блог о работе и жизни

Поддержка продуктов версии Server заканчивается 15 февраля 2024 г.

Поскольку прекращение поддержки наших продуктов версии Server не за горами, создайте выгодный план миграции в облако с помощью программы Atlassian Migration Program.

Оценить мои варианты

Новости

Atlassian Team ’23

Команды

git add

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

Учебные руководства по теме

git branch

Эта команда выступает универсальным инструментом администрирования веток. С ее помощью можно создавать изолированные среды разработки в одном репозитории.

Учебные руководства по теме

Git checkout

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

Учебные руководства по теме

Git clean

Удаляет неотслеживаемые файлы из рабочего каталога. Это логический аналог команды git reset, которая (обычно) работает только с отслеживаемыми файлами.

Учебные руководства по теме

git clone

Создает копию существующего репозитория Git. Клонирование — самый распространенный способ, с помощью которого разработчики могут получить рабочую копию центрального репозитория.

Учебные руководства по теме

Git commit

Получает проиндексированный снимок состояния и выполняет его коммит в историю проекта. Эта команда в сочетании с командой git add определяет классический рабочий процесс для всех пользователей Git.

Учебные руководства по теме

git commit —amend

Команда git commit с флагом —amend позволяет внести изменения в последний коммит. Она может оказаться полезной, если вы забыли проиндексировать файл или не указали важную информацию в комментарии к коммиту.

Учебные руководства по теме

git config

Удобный способ для настройки параметров конфигурации в инсталляции Git. Обычно эту команду используют сразу после установки Git на новую машину разработчика.

Учебные руководства по теме

git fetch

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

Учебные руководства по теме

git init

Инициализирует новый репозиторий Git. Если вы хотите использовать в проекте контроль версий, эту команду следует изучить раньше остальных.

Учебные руководства по теме

git log

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

Учебные руководства по теме

Git merge

Эффективный способ интеграции изменений из разошедшихся веток. После разветвления истории проекта командой git branch можно использовать команду git merge, чтобы объединить отдельные ветки.

Учебные руководства по теме

git pull

Команда git pull — это автоматизированная версия команды git fetch. Она загружает ветку из удаленного репозитория и сразу же объединяет ее с текущей веткой. Эта команда представляет собой git-эквивалент команды svn update.

Учебные руководства по теме

git push

Команда git push противоположна команде извлечения (с некоторыми оговорками). С ее помощью можно перенести локальную ветку в другой репозиторий и без труда опубликовать поступивший код. Эта команда похожа на svn commit с тем исключением, что она отправляет не один набор изменений, а серию коммитов.

Учебные руководства по теме

git rebase

С помощью команды перебазирования можно переместить ветки и избежать ненужных коммитов слияния. Полученную линейную историю зачастую намного легче понять и изучить.

Учебные руководства по теме

git rebase -i

С помощью флага -i можно запустить перебазирование в интерактивном режиме. При этом сохраняются все преимущества обычного перебазирования и появляется возможность добавлять, редактировать или удалять коммиты по ходу операции.

Учебные руководства по теме

git reflog

Git отслеживает изменения в конце веток с помощью механизма журналов ссылок (reflog). Он позволяет вернуться к наборам изменений, даже если на них не ссылается никакая ветка или тег.

Учебные руководства по теме

git remote

Удобный инструмент для администрирования удаленных подключений. С его помощью вместо полного URL-адреса в командах fetch, pull и push можно использовать более удобное сокращение.

Учебные руководства по теме

git reset

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

Учебные руководства по теме

git revert

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

Учебные руководства по теме

git status

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

Учебные руководства по теме

Терминология

Ветка

Ветка представляет собой независимое направление разработки. Ветки выступают в качестве абстрактного представления процессов редактирования, индексирования и выполнения коммитов, которые описаны в первом модуле «Основы Git» этой серии статей. Ветки можно рассматривать как способ запросить новый рабочий каталог, раздел проиндексированных файлов или историю проекта. Новые коммиты записываются в историю текущей ветки, что приводит к образованию форка в истории проекта.

Учебные руководства по теме

Централизованный рабочий процесс

Если ваши разработчики уже знакомы с Subversion, централизованный рабочий процесс позволит оценить преимущества Git без необходимости адаптировать команду к принципиально новому процессу. Кроме того, с его помощью можно удобно перейти к рабочим процессам, более ориентированным на Git.

Учебные руководства по теме

Рабочий процесс с функциональными ветками

Рабочий процесс с функциональными ветками развивает принципы централизованного рабочего процесса, поскольку в его рамках разработчики размещают новые функции в отдельных ветках. С таким подходом можно обсуждать изменения при помощи запросов pull, прежде чем они попадут в официальный проект.

Учебные руководства по теме

Форки

Чтобы не использовать один репозиторий на сервере в качестве «центральной» базы кода, можно воспользоваться ответвлениями (форками), чтобы у каждого разработчика был репозиторий на сервере. Таким образом, у каждого автора будет не один, а два репозитория Git: один закрытый локальный и один открытый на сервере.

Учебные руководства по теме

Рабочий процесс Gitflow Workflow

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

Учебные руководства по теме

HEAD

Указатель на текущий снимок в Git. По сути дела, команда git checkout просто обновляет указатель HEAD, чтобы он ссылался на указанную ветку или коммит. Когда HEAD указывает на ветку, Git молчит, но при попытке переключиться на коммит система переходит в состояние detached HEAD (открепленный указатель HEAD).

Учебные руководства по теме

Хук

Скрипт, который автоматически запускается каждый раз, когда в репозитории Git происходит определенное событие. С помощью хуков можно настраивать внутреннее поведение Git и запускать настраиваемые действия в ключевые моменты жизненного цикла разработки.

Учебные руководства по теме

Главная

Ветка разработки по умолчанию. При каждом создании репозитория Git создается ветка main; она же становится активной веткой.

Учебные руководства по теме

Пул-реквест

Запросы pull облегчают совместную работу разработчиков в Bitbucket. Они обеспечивают удобный веб-интерфейс для обсуждения предлагаемых изменений до их включения в официальный проект.

Учебные руководства по теме

Репозиторий

Набор коммитов, а также ветки и теги для идентификации коммитов.

Учебные руководства по теме

Тег

Ссылка, которую обычно используют, чтобы отметить конкретную точку в последовательности коммитов. В отличие от указателя HEAD, тег не обновляется по команде git commit.

Учебные руководства по теме

Контроль версий

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

Учебные руководства по теме

Рабочий каталог

Каталог, содержащий файлы, над которыми вы работаете. В нем обычно находится содержимое ветки коммита, на который указывает HEAD, и все локальные изменения, которые были совершены, но еще не подтверждены с помощью коммита.

A3.3 Приложение C: Команды Git — Основные команды

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

git add

Команда git add добавляет содержимое рабочего каталога в индекс (staging area) для последующего коммита. По умолчанию git commit использует лишь этот индекс, так что вы можете использовать git add для сборки слепка вашего следующего коммита.

Это одна из ключевых команд Git, мы упоминали о ней десятки раз на страницах книги. Ниже перечислены наиболее интересные варианты использования этой команды.

Знакомство с этой командой происходит в разделе Отслеживание новых файлов главы 2.

О том как использовать git add для разрешения конфликтов слияния написано в разделе Основные конфликты слияния главы 3.

В разделе Интерактивное индексирование главы 7 показано как использовать git add для добавления в индекс лишь отдельных частей изменённого файла.

В разделе Деревья показано как эта команда работает на низком уровне, чтобы вы понимали, что происходит за кулисами.

git status

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

Мы познакомили вас с этой командой в разделе Определение состояния файлов главы 2, разобрали стандартный и упрощённый формат вывода. И хотя мы использовали git status повсеместно в этой книге, практически все варианты использования покрыты в указанной главе.

git diff

Команда git diff используется для вычисления разницы между любыми двумя Git деревьями. Это может быть разница между вашей рабочей копией и индексом (собственно git diff ), разница между индексом и последним коммитом ( git diff —staged ), или между любыми двумя коммитами ( git diff master branchB ).

Мы познакомили вас с основами этой команды в разделе Просмотр индексированных и неиндексированных изменений главы 2, где показали как посмотреть какие изменения уже добавлены в индекс, а какие — ещё нет.

О том как использовать эту команду для проверки на проблемы с пробелами с помощью аргумента —check можно почитать в разделе Правила создания коммитов главы 5.

Мы показали вам как эффективно сравнивать ветки используя синтаксис git diff A…​B в разделе Определение применяемых изменений главы 5.

В разделе Продвинутое слияние главы 7 показано использование опции -w для скрытия различий в пробельных символах, а также рассказано как сравнивать конфликтующие изменения с опциями —theirs , —ours и —base .

Использование этой команды с опцией —submodule для сравнения изменений в подмодулях показано в разделе Начало работы с подмодулями главы 7.

git difftool

Команда git difftool просто запускает внешнюю утилиту сравнения для показа различий в двух деревьях, на случай если вы хотите использовать что-либо отличное от встроенного просмотрщика git diff .

Мы лишь вкратце упомянули о ней в разделе Просмотр индексированных и неиндексированных изменений главы 2.

git commit

Команда git commit берёт все данные, добавленные в индекс с помощью git add , и сохраняет их слепок во внутренней базе данных, а затем сдвигает указатель текущей ветки на этот слепок.

Вы познакомились с основами модели коммитов в разделе Коммит изменений главы 2. Там же мы продемонстрировали использование опций -a для добавления всех изменений в индекс без использования git add , что может быть удобным в повседневном использовании, и -m для передачи сообщения коммита без запуска полноценного редактора.

В разделе Операции отмены главы 2 мы рассказали об опции —amend , используемой для изменения последнего совершённого коммита.

В разделе О ветвлении в двух словах главы 3 мы более подробно познакомились с тем, что делает команда git commit и почему она делает это именно так.

Мы показали вам как подписывать ваши коммиты, используя опцию -S в разделе Подпись коммитов главы 7.

И наконец мы заглянули внутрь команды git commit в разделе Объекты коммитов главы 10 и узнали что она делает за кулисами.

git reset

Команда git reset , как можно догадаться из названия, используется в основном для отмены изменений. Она изменяет указатель HEAD и, опционально, состояние индекса. Также эта команда может изменить файлы в рабочем каталоге при использовании параметра —hard , что может привести к потере наработок при неправильном использовании, так что убедитесь в серьёзности своих намерений прежде чем использовать его.

Мы рассказали об основах использования git reset в разделе Отмена индексации файла главы 2, где эта команда использовалась для удаления файла из индекса, добавленного туда с помощью git add .

В разделе Раскрытие тайн reset, полностью посвящённой этой команде, мы разобрались в деталях её использования.

Мы использовали git reset —hard чтобы отменить слияние в разделе Прерывание слияния главы 7, там же было продемонстрировано использование команды git merge —abort для этих целей, которая работает как обёртка над git reset .

git rm

Команда git rm используется в Git для удаления файлов из индекса и рабочей копии. Она похожа на git add с тем лишь исключением, что она удаляет, а не добавляет файлы для следующего коммита.

Мы немного разобрались с этой командой в разделе Удаление файлов главы 2, показали как удалять файлы из рабочего каталога и индекса и только из индекса, используя флаг —cached .

Ещё один вариант использования git rm приведён в разделе Удаление объектов главы 10, где мы вкратце объяснили как использовать опцию —ignore-unmatch при выполнении git filter-branch , которая подавляет ошибки удаления несуществующих файлов. Это может быть полезно для автоматически выполняемых скриптов.

git mv

Команда git mv — это всего лишь удобный способ переместить файл, а затем выполнить git add для нового файла и git rm для старого.

Мы лишь вкратце упомянули эту команду в разделе Перемещение файлов главы 2.

git clean

Команда git clean используется для удаления мусора из рабочего каталога. Это могут быть результаты сборки проекта или файлы конфликтов слияний.

Мы рассмотрели множество опций и сценариев использования этой команды в разделе Очистка рабочего каталога главы 7.

Шпаргалка по Git

просмотр в указанном файле построчно: кто и когда последний менял каждую строчку кода (короткий формат даты):

git blame index.html --date short 

показать хэлп указанной команды, в данном случае config:

git help config 

показать логи:

git log 

показать статус:

git status 

показать изи текущим состоянием:

git diff HEAD~5 

показать изменения между коммитами от sha1 до sha2:

git diff sha1..sha2 

показать изменения между коммитами на master и на ветке bird:

git diff master bird 

отменяет изменения в указанном файле (восстаналивает файл из индекса):

git check­out -- cats.html 

При этом команда git check­out cats.html работает так: если есть ветка с именем cats.html, то произойдет переключение на эту ветку. Для того, чтобы этого не произошло можно сделать git checkout — cats.html, тогда гит будет точно знать, что нужно восстановить файл, а не переключиться на ветку. Кроме того файл можно восстанавливать не только с текущего индекса, а, например, так:

git checkout master~2 cats.html 

тогда cats.html будет взят из версии мастера на 2 коммита раньше.

Работа с коммитами:

git add . 

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

git commit --amend -m "Comment" 

удаляет последний коммит, а изменения остаются незакоммиченные:

git reset --soft HEAD^ 

удаляет последний коммит и все изменения в нем:

git reset --hard HEAD^ 

аналогично: удаляет два последних коммита и все изменения:

git reset --hard HEAD^^ 

удаляет два последние 5 коммитов и все изменения:

git reset --hard HEAD~5 

-u пишется в первый раз, чтобы потом запомнить позицию и можно было писать просто git push:

git push -u origin master 

Работа с удаленным сервером и удаленными ветками:

создание нового удаленого сервера с именем origin:

git remote add origin http://github.com/blabla.git 

просмотр списка удаленных серверов:

git remote -v 

удалить удаленный сервер (масло масляное? \^_\^):

git remote rm origin 

показать информацию об удаленном сервере:

git remote show origin 

удаляет локальные ветки, которых больше нет на удаленном сервере:

git remote prune origin 

показывает список всех удаленных веток:

git branch -r 

удаляет удаленную ветку name_branch:

git push origin :name_branch 

Теги:

добавляет новый тег с именем v0.0.3:

git tag -a v0.0.3 -m "version 0.0.3" 

пушит новый тег:

git push --tags 

Конфигурация и логирование:

раскрашивает логи =):

git config --global color.ui true 

выводит логи в сокращенно одну строчку:

git config --pretty=oneline 

вывод логов в указанном формате, где:
%ad — author date
%an — author name
%h — SHA hash
%s — subject
%d — ref names

git log --pretty=format:"%h %ad- %s [%an]" 

вывод логов с выводом измененных строчек:

git log --oneline -p 

вывод логов с выводом статистики изменений:

git log --oneline --stat 

вывод логов в виде графического дерева коммитов:

git log --oneline --graph 

вывод всех логов до указанной даты:

git log --until=1.minute.ago 

вывод логов начиная с указанной даты:

git log --since-1.day.ago 

вывод логов во временном промежутке:

git log --since=2012.01.01 --until=2013.12.31 

гит перестает следить за указанным файлом и удаляет его из гита, но не локально:

git rm --cached development.log 

посмотреть список конфигураций:

git config --list 

использовать emacs в качестве интерактивных команд:

git config --global core.editor emacs 

использовать opendiff для мержа конфликтов (работает только в OS X)

git config --global merge.tool opendiff 

Алиасы:

задание алиаса для лог формата:

git config --global alias.mylog 

«log —pretty=format:’%h %s [%an]’ —graph» создание сокращения, отныне git st аналогичен команде git status:

git config --global alias.st status 

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *