Насколько я понимаю, вы намерены сделать что-то вроде этого:
#!/bin/bash
FIRST_COMMIT_HASH_TODAY="$(git log --since="1 days ago" --pretty=format:%H | tail -n 1)"
git reset --soft ${FIRST_COMMIT_HASH_TODAY}^
git commit -m "Squashed changes for $(date +%F)"
Т.е..
- Перечислите хеши коммитов для всех коммитов, которые произошли в течение последнего дня, и извлеките первый из этих хэшей коммитов.
(подразумевается, что в текущей форме по крайней мере один коммит каждый день)
- Переместите указатель репо HEAD на фиксацию до $ FIRST_COMMIT_HASH_OF_THE_DAY , но оставьте рабочее дерево и индекс без изменений.
- Зафиксируйте раздавленные изменения.
A предостережение хотя ... Обратите внимание, что теперь вы фактически переписываете историю. Вы больше не можете просто сделать git pull
, чтобы
синхронизировать изменения, потому что, если клиентское репо все еще имеет исходную историю коммитов, в то время как сервер имеет переписанную историю,
вы получите что-то вроде:
Your branch and 'origin/master' have diverged,
and have 50 and 1 different commit(s) each, respectively.
Если вы хотите обработать всю историю, одним из подходов будет использование некоторого варианта git filter-branch . Ниже приведен один примерный подход, но у этого подхода есть много недостатков, поэтому вы можете его немного улучшить.
Слабые стороны / характеристики:
- Просто игнорирует часовые пояса из временных меток git raw. (странное поведение, если коммиты сделаны в разных часовых поясах)
- Идентифицирует последний коммит в ветви, которую вы хотите обработать, по хешу корневого дерева. (странное поведение, если несколько коммитов имеют одно и то же корневое дерево (например, возвратный коммит, возвращающий родительский коммит))
- Предполагает линейную ветвь истории. (странное поведение, если в ветке есть коммиты слияния)
- Специально не создает один коммит в день. Вместо этого для каждого коммита он проверяет, прошло ли как минимум 24 часа с момента предыдущего коммита. Если его нет, он просто пропускает этот коммит.
- Всегда сохраняет первый и последний коммит, независимо от того, близки ли они по времени к последующим / предыдущим коммитам.
- Работает на основе GIT_COMMITER_DATE, а не GIT_AUTHOR_DATE.
- Не очень хорошо протестирован. Поэтому обязательно сделайте резервную копию исходного репо, если вы собираетесь попробовать это запустить.
Пример команды:
LATEST_TREE=$(git rev-parse HEAD^{tree}) git filter-branch --commit-filter '
# $3 = parent commit hash (if commit has at least one parent)
if [ -z "$3" ]
then
# First commit. Keep it.
git commit-tree "$@"
elif [ "$1" == "$LATEST_TREE" ]
then
# Latest commit. Keep it.
git commit-tree "$@"
else
PREVIOUS_COMMIT_COMMITTER_DATE="$(git log -1 --date=raw --pretty=format:%cd $3)"
PREVIOUS_COMMIT_COMMITTER_DATE_NO_TIMEZONE="$(echo $PREVIOUS_COMMIT_COMMITTER_DATE | egrep -o "[0-9]{5,10}")"
GIT_COMMITTER_DATE_NO_TIMEZONE="$(echo $GIT_COMMITTER_DATE | egrep -o "[0-9]{5,10}")"
SECONDS_PER_DAY="86400"
if [ $(expr $GIT_COMMITTER_DATE_NO_TIMEZONE - $PREVIOUS_COMMIT_COMMITTER_DATE_NO_TIMEZONE) -gt $SECONDS_PER_DAY ]
then
# 24 hours elapsed since previous commit. Keep this commit.
git commit-tree "$@"
else
skip_commit "$@"
fi
fi' HEAD
Если у вас была команда для извлечения хэшей коммитов коммитов, которые вы хотите сохранить, возможно, вы могли бы получить хэш корневого дерева для всех этих коммитов и сохранить их в отдельном файле. Затем вы можете изменить условие коммит-фильтра, чтобы проверить, «присутствует ли текущий хеш корневого дерева в файле желаемых хешей корневого дерева?» вместо «прошло 24 часа с момента предыдущего коммита?». (Это усилило бы проблему «идентификации коммитов по хешу корневого дерева», о которой я упоминал выше, поскольку она будет применяться ко всем коммитам, а не только к последнему коммиту)