'Git commit --amend` затрагивает больше файлов, чем необходимо?

Я часто испытываю следующее:

  1. Изменить файлы A, B и C.
  2. Зафиксируйте изменения с git commit,
  3. Постройте проект, чтобы сборка была актуальной.
  4. Внесите исправления / исправления только в файл A.
  5. Бежать git commit -a --amend (или же git commit --amend path/to/A)
  6. Перестройте проект постепенно.

Теперь, поскольку я изменил только файл A с момента последнего создания, я ожидаю, что будет восстановлен только файл A, но я всегда вижу, что все A, B и C (т.е. все файлы тронут весь коммит) перестраиваются.

Мне кажется, что git commit --amend Это touch вставлять / изменять последние измененные временные метки каждой из A, B и C, хотя я только добавляю модификацию A в коммит.

Это необходимо? Можно ли этого избежать, чтобы касаться только А и восстанавливать только А?

Если это имеет значение, мой проект находится на C++, а моя система сборки - cmake+ninja, но я думаю, что это во многом помимо того, что для систем сборки достаточно стандартно полагаться на последние измененные временные метки, чтобы определить, что нужно перестраивать.

2 ответа

Решение

git commit не касается файлов в вашем рабочем дереве. Неважно, используете ли вы --amend Вот.

git commit без -a также не использует файлы из вашего рабочего дерева, но git commit -a Git, по сути, работает git add -u во-первых, который будет читать некоторые файлы из рабочего дерева, чтобы скопировать их в индекс. Тогда, так или иначе - с или без -a - git commit строит новый коммит из того, что есть в индексе.

У нового коммита, когда-то сделанного, есть некоторый новый, уникальный, никогда не виданный ранее хэш-идентификатор. Если вы делаете нормальный git commit (без --amend), у вас есть несколько коммитов в вашем репозитории, каждый со своим уникальным хеш-идентификатором, причем последний такой коммит имеет некоторый хеш-идентификатор H:

... <-F <-G <-H   <-- your-branch (HEAD)

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

...--F--G--H--I   <-- your-branch (HEAD)

С --amend разница в том, что вместо нового коммита I указать на существующий коммит H, Git создает новый коммит с тем же родителем, что и H имеет, в этом случае G, Эффект в том, что H отталкивается в сторону:

          H
         /
...--F--G--I   <-- your-branch (HEAD)

Существующий коммит H не изменяется, но кажется исчезающим: его нельзя найти, начиная с I и работает в обратном направлении. Так git log скрывает это, и кажется, что прошло, как будто Git как-то изменился H, Git не имеет; H все еще не поврежден По умолчанию он также может быть восстановлен в течение как минимум 30 дней, так как хэш-идентификатор хранится в том, что Git называет reflogs. Но это выглядит ушел.

Если вы видите, что различные файлы перестраиваются, это не потому, что сам Git коснулся исходных файлов. Что-то еще, возможно, коснулось исходных файлов, или - мое предположение, но только предположение - ваша система сборки может пометить их как зависящие от конкретного хэша Git commit: I имеет другой хеш, чем H и артефакты сборки были следствием H не I, они сейчас устарели.

(Другие возможности включают Git-хуки, которые изменяют временные метки на файлах, конечно.)

Один из способов избежать этого (вручную) - выполнить все коммиты без внесения изменений и, когда вы закончите с изменениями, перебазировать интерактивно, раздавив коммиты (те, которые вы вносите сейчас)

Другие вопросы по тегам