git commit --amend в отключенном состоянии HEAD

Я понимаю, что правильный способ внесения изменений в старый GIT commit - это использовать rebase --interactive, но для того, чтобы понять все понятия, я хотел бы понять, что происходит, когда я делаю

  • git checkout <commit>
  • изменить что-то в файле
  • добавить измененный файл в индекс
  • а затем git commit . --amend

Когда я это делаю, вместо того, чтобы исправлять фиксацию, он отделяет новый фиксатор от PARENT того же коммита.

Является ли это просто GIT способ сказать мне, что я не могу внести поправки в фиксацию, которая уже имеет детей?

Ответ 1

В Git, после создания фиксации, он устанавливается в виде камня; вы не можете его изменить. Все, что вы можете сделать, это создать новый коммит, который "похож" на него, путем внесения в него изменений, выбора вишни и т.д.

Я понимаю ваше замешательство: "изменить" - это немного неправильное название; он несколько вводит в заблуждение, поскольку он предлагает изменить что-то на месте. В Git исправление фиксации фактически состоит в создании совершенно новой фиксации, которая имеет тот же самый родитель (ы), что и исходная фиксация.

В качестве примера предположим, что после запуска git checkout B вы находитесь в следующей ситуации:

enter image description here

(Ваш HEAD отсоединен, но это не относится к точке.) Независимо от того, выполняете ли вы или сцениваете изменения, запуск git commit --amend приведет вас в эту ситуацию:

enter image description here

Commit D может быть очень, очень похож на B; в частности, он может иметь точно такой же патч, точно такое же сообщение фиксации, что и B и т.д. Однако отметки времени (фиксация, автор) обычно будут отличаться (если вы не можете изменить фиксация в течение секунды!), что означает, что SHA-1 D будет отличаться от SHA-1 B; и если два коммитов не имеют одного и того же SHA, они не являются одним и тем же фиксацией.

Когда мы говорим, что B является родительским фиксатором C, мы имеем в виду commit C ссылки commit B своим SHA. Однако commit C не знает ничего о SHA commit D, потому что commit D был создан после C. Следовательно, D не может быть C parent. Поэтому commit D отключается по касательной и не имеет потомков.


Если вы хотите приземлиться в следующем состоянии,

enter image description here

где B' даже немного отличается от B, вы должны использовать git rebase -i, а не git commit --amend.