Опция --amend
, похоже, изменяет существующий коммит. Это не так.
Я думаю, что лучшей иллюстрацией здесь является отрисовка (часть) графика фиксации .Помните, что в Git каждый коммит имеет уникальный хэш-идентификатор - большую уродливую строку букв и цифр.Каждый коммит имеет свой отдельный идентификатор.Эти вещи слишком громоздки для регулярного использования людьми, поэтому мы склонны использовать имена , такие как имена ветвей, чтобы запомнить их:
...--F--G--H <-- myBranch
Когда вы делаете новый коммит, высделайте это сначала, выполнив git checkout
нужной ветви.Это добавляет специальное имя HEAD
к имени этой ветви, и извлекает конкретный коммит - в данном случае H
- на который указывает имя.
Затем вы вносите любые изменения, которыеwant (в вашем рабочем дереве), используйте git add
(чтобы скопировать обновленные файлы обратно в область index / staging-) и запустите git commit
(без --amend
).На этом этапе Git:
- сохраняет файлы индекса / промежуточной области в качестве нового снимка для нового коммита;
- устанавливает для вас автора и коммиттера нового коммита, а также егоотметки даты и времени для «сейчас»;
- записывает ваше сообщение в журнал для новой фиксации, а
- записывает необработанный идентификатор хэша из текущий коммит (для которого мы используем букву
H
) в новый коммит в качестве его родителя.
Так что теперь у нас есть:
...--F--G--H <-- myBranch (HEAD)
\
I
гдеI
это новый коммит.Последний шаг - это сложная часть: ваш Git теперь записывает новый хэш-идентификатор нового коммита (который был просто создан путем создания коммита - мы называем его I
здесь, но опять же это какой-то большой уродливый хэш-идентификатор) в имя myBranch
, так как это то, к которому прикреплено специальное имя HEAD
:
...--F--G--H
\
I <-- myBranch (HEAD)
Если вы теперь git push
, то это к другому Git, который вы называете origin
Ваш Git помнит, что его Git myBranch
указывает на коммит I
:
...--F--G--H
\
I <-- myBranch (HEAD), origin/myBranch
Но теперь вы решаете, что что-то не так с коммитом I
.Таким образом, вы вносите некоторые изменения в файлы и git add
их, и запускаете git commit --amend
. Это не меняет коммит I
. Вместо этого он создает еще один новый коммит - назовем его J
, но на этот раз вместо установки родительского элемента J
в I
, Git устанавливаетРодитель J
снова H
.Затем он записывает фактический хэш-идентификатор J
, что бы это ни было, в myBranch
:
J <-- myBranch (HEAD)
/
...--F--G--H
\
I <-- origin/myBranch
Это то, что находится в вашем хранилище.Другой репозиторий, в origin
, имеет имя myBranch
, указывающее на коммит I
- тот, который вы дали ему ранее.
Теперь вы должны исправить представление другого репозитория Git о том, где его myBranch
должен указать.Вы должны передать ему J
коммит, а затем сказать ему: забудьте коммит I
, просто сделайте свой myBranch
коммит имени J
. После того, как вы это сделаете, ваш репозиторий и их репозиторий больше не сможет найти коммит I
.Ваш Git будет иметь следующее:
J <-- myBranch (HEAD), origin/myBranch
/
...--F--G--H
\
I [abandoned]
Обратите внимание, что коммит I
еще не ушел .Он останется на некоторое время - по крайней мере, на 30 дней по умолчанию - на тот случай, если вы решите, что хотите вернуть его.Тем не менее, будет трудно найти .Я использовал I
для определения его действительного хеш-идентификатора.Но что является его фактическим хеш-идентификатором?Как вы будете догадываться, каким может быть его хеш-идентификатор?(Есть способ, но оставьте его для другого вопроса :-))
Как сказал Энди в своем ответе , вам нужно будет использовать git push -f
, чтобы заставить сервер забыть зафиксироватьI
при запоминании нового коммита замены J
.Это нормально, если каждый, кто может использовать имя сервера myBranch
, заранее соглашается с тем, что этими именами манипулируют таким образом.Если вы единственный, кто использует серверное хранилище, вы должны согласиться с самим собой, что это нормально.Если другие люди используют его, убедитесь, что они понимают, что вы делаете в первую очередь!