Алексей Махоткин

домашняя страница

Git-checkout

git-checkout(1) Manual Page

NAME

git-checkout - Извлекает ветку или файлы в рабочей копии

Кратко

git checkout [-q] [-f] [-m] [<ветка>]
git checkout [-q] [-f] [-m] [--detach] [<коммит>]
git checkout [-q] [-f] [-m] [[-b|-B|--orphan] <новая-ветка>] [<начальная-точка>]
git checkout [-f|--ours|--theirs|-m|--conflict=<style>] [<а-ля-дерево>] [--] <пути>…
git checkout [-p|--patch] [<а-ля-дерево>] [--] [<пути>…]

Описание

Обновляет файлы в рабочем дереве, чтобы они совпадали с той версией, которая находится в индексе или в указанном дереве. Если пути не указаны, то git checkout также обновит HEAD так, чтобы указанная ветка стала текущей.

git checkout <branch>

Чтобы перейти к работе над <веткой>, эта команда переключается на нее, обновляя индекс, а также файлы в рабочей копии. HEAD переустанавливается так, чтобы указывать на ветку. Локальные исправления в файлах в рабочей копии сохраняются, чтобы их можно было закоммитить на <ветку>.

Если <ветка> не обнаружена, но существует следящая ветка с тем же названием, к которой привязан в точности один репозиторий (назовем его <ид-репы>), то команда эквивалентна следующей:

$ git checkout -b <ветка> --track <ид-репы>/<ветки>

Можно не указывать <ветку> — в этом случае команда превращается в “извлечь текущую ветку”: это пустая команда с побочным эффектом — она показывает информацию о слежении, если таковая есть для текущей ветки.

git checkout -b|-B <новая-ветка> [<начальная-точка>]

При указании ключа -b будет создана (в точности как при использовании команды git-branch(1)) и извлечена новая ветка. Можно использовать ключи --track и --no-track. Для удобства использование --track автоматически означает создание ветки — см. ниже описание ключа --track.

При указании ключа -B <новая-ветка> будет создана, если не существует. Если она существует, то будет пересоздана. Эта команда делает то же самое, что две команды:

$ git branch -f <branch> [<start point>]
$ git checkout <branch>

но за одну транзакцию. То есть, если “git checkout” выполнится с ошибкой, то и ветка не будет пересоздана.

git checkout --detach [<branch>]
git checkout <commit>

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

Ключ --detach приводит к такому же поведению при использовании <ветки> (без этого ключа при указании имени ветки команда извлечет ее, не создавая отвязанное состояние), или же текущего коммита, если <ветка> не указана.

git checkout [-p|--patch] [<а-ля-дерево>] [--] <спецификация-пути>…

При указании <спецификаций-путей> или ключа --patch, git checkout не переключает ветки, а обновляет указанные пути в рабочем дереве из индексного файла или из указанного <а-ля-дерева> (чаще всего это будет коммит). В этом случае ключи -b и --track не имеют с смысла и при их указании произойдет ошибка. Аргумент <а-ля-дерево> можно использовать для указания конкретного коммита, тэга или дерева, используемого для обновления указанных путей в индексе, с дальнейшим обновлением рабочего дерева.

Индекс может содержать неслитые записи из-за неудачного слияния. По умолчанию, если вы попытаетесь извлечь такую запись из индекса, то операция извлечения приведет к ошибке и ничего не будет извлечено. При использовании ключа -f неслитые изменения будут проигнорированы. Содержимое из той или иной стороны слияния можно извлечь из индекса с помощью ключей --ours и --theirs. С ключом -m изменения в рабочем дереве можно отбросить, чтобы пересоздать исходный результат конфликтного слияния.

Опции

-q
--quiet

Не выдавать сопроводительных сообщений.

-f
--force

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

При извлечении путей из индекса, не выдавать ошибку при столкновении с неслитыми файлами; вместо этого такие файлы будут проигнорированы.

--ours
--theirs

При извлечении неслитых путей из индекса, извлекать состояние №2 (наше) или №3 (‘их’).

-b <new_branch>

Создать новую ветку, которая называется <new_branch> и начать ее со <start_point>; подробности см. в git-branch(1).

-B <new_branch>

Создать новую ветку, которая называется <new_branch> и начать ее со <start_point>; если ветка с таким названием уже существует, то переставить ее на <start_point>. Эта команда аналогична команде “git branch” с ключом “f”; подробности см. в git-branch(1).

-t
--track

При создании новой ветки установить конфигурацию родительского репозитория “upstream”. См. описание “--track” в git-branch(1).

Если ключ -b не указан, то имя новой ветки будет взято из названия следящей ветки: префиксы “remotes/” и “refs/remotes/” отрезаются, а также отрезается все до следующего символа “/” (считается, что это идентификатор родительского репозитория). Таким образом, новая ветка будет называться “hack”, если ветка создается из веток “origin/hack”, “remotes/origin/hack” и “refs/remotes/origin/hack”. Если в указанном имени нет ни одного символа ”/”, то гадания останавливаются, и требуется явно указать имя с помощью ключа -b.

--no-track

Не устанавливать конфигурацию родительского репозитория “upstream”, даже если конфигурационная переменная branch.autosetupmerge установлена в true.

-l

Создает reflog новой ветки; подробности см. в git-branch(1).

--detach

Вместо извлечения ветки для работы над ней, извлечь указанный коммит для изучения и временных экспериментов. Это поведение по умолчанию для команды “git checkout <commit”>, если <commit> не является названием ветки. Подробности см. в главе “Отделенная HEAD”.

--orphan <new_branch>

Создать новую “висящую” ветку, которая называется <new_branch>, начав ее со <start_point>, и переключиться на нее. Первый коммит, сделанный на этой ветке, не будет иметь родительского коммита и станет корневым коммитом новой истории изменений, которая полностью отвязана от всех остальных веток и коммитов.

Индекс и рабочее дерево устанавливаются в такое состояние, как будто бы перед тем выполнили команду “git checkout <start_point>”. Это позволяет начать новую историю, которая запишет состояние файлов, аналогичное <start_point>, выполнив “git commit -a” для создания корневого коммита.

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

Если вы хотите начать отвязанную историю, которая совершенно отличается от <start_point>, то после создания “висящей” ветки вам нужно очистить индекс и рабочее дерево с помощью команды “git rm -rf .”, выполнив ее в верхнем каталоге рабочего дерева. После этого можно приготовить новые файлы чтобы добавить их в рабочее дерево, скопировав их из другого каталога, распаковав из архива и т. д.

-m
--merge

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

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

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

--conflict=<style>

То же самое, что и ключ --merge, но позволяет указать способ представления конфликтующих участков, переопределяя конфигурационную переменную merge.conflictstyle. Возможные значения аргумента — “merge” (по умолчанию) и “diff3” (помимо информации, показанной в стиле “merge”, также показывается оригинальное содержимое).

-p
--patch

Позволяет интерактивно выбрать определенные фрагменты различий между <а-ля-деревом> (или индексом, если таковое не указано), и рабочим деревом. Указанные фрагменты затем отменяются в рабочем дереве (а также в индексе, если указано <а-ля-дерево>).

Это означает, что можно использовать git checkout -p для выборочной отмены изменений в ващем рабочем дереве. См. “Интерактивный режим“ в git-add(1), где описано, как работает режим --patch.

<branch>

Ветка, которую нужно извлечь; если этот аргумент указывает на ветку (то есть если добавить к его имени “refs/heads/” — получится корректная ссылка), то извлекается эта ветка. В противном случае, если здесь указан определенный коммит, то HEAD переходит в “отделенное” состояние, и не указывает ни на одну ветку (см. ниже).

Специальный синтаксис ”@{-N}” означает “N-ная последняя извлеченная ветка” (а не отвязанное состояние). Также можно указать -, это синоним для ”@{-1}”.

Еще один специальный случай — “A…B” означает точку расхождения между ветками A и B, если она ровно одна. Можно не указывать либо одну, либо другую ветку, тогда по умолчанию используется значение HEAD.

<new_branch>

Название новой ветки.

<start_point>

Указывает коммит, от которого начинать новую ветку; подробности см. в git-branch(1). По умолчанию — HEAD.

<а-ля-дерево>

Дерево, которое нужно извлечь (если указаны пути). Если не указано, то используется индекс.

Отделенная HEAD

HEAD в норме указавает на ветку с именем (например, master). Каждая ветка, в свою очередь, указывает на конкретный коммит. Давайте взглянем на репозиторий с тремя коммитами, один из которых помечен, и извлеченной веткой master:

           HEAD (указывает на ветку 'master')
            |
            v
a---b---c  ветка 'master' (указывает на коммит 'c')
    ^
    |
  tag 'v2.0' (указывает на коммит 'b')

Когда в таком состоянии создается коммит, ветка обновляется и начинает указывать на этот новый коммит. А именно: git commit создает новый коммит d, чьим родительским коммитом является c, и обновляет ветку master, чтобы она указывала на коммит d. HEAD все еще указывает на ветку master и тем самым опосредованно — на коммит d:

$ edit; git add; git commit

               HEAD (указывает на ветку 'master')
                |
                v
a---b---c---d  ветка 'master' (указывает на коммит 'd')
    ^
    |
  tag 'v2.0' (указывает на коммит 'b')

Иногда полезно извлечь коммит, который находится не на вершине некоторой ветки, или даже создать новый коммит, который не принадлежит ни одной ветке. Давайте посмотрим, что произойдет, если извлечь коммит b (здесь показаны два способа такого извлечения):

$ git checkout v2.0  # or
$ git checkout master^^

   HEAD (указывает на коммит 'b')
    |
    v
a---b---c---d  ветка 'master' (указывает на коммит 'd')
    ^
    |
  tag 'v2.0' (указывает на коммит 'b')

Заметим, что при любом способе извлечения HEAD теперь указывает прямо на коммит b. Это называется “отделенная HEAD”. Это означает попросто, что HEAD указывает на конкретный коммит, а не на именованную ветку. Давайте посмотрим, что произойдет, если создать новый коммит:

$ edit; git add; git commit

     HEAD (указывает на коммит 'e')
      |
      v
      e
     /
a---b---c---d  branch 'master' (указывает на коммит 'd')
    ^
    |
  tag 'v2.0' (указывает на коммит 'b')

Теперь у нас есть коммит e, но на него указывает только HEAD. Мы, конечно же, можем добавить еще коммитов:

$ edit; git add; git commit

         HEAD (указывает на коммит 'f')
          |
          v
      e---f
     /
a---b---c---d  ветка 'master' (указывает на коммит 'd')
    ^
    |
  tag 'v2.0' (указывает на коммит 'b')

Вообще, мы можем выполнять любые обычные команды Git. Однако, посмотрим что получится, если извлечь master:

$ git checkout master

               HEAD (указывает на ветку 'master')
      e---f     |
     /          v
a---b---c---d  ветка 'master' (указывает на коммит 'd')
    ^
    |
  tag 'v2.0' (указывает на коммит 'b')

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

$ git checkout -b foo   <1>
$ git branch foo        <2>
$ git tag foo           <3>
  1. создает новую ветку foo, которая указывает на коммит f, а затем обновляет HEAD, чтобы указывать на ветку foo. Другими словами, после выполнения этой команды мы выйдем из состояния отделенного HEAD.

  2. аналогично, создает новую ветку foo, которая указывает на коммит f, но оставляет HEAD в отделенном состоянии.

  3. создает новую метку foo, которая указывает на коммит f, оставляя HEAD в отделенном состоянии.

Если мы ушли с коммита f, то сначала нам надо узнать его идентификатор (обычно с помощью команды git reflog). Затем мы можем создать ссылку на него. Например, чтобы увидеть два последних коммита, на которые указывал HEAD, можно использовать одну из нижеследующих команд:

$ git reflog -2 HEAD # или
$ git log -g -2 HEAD

Примеры

  1. Нижеследующая последовательность команд извлекает ветку master, откатывает Makefile на две ревизии назад, по ошибке удаляет hello.c, а затем восстанавливает этот файл из индекса.

    $ git checkout master             <1>
    $ git checkout master~2 Makefile  <2>
    $ rm -f hello.c
    $ git checkout hello.c            <3>
    1. переключить ветку

    2. извлечь файл из другого коммита

    3. восстановить hello.c из индекса

      Если вы хотите извлечь из индекса все файлы на языке C, можно сказать:

      $ git checkout -- '*.c'

      Заметьте, что *.c находится в кавычках. Файл hello.c также будет извлечен, хоть он больше и не находится в рабочем дереве, потому что указанная маска будет использована для поиска записей в индексе (а не в рабочем дереве).

      Если у вас есть ветка с неудачным названием hello.c (именно так!), то на этом шаге будет извлечена именно она, а не указанный файл. Чтобы все же извлечь файл, надо сказать:

      $ git checkout -- hello.c
  2. После работы над некорректной веткой переключиться обратно на нужную можно с помощью команды

    $ git checkout mytopic

    Однако, если “некорректная” ветка и нужная ветка “mytopic” отличаются в файлах, которые вы локально изменили, то извлечение приведет к следующей ошибке:

    $ git checkout mytopic
    error: You have local changes to 'frotz'; not switching branches.

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

    $ git checkout -m mytopic
    Auto-merging frotz

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

  3. Если при переключении веток с помощью ключа -m происходит конфликт, то вы увидите примерно такое сообщение:

    $ git checkout -m mytopic
    Auto-merging frotz
    ERROR: Merge conflict in frotz
    fatal: merge program failed

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

    $ edit frotz
    $ git add frotz

Git

Входит в пакет программ git(1).


Last updated 2014-08-31 21:06:18 CEST

Comments