Как я могу переместить head обратно в предыдущее место? (отдельная голова) & отменить коммиты

Коммиты

Коммит в git репозитории хранит снимок всех файлов в репозитории. Почти как огромная копия, только эффективнее.

Git пытается быть лёгким и быстрым, так что он не просто слепо копирует весь проект каждый раз, а ужимает коммит в набор изменений или «дельту» между текущей версией и предыдущей. Это позволяет занимать меньше места.

Также Git хранит всю историю о том, когда какой коммит был сделан и кем

Это очень важно, можно посмотреть из-за кого упал прод и навалять ему. Файлы в репозитории могут находиться в 3 различных “областях”

Файлы в репозитории могут находиться в 3 различных “областях”.

  • HEAD
  • Индекс
  • Рабочий каталог

Наш проект сейчас пуст. Давайте создадим первый файл:

На данном этапе только область “Рабочий каталог” содержит данные.

Рабочий проект это ваша папка с файлами, в данном случае это . Две другие области сохраняют свое содержимое внутри каталога в понятном и удобном для git формате, но не понятном для человека. Рабочий Каталог распаковывает их в файлы, что упрощает для нас их редактирование.

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

Сделаем снимок текущего состояния проекта, то есть сделаем коммит. Для этого необходимо сначала добавить содержимое “Рабочего Каталога” в Индекс. Индекс — это черновик коммита. Только файлы из индекса попадают в коммит.

Без добавления файла в Индекс у нас не получится создать коммит, проверьте это сами:

Для добавления в Индекс используется следующая команда:

Когда у вас много файлов, вы можете добавить их все разом .

Теперь сделаем наш первый коммит, выполнив команду . Тем самым мы сохраним содержимое Индекса как неизменяемый снимок в области . Хорошей практикой считается коротко описать, что было изменено, для этого используется флаг :

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

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

Теперь мы хотим внести изменения в файл и закоммитить его. Мы пройдём через всё ту же процедуру; сначала мы отредактируем файл в нашем рабочем каталоге. Давайте называть эту версию файла v2 и обозначать красным цветом.

Теперь посмотрим, какие изменения произошли в git:

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

Еще раз проверяем статус репозитория:

Новый файл появился в списке не отслеживаемых, то есть в Рабочем Каталоге. Давайте добавим в отслеживание этот файл, а так же измененный ранее.

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

Я уже упоминал, что у коммитов есть родитель, который указывает на предыдущий коммит. Из таких цепочек складывается “ветка”. О ветках мы поговорим в следующей статье. Пока достаточно знать, что по умолчанию у нас уже есть ветка .

Для удобства восприятия визуализируем наши коммиты. Кружочки это коммиты, а стрелочки между ними указывают на родителей.

Прочие команды и необходимые возможности

Хэш — уникальная идентификация объектов

В git для идентификации любых объектов используется уникальный (то есть с
огромной вероятностью уникальный) хэш из 40 символов, который определяется
хэшируюшей функцией на основе содержимого объекта. Объекты — это все: коммиты,
файлы, тэги, деревья. Поскольку хэш уникален для содержимого, например, файла,
то и сравнивать такие файлы очень легко — достаточно просто сравнить две строки
в сорок символов.

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

Ищет разницу текущего состояния проекта и коммита за номером… сами видите,
каким:

То же самое, но оставляем только шесть первых символов. Git поймет, о каком
коммите идет речь, если не существует другого коммита с таким началом хэша:

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

Читает лог с коммита по коммит:

Разумеется, человеку пользоваться хэшами не так удобно, как машине, именно
поэтому были введены другие объекты — тэги.

git tag — тэги как способ пометить уникальный коммит

Тэг (tag) — это объект, связанный с коммитом; хранящий ссылку на сам коммит,
имя автора, собственное имя и некоторый комментарий. Кроме того, разработчик
может оставлять на таких тегах собственную цифровую подпись.

Кроме этого в git представленные так называемые «легковесные тэги» (lightweight
tags), состоящие только из имени и ссылки на коммит. Такие тэги, как правило,
используются для упрощения навигации по дереву истории; создать их очень легко.

Создаёт «легковесный» тэг, связанный с последним коммитом; если тэг уже есть,
то еще один создан не будет:

Помечает определенный коммит:

Удаляет тег:

Перечисляет тэги:

Создаёт тэг для последнего коммита, заменяет существующий, если таковой уже был:

После создания тэга его имя можно использовать вместо хэша в любых командах
вроде git diff, git log и так далее:

Обычные тэги имеет смысл использовать для приложения к коммиту какой-либо
информации, вроде номера версии и комментария к нему. Иными словами, если в
комментарии к коммиту пишешь «исправил такой-то баг», то в комментарии к тэгу по
имени «v1.0» будет что-то вроде «стабильная версия, готовая к использованию».

Создаёт обычный тэг для последнего коммита; будет вызван текстовый редактор для
составления комментария:

Создаёт обычный тэг, сразу указав в качестве аргумента комментарий:

Команды перечисления, удаления, перезаписи для обычных тэгов не отличаются от
команд для «легковесных» тэгов.

Относительная адресация

Вместо ревизий и тэгов в качестве имени коммита можно опираться на еще один
механизм — относительную адресацию. Например, можно обратиться прямо к предку
последнего коммита ветки master:

Если после «птички» поставить цифру, то можно адресоваться по нескольким предкам
коммитов слияния:

Ищет изменения по сравнению со вторым предком последнего коммита в master; HEAD
здесь — указатель на последний коммит активной ветки.

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

Что привнес «дедушка» нынешнего коммита:

То же самое:

Обозначения можно объединять, чтобы добраться до нужного коммита:

Файл .gitignore — объясняем git, какие файлы следует игнорировать

Иногда по директориям проекта встречаются файлы, которые не хочется постоянно
видеть в сводке git status. Например, вспомогательные файлы текстовых редакторов,
временные файлы и прочий мусор.

Заставить git status игнорировать определенные файлы можно, создав в корне или
глубже по дереву (если ограничения должны быть только в определенных директория)
файл .gitignore. В этих файлах можно описывать шаблоны игнорируемых файлов
определенного формата.

Пример содержимого такого файла:

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

Серверные команды репозитория

Команда создания вспомогательных файлов для dumb-сервера в $GIT_DIR/info и
$GIT_OBJECT_DIRECTORY/info каталогах, чтобы помочь клиентам узнать, какие ссылки
и пакеты есть на сервере:

Проверяет сколько объектов будет потеряно и объём освобождаемого места при
перепаковке репозитория:

Переупаковывает локальный репозиторий:

Как избежать такого в дальнейшем?

В GitHub и GitLab есть функциональность под названием «защищённые ветки» (protected branches). Отметьте , , или какие ещё ветки важны для вас как защищённые и система не даст вам выстрелить себе в ногу. Если force push всё же понадобится, то защиту всегда можно на время снять. См

документацию: https://help.github.com/articles/defining-the-mergeability-of-pull-requests/

Создайте алиасы для команд, которые должны делать , чтобы обезопасить себя от ошибок по неосторожности:

Прекратите уже экспериментировать прямо в основной ветке! Команда — ваш друг.

Pro Tip: У команды также ещё очень хорошо сочетаются друг с другом ключи и , особенно, если вы отвлеклись от проекта на месяцок-другой. Попробуйте, если, конечно, вам всё ещё мало приключений…

Подмодули

Клонирование репозитория с подмодулями

При клонировании репозитория вам необходимо инициализировать и обновить подмодули:

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

после обычного клонирования репозитория

Обновление подмодулей

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

Для получения состояния последнего коммита всех подмодулей необходимо выполнить
следующую команду:

или использовать аргументы по умолчанию команды git pull:

Эта команда просто обновляет локальную рабочую копию. При запуске команды git status
каталоги подмодулей будут показаны изменёнными. Чтобы обновить репозиторий необходимо
зафиксировать изменения:

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

Добавление подмодулей

В текущий проект можно включить другой репозиторий Git в качестве папки, отслеживаемый Git:

После этого необходимо добавить и зафиксировать новый файл .gitmodules. В нём описано
какие подмодули следует клонировать при запуске команды git submodule update

Обновления журнала

Если параметр конфигурации «core.logAllRefUpdates» имеет значение «истина» и ссылка находится под «refs / heads /», «refs / remotes /», «refs / notes /» или псевдореф, например HEAD или ORIG_HEAD; или существует файл «$ GIT_DIR / logs / <ref>», тогда добавит строку в файл журнала «$ GIT_DIR / logs / <ref>» (разыменование всех символических ссылок перед созданием имени журнала), описывающую изменение значения реф. Строки журнала имеют следующий формат:

oldsha1 SP newsha1 SP committer LF

Где oldsha1 — это 40-символьное шестнадцатеричное значение, ранее сохраненное в <ref>, «newsha1» — 40-символьное шестнадцатеричное значение <newvalue>, а «committer» — имя коммиттера, адрес электронной почты и дата в стандартном формате идентификатора коммиттера Git. ,

Опционально с -м:

oldsha1 SP newsha1 SP committer TAB message LF

Где все поля,как описано выше,и «сообщение»-это значение,передаваемое в опцию -m.

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

2012–2021 Скотт Чакон и другиеЛицензия MIT.https://git-scm.com/docs/git-update-ref

Отменить опубликованные коммиты с новыми коммитами

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

справочная страница фактически охватывает многое из этого в своем описании. Еще одна полезная ссылка — .

Если вы решите, что в конце концов не хотите возвращаться, вы можете отменить возврат (как описано здесь) или вернуться к предыдущему состоянию (см. Предыдущий раздел).

Вы также можете найти этот ответ полезным в этом случае: Как переместить HEAD обратно в предыдущее место ? (Отдельная голова) и отменить фиксацию

Подробнее о шаблонах игнорирования

Шаблон Примеры соответствия Пояснение*
**/logs logs/debug.log logs/monday/foo.bar build/logs/debug.log Добавьте в начало шаблона две звездочки, чтобы сопоставлять каталоги в любом месте репозитория.
**/logs/debug.log logs/debug.log build/logs/debug.log но не logs/build/debug.log Две звездочки можно также использовать для сопоставления файлов на основе их имени и имени родительского каталога.
*.log debug.log foo.log .log logs/debug.log Одна звездочка — это подстановочный знак, который может соответствовать как нескольким символам, так и ни одному.
*.log !important.log debug.log trace.log но не important.log logs/important.log Добавление восклицательного знака в начало шаблона отменяет действие шаблона. Если файл соответствует некоему шаблону, но при этом также соответствует отменяющему шаблону, указанному после, такой файл не будет игнорироваться.
.log !important/.log trace.* debug.log important/trace.log но не important/debug.log Шаблоны, указанные после отменяющего шаблона, снова будут помечать файлы как игнорируемые, даже если ранее игнорирование этих файлов было отменено.
/debug.log debug.log но не logs/debug.log Косая черта перед именем файла соответствует файлу в корневом каталоге репозитория.
debug.log debug.log logs/debug.log По умолчанию шаблоны соответствуют файлам, находящимся в любом каталоге
debug?.log debug0.log debugg.log но не debug10.log Знак вопроса соответствует строго одному символу.
debug.log debug0.log debug1.log но не debug10.log Квадратные скобки можно также использовать для указания соответствия одному символу из заданного диапазона.
debug.log debug0.log debug1.log но не debug2.log debug01.log Квадратные скобки соответствуют одному символу из указанного набора.
debug.log debug2.log но не debug0.log debug1.log debug01.log Восклицательный знак можно использовать для указания соответствия любому символу, кроме символов из указанного набора.
debug.log debuga.log debugb.log но не debug1.log Диапазоны могут быть цифровыми или буквенными.
logs logs logs/debug.log logs/latest/foo.bar build/logs build/logs/debug.log Без косой черты в конце этот шаблон будет соответствовать и файлам, и содержимому каталогов с таким именем. В примере соответствия слева игнорируются и каталоги, и файлы с именем logs
logs/ logs/debug.log logs/latest/foo.bar build/logs/foo.bar build/logs/latest/debug.log Косая черта в конце шаблона означает каталог. Все содержимое любого каталога репозитория, соответствующего этому имени (включая все его файлы и подкаталоги), будет игнорироваться
logs/ !logs/important.log logs/debug.log logs/important.log Минуточку! Разве файл logs/important.log из примера слева не должен быть исключен нз списка игнорируемых? Нет! Из-за странностей Git, связанных с производительностью, вы не можете отменить игнорирование файла, которое задано шаблоном соответствия каталогу
logs/**/debug.log logs/debug.log logs/monday/debug.log logs/monday/pm/debug.log Две звездочки соответствуют множеству каталогов или ни одному.
logs/*day/debug.log logs/monday/debug.log logs/tuesday/debug.log but not logs/latest/debug.log Подстановочные символы можно использовать и в именах каталогов.
logs/debug.log logs/debug.log но не debug.log build/logs/debug.log Шаблоны, указывающие на файл в определенном каталоге, задаются относительно корневого каталога репозитория. (При желании можно добавить в начало косую черту, но она ни на что особо не повлияет.)

Изменение самого последнего коммита

Команда git commit –amend позволяет вам изменить самое последнее сообщение о коммите.

Не изменять коммит

Чтобы изменить сообщение самого последнего коммита, который не был передан в удаленный репозиторий, передайте его снова, используя флаг –amend.

  1. Перейдите в каталог хранилища в вашем терминале.
  2. Выполните следующую команду, чтобы поправить (изменить) сообщение о последнем коммите:
    git commit --amend -m "New commit message."

    Команда выполняет перезапись самого последнего коммита новым.

    Опция -m позволяет записать новое сообщение в командной строке без открытия редактора сессии.

Перед изменением сообщения о коммите вы также можете добавить другие ранее забытые изменения:

git add .git commit --amend -m "New commit message."

Измененный коммит

Измененный коммит – это новый объект с другим SHA-1. Предыдущий коммит больше не будет существовать в текущей ветке.

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

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

  1. Перейдите в хранилище.
  2. Исправьте сообщение о последнем введенном коммите:
    git commit --amend -m "New commit message."
  3. Принудительно нажмите, чтобы обновить историю удаленного хранилища:
    git push --force branch-name

Сложный вариант: починить за кем-то

Иногда бывает, что сделали либо не вы, либо кто-то принял пачку Pull Request’ов в то время, пока вы веселились со своими экспериментами.

Тяжесть ситуации в том, что вы не можете просто сделать , поскольку у вас локально нет коммитов, которые нужно восстановить (и у вас не получиться скачать их с помощью ).

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

Здесь нам поможет тот факт, что GitHub не удаляет коммиты, которые больше не принадлежат ни к какой ветке. Но, что усложняет задачу, не даёт их и стянуть с командной строки.

Если force-пуш сделали вы, то просто возьмите хэш коммита, который был в ветке до вас (как и в прошлом пункте). Если не вы, то можно зайти в ленту событий GitHub’а (на главной странице, в случае, если вы подписаны на репозиторий) и посмотреть, кто последний коммитил в эту ветку:

Теперь через консоль можно получить недостающие коммиты:

$ git fetch
From github.com:org/repo
 *       master-before-force-push -> origin/master-before-force-push

и теперь задача сводится к предыдущей:

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

Изменение самой последней фиксации

Команда позволяет вам изменить самое последнее сообщение фиксации.

Не нажата фиксация

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

  1. Перейдите в каталог репозитория в вашем терминале.

  2. Выполните следующую команду, чтобы исправить (изменить) сообщение последней фиксации:

    Что делает команда, так это перезапись самой последней фиксации новой.

    Параметр позволяет вам написать новое сообщение в командной строке, не открывая сеанс редактора.

Перед изменением сообщения о фиксации вы также можете добавить другие изменения, которые вы ранее забыли:

Нажатая фиксация

Исправленный (измененный) коммит — это новая сущность с другим SHA-1. Предыдущая фиксация больше не будет существовать в текущей ветке.

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

Если вы изменили сообщение последнего отправленного коммита, вам придется принудительно отправить его.

  1. Перейдите в репозиторий.

  2. Измените сообщение последней нажатой фиксации:

  3. Принудительно нажмите, чтобы обновить историю удаленного репозитория:

Временно переключитесь на другую фиксацию

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

Или, если вы хотите совершать коммиты, пока вы там, продолжайте и создайте новую ветку, пока вы в ней:

Чтобы вернуться туда, где вы были, просто проверьте ветку, в которой вы были снова. (Если вы внесли изменения, как всегда при переключении ветвей, вам придется иметь с ними дело соответствующим образом. Вы можете выполнить сброс, чтобы выбросить их; вы можете спрятать, оформить заказ, припрятать поп, чтобы взять их с собой; вы можете зафиксировать их в ветку там, если вы хотите ветку там.)

Rogue Coder?

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

Работаете с другими? Git сложен. Прочтите комментарии под этим ответом, прежде чем делать что-то необдуманное.

Возврат рабочей копии к самой последней фиксации

Чтобы вернуться к предыдущей фиксации, игнорируя любые изменения:

Где HEAD — последняя фиксация в вашей текущей ветке

Возврат рабочей копии к более ранней фиксации

Чтобы вернуться к фиксации, более ранней, чем самая последняя фиксация:

Кредиты идут на аналогичный вопрос о переполнении стека, Вернуться к фиксации с помощью хэша SHA в Git? .

Просмотр истории коммитов

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

Помимо автора и даты, у каждого комита есть идентификатор, который называется hash. Пример: 2934ee19f4d4ca37ff9bea9dc8208ef5362d789e. Необязательно использовать такую длинную запись, git поймет и по первым 5 символам, какой hash вам нужен.

Команда имеет очень большое количество опций для поиска коммитов по разным критериям.

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

Общее

Git — система контроля версий (файлов). Что-то вроде возможности сохраняться в компьютерных играх (в Git эквивалент игрового сохранения — коммит)

Важно: добавление файлов к «сохранению» двухступенчатое: сначала добавляем файл в индекс (), потом «сохраняем» ()

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

Отслеживаемые файлы могут быть в 3-х состояниях: неизменённые, изменённые, проиндексированные (готовые к коммиту).

Ключ к пониманию

Ключ к пониманию концепции git — знание о «трех деревьях»:

  • Рабочая директория — файловая система проекта (те файлы, с которыми вы работаете).
  • Индекс — список отслеживаемых git-ом файлов и директорий, промежуточное хранилище изменений (редактирование, удаление отслеживаемых файлов).
  • Директория — все данные контроля версий этого проекта (вся история разработки: коммиты, ветки, теги и пр.).

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

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

Простейший цикл работ

  • Редактирование, добавление, удаление файлов (собственно, работа).
  • Индексация/добавление файлов в индекс (указание для git какие изменения нужно будет закоммитить).
  • Коммит (фиксация изменений).
  • Возврат к шагу 1 или отход ко сну.

Указатели

  • — указатель на текущий коммит или на текущую ветку (то есть, в любом случае, на коммит). Указывает на родителя коммита, который будет создан следующим.
  • — указатель на коммит, с которого вы только что переместили (командой , например).
  • Ветка (, etc.) — указатель на коммит. При добавлении коммита, указатель ветки перемещается с родительского коммита на новый.
  • Теги — простые указатели на коммиты. Не перемещаются.

Перед началом работы нужно выполнить некоторые настройки:

Если вы в Windows:

Длинный вывод в консоли: Vim

Если нужно что-то написать, нажмите i — это переход в режим вставки текста. Если нужно сохранить изменения, перейдите в командный режим и наберите :w.

# Нажатия кнопок
ESC     — переход в командный режим
i       — переход в режим редактирования текста
ZQ (зажат Shift, поочередное нажатие) — выход без сохранения
ZZ (зажат Shift, поочередное нажатие) — сохранить и выйти
```bash
# Нажатия кнопок
ESC     — переход в командный режим
i       — переход в режим редактирования текста
ZQ (зажат Shift, поочередное нажатие) — выход без сохранения
ZZ (зажат Shift, поочередное нажатие) — сохранить и выйти

# Ввод в командном режиме
:q!             — выйти без сохранения
:wq             — сохранить файл и выйти
:w filename.txt — сохранить файл как filename.txt
Рейтинг
( Пока оценок нет )
Понравилась статья? Поделиться с друзьями:
Все про сервера
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: