Без --graph
, git log --oneline
пропускает некоторую информацию.Пропущенная информация может * быть важной здесь.Это , вероятно, , но это может быть неактуально.Давайте предположим, что это уместно, и нарисуем его.
Давайте посмотрим на , что хранит Git (пока не слишком много заботясь о части how ).То, что Git хранит, в любом случае в первом приближении, это коммит .Каждый коммит содержит полный и полный снимок всех файлов , а также всех файлов, которые существовали в Git в index на момент создания вами коммита.Итак, ваш файл больших данных находится в коммите 83601d3
(data added!
).Это также в коммитах 2a85665
и 8005019
.Он также может быть в d750b6c
(здесь отмечен data file ignored (added to .gitignore)
), поскольку добавление name в .gitignore
не меняет отсутствие или присутствие файла в индексе. 1 Перечисление файла в .gitignore
в основном просто закрывает git status
, говоря, чтобы он не жаловался, если файл находится в рабочем дереве, но отсутствует в индексе.
Но сохраненный снимокне только вещь в коммите.Каждый коммит также сохраняет некоторые метаданные - некоторые данные о сохраненном снимке.Например, каждый сделанный вами коммит имеет ваше имя и адрес электронной почты.В нем есть ваше сообщение журнала - информация, которую вы сохранили в Git, о , почему вы сделали этот коммит, чтобы вы могли видеть, что вы думали в то время.У него есть отметка даты и времени.И, что особенно важно, он имеет хэш-идентификатор - например, 83601d3
(но с полной длиной в 40 символов) - его parent commit.
Git выглядиткоммиты по этим хэш-идентификаторам.По сути, идентификаторы являются реальными именами коммита.Каждый идентификатор уникален для этого конкретного коммита.Фактически, идентификатор формируется путем вычисления криптографического хэша над содержимым коммита - так что это означает, что parent ID дочернего коммита является важной частью личность ребенка.Помните, что в глубине вашей головы, пока мы берем момент, чтобы нарисовать эту цепочку коммитов:
993ebd6 last commit
↓
cd882ce blah blah blah
↓
... ...
↓
289a7dd blah blah blah
↓
d750b6c data file ignored (added to .gitignore)
↓
8005019 repo still includes data files
↓
2a85665 repo still includes data files
↓
83601d3 data added!
↓
89b7a4a initial commit
, встроенный в каждый коммит, другими словами, является своего рода стрелкой назад (или вниз вэто вертикальный рисунок).Добавление --graph
к git log
, с или без --oneline
, заставляет Git рисовать стрелки / линии одинакового типа (в основном используя вертикальную черту |
для соединения маркеров *
при каждом коммите, с указанием направления стрелкивместо того, чтобы рисовать).
Другая вещь, которую нужно понять, состоит в том, что, поскольку идентификатор хеша чрезвычайно чувствителен к каждому биту данных в коммите, если вы попытаетесь изменить коммит - например, удалив из него файл - вы получаете не измененный коммит, а скорее новый и другой коммит.Новый коммит вполне может быть лучше , но у него другой хэш-идентификатор.
Итак, давайте заменим плохой коммит 83601d3
новым, лучшим.Мы пока не знаем, каков его хэш-идентификатор, но мы все равно можем его нарисовать:
2a85665 repo still includes data files
↓
83601d3 data added! XXXXXXX improved: no extra data
↓ │
89b7a4a initial commit ←─────┘
Так что ... все в порядке, но теперь нам нужно также скопировать 2a85665
.В любом случае, мы бы сделали, потому что у него все еще есть большие файлы, поэтому мы должны сделать новый и улучшенный коммит, в котором их нет. родительский нового и улучшенного 2a85665
будет иметь новый хэш-идентификатор YYYYYYYY
.
Теперь нам также нужно скопировать 8005019
минус большие файлы.И затем, поскольку он получает новый хэш-идентификатор, мы определенно должны также скопировать d750b6c
, , даже если d750b6c
не имеет больших файлов .Мы должны сделать новую копию с новым идентификатором хеша в качестве родителя.
Имея копиюТо есть d750b6c
, мы должны скопировать его дочерний элемент, чтобы, опять же, заменить идентификатор родительского хэша, если ничего больше. Это пульсирует при каждом другом коммите, пока мы не достигнем 993ebd6
. Скопировав это, мы получили новую цепочку, заканчивающуюся тем, чем является этот новый хеш. Git заменил хеш-идентификатор 993ebd6
, хранящийся под именем master
(или любым другим именем ветви, которое вы используете), на хеш-идентификатор последнего замещающего коммита, по сути, «забыв» исходную цепочку коммитов.
Эта операция - внесение некоторых изменений в некоторые ранние коммиты, а затем их изменение будет распространяться по всей цепочке коммитов, копирование и замена каждого на новую и улучшенную версию - вот что git rebase
построен, чтобы делать. С git rebase -i
вы получаете возможность исправить более ранний коммит, а затем скопировать все последующие коммиты в новые и улучшенные версии. В результате получается новая цепочка коммитов, и всем, кто использовал старую цепочку - вам в вашем Git-репозитории, но также всем, у кого есть отдельный Git-репозиторий, например, тот, что в origin
- переключиться на новую цепь. Для вас это просто вопрос использования git push --force
для обновления вашего пульта на origin
.
1 Более подробную информацию об индексе, например, область размещения или иногда кэш , смотрите в других статьях, в которых описано, как Git создает новый коммит от того, что в индексе в то время. Вот как создаются снимки Git: вы копируете файлы в индекс, а затем запускаете git commit
. Шаг копирования в индекс - это то, что фактически сжимает и выполняет Git-файл, делая его готовым к быть подтвержденным. После этого Git продолжает извлекать файлы Git-ified из коммитов и копировать их в индекс, чтобы они были готовы перейти к next commit.
Наличие файла в индексе определяет, отслеживается ли файл . Вы можете использовать git rm --cached
, чтобы удалить файл из индекса, не удаляя его из рабочего дерева: теперь он не отслежен, т. Е. Отсутствует в индексе, и поэтому не будет в next commit, если вы не сделаете что-то вроде выбора существующего коммита с файлом, чтобы Git снова скопировал файл в индекс.