'Git commit --amend` затрагивает больше файлов, чем необходимо?
Я часто испытываю следующее:
- Изменить файлы A, B и C.
- Зафиксируйте изменения с
git commit
, - Постройте проект, чтобы сборка была актуальной.
- Внесите исправления / исправления только в файл A.
- Бежать
git commit -a --amend
(или жеgit commit --amend path/to/A
) - Перестройте проект постепенно.
Теперь, поскольку я изменил только файл 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-хуки, которые изменяют временные метки на файлах, конечно.)
Один из способов избежать этого (вручную) - выполнить все коммиты без внесения изменений и, когда вы закончите с изменениями, перебазировать интерактивно, раздавив коммиты (те, которые вы вносите сейчас)