Преамбула
Вы действительно должны рассмотреть свой рабочий процесс.Скорее всего, вы пытаетесь добиться странного рабочего процесса, скопированного с какой-то древней VCS.Git используется для отслеживания истории и позволяет вам переписать ее.Но вам нужно принять решение, какую историю вы хотите.Выполнение управления вариантами в отношении истории, вероятно, является плохой идеей.
500 commit - не большое значение для Git, ядро Linux получило около 63.000 (!) Коммитов только в 2018 году ;)
Решение
Тем не менее, вот хакерское доказательство концепции, которая отвечает вашим потребностям.Нет необходимости в выделенном репозитории, переписанная история просто хранится в какой-то отдельной ветке.Первый запуск создаст эту потерянную ветвь, последующие запуска обновят ее последними коммитами.Оба вызова выглядят одинаково:
$ path/to/crazy-rebase <rewritten-branch> <last-commit-to-transfer>
Например:
$ ./crazy-rebase cutoff master
Как это работает
Во время первого запуска сценарий создает потерянную ветвь (например, cutoff
) из данной ревизии (например, master
) без какой-либо предыдущей истории.Все дальнейшие запуски будут выбирать все коммиты (пока не присутствующие) в эту потерянную ветвь (используя ребаз).Необходимые коммиты выводятся из последнего успешного завершения (на самом деле это хранится в специальной ссылке CUTOFF_BASE
).
Script crazy-rebase
:
#!/usr/bin/env bash
CUTOFF="$1"
CURRENT="$2"
LAST_BASE="CUTOFF_BASE"
error() {
local errcode=$?
echo "ERR: $*" >&2
exit $errcode
}
log() {
echo "LOG: $*" >&2
}
ret() {
return "$1"
}
prepare() {
local cutoff="$1"
local current="$2"
local base_hash
git show-ref --quiet "$cutoff" &&
return 0
log "Preparing cut-off branch '$cutoff' ..." &&
base_hash="`git show -s --pretty=%H "$current"`" &&
git checkout --quiet --orphan="$cutoff" "$current" &&
git commit -m "Cutoff branch, based on '$base_hash'" &&
git checkout --quiet "$current" &&
git update-ref "$LAST_BASE" "$base_hash" &&
log "Cut off branch '$cutoff' created." &&
exit 0 ||
error "Failed to init cut-off branch '$cutoff'."
}
rebase() {
local cutoff="$1"
local current="$2"
local current_hash
local errcode
log "Rebasing commits '$LAST_BASE..$current' onto cut-off branch '$cutoff' ..."
current_hash="`git show -s --pretty=%H "$current"`" &&
git rebase --rebase-merges --onto "$cutoff" "$LAST_BASE" "$current_hash" || {
errcode=$?
log "STARTING INTERACTIVE SHELL TO RESOLVE REBASE."
log "Use 'git rebase --continue' after resolving the issue e.g. with 'git mergetool'."
log "Do not forget to exit this shell to continue the script."
$SHELL
if test -e "`git rev-parse --git-dir`/rebase-merge"; then
git rebase --abort 2>/dev/null
git checkout --quiet "$current"
ret $errcode
error "Failed to transfer commits '$LAST_BASE..$current' to '$cutoff'."
fi
} &&
git rebase --rebase-merges HEAD "$cutoff" &&
git checkout --quiet "$current" &&
git update-ref "$LAST_BASE" "$current" &&
log "Cut-off branch '$cutoff' updated." &&
true
}
prepare "$CUTOFF" "$CURRENT" &&
rebase "$CUTOFF" "$CURRENT" &&
true
Используйте это, если вы хотитеотправить результат в удаленное хранилище:
$ git push <remote> cutoff:<name-of-cutoff-on-remote>