Почему неустановленные изменения все еще присутствуют после проверки другой ветви?
Я наблюдаю что-то, что не согласуется с тем, что я знаю о 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 и поэтому будет существовать в любой ветви, которую вы извлекаете.