Помимо существующих (правильных) ответов, стоит отметить, что при использовании git commit [flags] file1 file2 ... fileN
вы можете поставить флаги --only
или --include
:
--only
это значение по умолчанию, и это означает не обращая внимания на то, что я поставил до сих пор, просто сделайте коммит с добавлением этих файлов .
--include
означает к чемуЯ до сих пор готов, добавьте эти файлы тоже .
Это достаточно просто, но немного неправильно, потому что --only
должен принять после фиксации действие также.
Для правильного понимания необходимо знать, что такое индекс Git и как git commit
на самом деле фиксирует то, что в индексе , а не то, что вдерево работы.
То, как программисты Git предполагают, что вы используете Git
Индекс - довольно сложная вещь, но большинство сводится к следующему: Индекс содержит набор файлов, которые будут добавлены в ваш следующий коммит. То есть, если вы запустите git commit
прямо сейчас - безut перечисляя любые файлы - новый коммит будет снимком всех файлов, которые в данный момент находятся в индексе, сохраняя содержимое, которое сейчас находится в индексе .
Что означает , так это то, что сразу после:
$ git clone <some-url>
$ cd <repository>
$ git checkout <branch>
в вашем индексе все те же файлы, с тем же содержанием , чтовы видите в своем рабочем дереве.
Таким образом, каждый коммит представляет собой полный снимок всех файлов в этом коммите, замороженных навсегда, в специальной сжатой форме только для Git.Это означает, что вы всегда можете вернуть все эти файлы в их первоначальном виде, используя Git для извлечения и распаковки, и это то, что делает git checkout
: он находит последний коммит в ветви, иизвлекает и распаковывает файлы.(Это слишком упрощенно: git checkout
действительно довольно необычно. Но это самое основное, что он делает.)
Файлы полезной формы находятся в вашем рабочем дереве , где вы можете видетьих и работать над ними.Это хорошо, потому что преданные заморожены и доступны только для Git, что, очевидно, было бы проблемой.: -)
Но, чтобы сделать новый коммит, вместо повторного сжатия всех файлов рабочего дерева - что во многих случаях займет много времени - что делает Git сохранить (не замороженные, но все еще сжатые и только для Git) файлы в этой вещи, называемой, по-разному, index , область подготовки или кэш .Поэтому, если у вас есть README.txt
и main.py
в вашем рабочем дереве, они также есть - в форме только для Git - в вашем текущем коммите (где они заморожены) и в вашем индексе (где они оттаивают, но все еще только в Git).
Запуск git add README.txt
указывает Git перезаписать индексную копию с копией рабочего дерева: возьмите файл обычного формата и перезапустите- сжать его до формата Git-only, заменив README.txt
в индексе на значение из рабочего дерева.Он еще не заморожен - вы можете перезаписать его еще раз перед фиксацией - но он готов сейчас.
Запуск git commit
без указания каких-либо файлов, говорит Git: Упакуйте все, что есть в индексе прямо сейчас и сделайте новый коммит из этого. Это происходит очень быстро, поскольку файлы уже находятся в правильной форме: Git просто нужно заморозить их вновый коммит.(Конечно, пока вы не сделаете файлы в индексе отличными от файлов в текущем коммите, в этом нет никакого смысла.)
Обратите внимание, что после git commit
делает новый коммит из индекса, вы обычно возвращаетесь к нормальной ситуации, когда индекс и текущий коммит совпадают.Если вы git add
добавили все файлы, которые вы изменили, все три копии каждого файла - HEAD
, индекс и рабочее дерево - совпадают.
Представляем --only
и--include
Бег git commit
с некоторые перечисленные файлы немного отличаются, и именно здесь приходит --only
против --include
. Если вы используете --include
, Git по существу делает git add
для перечисленных файлов.Это просто сокращение для git add <those files> && git commit
, более или менее.
Но, если вы используете --only
- или не указываете, что означает --only
- то, что делает Git, этоуберите регулярный индекс с пути и вместо этого создайте новый временный индекс из того, что находится в замороженном коммите.Для этого нового временного индекса Git будет git add
каждый из перечисленных вами файлов.Затем Git сделает новый коммит из этого other index.Но теперь есть проблема, потому что Git теперь нужно вернуться к нормальному индексу, и вот здесь он становится немного хитрым.
Сделав new коммит из временного индекса, GitТеперь необходимо обновить индекс real таким же образом.По сути, после фиксации из временного индекса Git повторно добавляет тот же набор файлов, который вы перечислили, в индекс real , чтобы они снова соответствовали.
Давайте снова используем двухфайловый пример с README.txt
и main.py
.На этот раз давайте добавим номер версии после каждого файла.Он не является частью имени файла, он просто помогает нам запомнить:
HEAD index work-tree
------------- ------------- -------------
README.txt(1) README.txt(1) README.txt(1)
main.py(1) main.py(1) main.py(1)
Они начинаются со всех трех версий каждого файла, которые являются одинаковыми.(Обратите внимание, что вы не можете изменить копию HEAD
. Вы можете сделать только новый коммит, который затем становится копией HEAD
, потому чтоHEAD
называет новый коммит.)
Теперь вы редактируете оба файла в рабочем дереве:
HEAD index work-tree
------------- ------------- -------------
README.txt(1) README.txt(1) README.txt(2)
main.py(1) main.py(1) main.py(2)
Допустим, вы сейчас делаете git add main.py
, чтобы скопировать версию рабочего дерева.в индекс:
HEAD index work-tree
------------- ------------- -------------
README.txt(1) README.txt(1) README.txt(2)
main.py(1) main.py(2) main.py(2)
Если вы запустите простой git commit
прямо сейчас, новый HEAD
будет иметь старый README.txt
, потому что index имеет старый README.txt
.Но вместо этого давайте запустим git commit --only README.txt
.Это делает временный индекс, так что мы имеем:
HEAD temp-index work-tree
------------- ------------- -------------
README.txt(1) README.txt(2) README.txt(2)
main.py(1) main.py(1) main.py(2)
Далее, это делает новый коммит из временного индекса:
HEAD temp-index work-tree
------------- ------------- -------------
README.txt(2) README.txt(2) README.txt(2)
main.py(1) main.py(1) main.py(2)
Между тем, индекс real еще не изменился.Прокрутите немного вверх и посмотрите на это: какая версия main.py
есть в нем?Какая версия README.txt
есть в ней?
Если Git просто переключился обратно на реальный индекс сейчас, сохраняя только что сделанный вами коммит, это то, что вы бы получили:
HEAD ugly-index work-tree
------------- ------------- -------------
README.txt(2) README.txt(1) README.txt(2)
main.py(1) main.py(2) main.py(2)
То есть ваше дерево работ - это все последние файлы.Ваш коммит имеет обновленный README.txt
.Но это уродливое состояние означает, что следующий коммит будет использовать старая / неправильная версия из README.txt
!Вот почему Git теперь повторно добавляет README.txt
к реальному индексу, так что вы получите:
HEAD index work-tree
------------- ------------- -------------
README.txt(2) README.txt(2) README.txt(2)
main.py(1) main.py(2) main.py(2)
Теперь вы готовы сделать второй коммит с обновленным main.py
, если хотите.