Использование Git фразы поэтапные изменения или для внесения некоторых изменений может очень запутать.
Чтобы не запутаться, вот что вам нужно знать:
У Git есть вещь, которую Git вызывает по-разному: index , область подготовки или иногда - редко сейчас - кэш . Все эти три имени относятся к одной вещи. Здесь я просто назову его индексом.
Индекс изначально содержит копию 1 из каждого файла , который находится в коммитечто ты проверил. (Этот текущий коммит также называется HEAD
.) Эти файлы в формате Git-only. Вы не можете видеть эти файлы. (Это небольшое завышение - есть некоторые специальные трюки с Git, чтобы увидеть их, но обычно они невидимы.) Файлы, которые вы можете см. в вашем рабочем дереве , в котором хранятся обычные повседневные файлы.
Когда вы делаете следующий коммит, Git будет использовать файлыкоторые находятся в индексе в то время. То есть, когда вы запускаете git commit -m "some message"
(или после того, как git commit
без -m
получит от вас сообщение), Git затем упакует все файлы, которые находятся в индексе на тот момент и используйте их для создания нового коммита.
Следовательно, если вы изменили или заменили файл в своем рабочем дереве, вы должны сначала скопировать егообратно в индекс . В противном случае Git просто повторно использует исходный файл.
Когда вы запускаете git add <em>file</em>
, Git берет копию рабочего дерева, сжимает ее в специальный формат Git-only и прочее. сжатая копия в указатель. Теперь индексная копия больше не соответствует копии HEAD
, но совпадает с копией рабочего дерева.
Если вы измените копию рабочего дерева снова , теперь все три копии будутразные! В этот момент git status
сообщит вам, что у вас есть «изменения, подготовленные для фиксации», а также «изменения не подготовка для фиксации».
Вы можете изменить копию рабочего дерева на что угоднов любое время. Это не влияет на индексную копию.
Вы можете удалить копию рабочего дерева, не удаляя индексную копию, используя любой инструмент на вашем компьютере, который удаляет файл. Вы также можете удалить копию index , не удаляя копию рабочего дерева, используя git rm --cached
. И вы можете удалить обе копии, используя git rm
. Ничто из этого не влияет на любой существующий коммит - ни один существующий коммит не может быть когда-либо изменен! Но удаление копии индекса влияет на следующий коммит, потому что когда вы запускаете git commit
, Git упакует все файлы, которые есть в индексе в это время, поэтому, если файл пропал из индекса, оно не будет в следующем коммите.
Поскольку в индексе есть то, что будет в следующем коммите, это довольно хорошее описаниеindex: Индекс - это, в основном, все равно, что пойдет в вашем следующем коммите. Индекс действительно должен играть некоторые дополнительные роли, особенно во время слияний, но мы не будем их здесь рассматривать.
1 Технически, индекс фактически содержит ссылки на копии. Но эффект почти такой же, как если бы индекс содержал реальные копии, по крайней мере, до тех пор, пока вы не начнете погружаться в то, как манипулировать индексом напрямую, используя git update-index
.
Как "не вносить изменения"
Чтобы получить файл из текущего (HEAD
) коммита обратно в индекс в том виде, в котором он находится в текущем коммите , вы можете использовать git reset -- <em>file</em>
. --
здесь требуется только в том случае, если имя файла напоминает параметр git reset
или имя ветви. Например, если у вас есть файл с именем master
и именем ветви master
, git reset master
выглядит так, как будто вы хотите использовать имя ветви , поэтому вы должны написать git reset -- master
чтобы сказать git, что вы имеете в виду файл master
.
Итак:git reset -- <em>file</em>
копирует файл из фиксации HEAD
в индекс . Это верно, даже если вы удалили индексную копию: сброс просто вернет ее обратно. Также верно, если файл не в коммите HEAD
. Если вы добавили файл F
в индекс, а затем решили, что его в конце концов не должно быть в индексе, вы можете git reset -- F
и удалит его из индекса.
(Вы также можете git rm --cached F
, если хотите: это имеет тот же эффект на данный момент. Но если вы просто хотите, чтобы индексная копия соответствовала копии HEAD
, используйте git reset
, потому что это работает для обоих случаев: там является копией HEAD
, или ее нет. *
Как вы знаете, что ставится?
Опять же, вы не можете на самом деле см. копию файла в вашем индексе. Так как же узнать, соответствует ли он какой-то другой копии? Ответ: git status
говорит вам кратко и полезно.
Допустим, у вас есть три файла в вашем рабочем дереве с именами README.md
, main.py
иutil.py
. Первые два из этих файлов вышли из коммита HEAD
, и вы только что создали util.py
сейчас, так что это не в коммите HEAD
и не в индексе.
Команда git status
выполняет два сравнения:
Во-первых, она сравнивает каждый файл в HEAD
с каждым файломв указателе. Таким образом, это сравнивает HEAD:README.md
(копия HEAD) с :README.md
(индексная копия). 2 Затем сравнивается HEAD:main.py
с :main.py
.
Для каждого файла, который то же самое , git status
говорит ничего .
Для каждого файла, который отличается , git status
говорит, что есть внесенные изменения для коммита . Если файл полностью отсутствует в индексе, вы поставили удаление. Если файл в индексе совершенно новый, вы добавили новый файл.
Итак, если вы знаете, что было в коммите HEAD
, теперь вы знаете, какие файлы одинаковы вindex: что-нибудь git status
не упомянул .
Далее, сказав вам, что отличается или нет в HEAD
против индекса, git status
переходит кСравните каждый файл в индексе с каждым файлом в рабочем дереве. Итак, здесь он будет сравнивать :README.md
с README.md
, :main.py
с main.py
и обнаруживать, что есть util.py
, которого нет в индексе.
Для каждого файла, то же самое , git status
говорит ничего .
Для каждого файла, который отличается , git status
сообщает об изменениях не ступенчатодля фиксации. Это верно, потому что git commit
не будет использовать рабочее дерево, оно просто будет использовать индекс.
Для файла, подобного util.py
, это находится в рабочем дереве, но нет в индексе, git status
сообщает об этом как неотслеживаемый файл . Вот что такое неотслеживаемый файл: файл, который находится в рабочем дереве, но отсутствует в индексе.
Обратите внимание, что если вы удалите файл изИндекс, он мгновенно не отслеживается! Если вы git add
файл, чтобы он был в индексе, ну, теперь он отслеживается.
2 Этот забавный синтаксис HEAD:file
и :file
специфичен для Gitсам по себе, и работает только с некоторыми командами Git. Одним из них является git show
: вы на самом деле можете увидеть индексную копию README.md
, используя, например, git show :README.md
. Поскольку git show
является ориентированной на пользователя командой, вы можете сделать это с довольно хорошей безопасностью: git show HEAD:file
, git show :file
и git show <commit:>file
- все это довольно хорошие способы увидеть конкретную копию конкретного файла, который был превращен вего внутренняя форма Git, либо сохраненная в коммите, либо готовая к коммиту.
Вы также можете просмотреть имена всех индексных копий файлов, используя git ls-files
. В большом хранилище это печатает лот имен! Однако он не предназначен для обычного повседневного использования и не очень удобен для пользователя.
Commits read index;git checkout
пишет в него
Чтобы сделать новый коммит, вы просто копируете нужные файлы в индекс и запускаете git commit
. Индекс уже содержит всех файлов из текущего коммита, поэтому вам нужно только обновить любые файлы, которые вы хотите изменить, или добавить любые новые файлы, которые вы хотите, или удалить любыефайлы, которые вы хотите удалить. Затем вы git commit
и делаете новый коммит. Этот новый коммит теперь является коммитом HEAD
, а теперь коммитом HEAD
и индексом совпадают.
Если коммит HEAD
и индекс совпадают, и эти два соответствуют рабочему дереву, товсе "чисто", и вы можете легко переключиться на другой коммит, используя, например:
git checkout otherbranch
(или новую команду Git 2.23 git switch
, которая похожа на дружественный вариант git checkout <em>branch</em>
, который невсе другие инструменты Git объединены в одну команду - git checkout
может выполнять где-то от трех до семи различных заданий, в зависимости от того, как вы считаете).
Эта проверка, если она успешна, 3 должен:
- заполнить ваш индекс всеми файлами из кончика
otherbranch
(и удалить все ненужные); - заполнить ваше рабочее дерево всемифайлы из кончика
otherbranch
(и удалите все ненужные);и - сделать имя
HEAD
ссылкой на коммит-коммит otherbranch
.
Как только это будет сделано, ваш HEAD
коммит, индекс и рабочее дерево сновавсе совпадения.
3 Команда git checkout
может иногда успешно *, даже если индекс и рабочее дерево не являются "чистыми". Очистить - это плохо определенный термин, но чтобы узнать больше о том, когда git checkout
позволит вам переключать ветви при переносе изменений, см. Извлечение другой ветви, когда в текущей ветви есть незафиксированные изменения .
Заключение
Вы не можете видеть индексные копии файлов! То, что вы можете и должны сделать, это использовать git status
, который сравнивает файлы HEAD
с индексными копиями. В большом проекте с сотнями, тысячами или даже миллионами файлов Git ничего не скажет почти обо всех из них. Здесь будут упомянуты только те, которые отличаются . Это гораздо полезнее.
Всякий раз, когда ваши HEAD
, индекс и рабочее дерево все совпадают, git status
говорит ничего . Когда git status
видит некоторые вещи, которые не совпадают, он печатает имена файлов под изменениями, подготовленными для фиксации и / или под изменениями, не подготовленными для фиксации , в зависимости от того, является ли это HEAD
и индексные копии, которые не согласны, или индексные и рабочие копии дерева, которые не согласны, или и то и другое.
git add
копирует файлы в индекс. Если они уже были там, ну, теперь они перезаписаны копией из рабочего дерева. Если раньше их там не было, то теперь они есть.
git rm
удаляет файлы из индекса. Без --cached
он также удаляет те же файлы из рабочего дерева. С --cached
он оставляет копии рабочего дерева в одиночку - что хорошо для сейчас , но позже git checkout
может потребоваться удалить копии рабочего дерева!
Git будетВ общем, старайтесь изо всех сил не уничтожать файлы рабочего дерева с ценными данными. Что же "драгоценного", правда? Ну, если файл рабочего дерева util.py
был добавлен и зафиксирован и соответствует HEAD:util.py
и :util.py
, на данном этапе util.py
- это , а не драгоценен больше, потому что, если ты этого хочешь, он есть в коммите. Таким образом, вы можете git checkout
старый коммит, который не имеет util.py
, и Git будет чувствовать себя абсолютно безопасно, удалив util.py
из вашего рабочего дерева. Просто git checkout
последняя команда вернулась.
Некоторые команды Git, включая git reset --hard
, , будут уничтожать файлы рабочего дерева. Теория git reset --hard
заключается в том, что вы хотите сбросить как индекс , так и вашего рабочего дерева. Режим по умолчанию, git reset --mixed
, сбрасывает только индексные копии. 4 Именно поэтому git reset -- file
"распаковывает" файл - копирует HEAD:file
в :file
- но не касаетсякопия рабочего дерева file
.
4 В частности, git reset --soft
, git reset --mixed
и git reset --hard
позволяют вам делать каждый файл. Если вы хотите сделать только один файл, используя git reset -- file
, он всегда использует --mixed
. В других случаях вам нужно использовать один из множества альтернативных режимов git checkout
. Git 2.23 вводит новую команду git restore
, которая предназначена для того, чтобы сделать это менее запутанным. Время покажет, так ли это: git restore
технически все еще экспериментален.