Почему неустановленные изменения все еще присутствуют после проверки другой ветви?

Я наблюдаю что-то, что не согласуется с тем, что я знаю о git checkout команда. Хотя на ветке, кроме masterЯ делаю некоторые изменения в отслеживаемом файле; без постановки и фиксации этих изменений я запускаю

git checkout master

Git подчиняется, не отмахиваясь от века; но что еще более удивительно, все модификации, которые я сделал в этой ветке, все еще присутствуют! Вот пример, воспроизводящий ситуацию:

mkdir myrepo
cd myrepo
git init
touch README # create a new file
git add .
git commit -m "initial commit"
git checkout -b new-branch
echo "foo" >> README
git checkout master  

На этом этапе README файл в моем рабочем дереве содержит foo линия, хотя я и добавил ее в то время как на другой ветке (new-branch). я ожидал README быть пустым, как версия, записанная в кончике master, Почему foo линия еще там после проверки master?

2 ответа

Решение

На первый взгляд, ваш вопрос казался довольно неинтересным, но он заставил меня понять, что git checkout не такая простая операция, как кажется. Спасибо за вопрос :)

Насколько я понимаю, ваш вопрос таков: почему произошли незафиксированные изменения, т.е. foo линия, все еще присутствующая в рабочем дереве после проверки master? Если вы посмотрите вверх git-checkout На странице man вы найдете следующее описание:

git checkout <branch>

    To prepare for working on <branch>, switch to it by updating the
    index and the files in the working tree, and by pointing HEAD at
    the branch. Local modifications to the files in the working tree
    are kept, so that they can be committed to the <branch>.

Тем не менее, это описание, кажется, противоречит тому, что происходит в вашем примере. Вы не первый, кого это смущает; увидеть это обсуждение. В нем Хунио Хамано, сопровождающий Git, разъясняет, что git checkout <commit-ish> делает при наличии локальных модификаций:

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


Изложение ответа Хунио Хамано

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

  • Cs обозначает исходный коммит, т. Е. Коммит, на который указывает HEAD перед операцией проверки,
  • Обозначает состояние области подготовки,
  • Ws обозначают состояние рабочего дерева,
  • Ct обозначает целевой коммит, т.е. коммит, который мы пытаемся проверить.

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

  • diff (Cs, Is) (который вы можете увидеть в выводе git diff --staged),
  • diff(Cs,Ws) (который вы можете увидеть в выводе git diff),

и проверяет, применяются ли эти изменения корректно к целевому коммиту, Ct. Если есть какой-либо конфликт, операция извлечения отменяется. Иначе, HEAD перемещается в Ct, и состояния промежуточной области (Is) и рабочего дерева (Ws) сохраняются.

Приложение к вашему примеру

До git checkout master

Сразу после линии

git commit -m "initial commit"

в вашем примере репо выглядит так:

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

"В течение" git checkout master

Тогда ты бежишь

git checkout master

Итак, при условии, что моя интерпретация ответа Джунио верна, что здесь происходит?

Потому что обе текущие ветви, new-branchи ветка, чтобы проверить, master, указать на тот же коммит A, и Cs и Ct (используя мою терминологию) соответствуют A, В этом случае, конечно, diff(Cs,Is) и diff(Cs,Ws) применяются к Ct; здесь нет конфликта

Поэтому операция проверки осуществляется:

  • HEAD сделано, чтобы указать на master,
  • состояние площадки хранения сохраняется,
  • состояние рабочего дерева сохраняется.

После git checkout master

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

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

Другие вопросы по тегам