Preamble
You should really consider your workflow. Most likely you are trying to achieve a strange workflow copied from some ancient VCS.
Git is used to track history and let you rewrite it. But you need to make a decision which history you want. Doing variant management regarding history is probably a bad idea.
500 commit is not a big number for Git, the Linux kernel got about 63.000 (!) commits just in 2018 ;)
Solution
Nevertheless, here is a hacky proof of concept which fulfils your needs. There is no need for a dedicated repository, the rewritten history is just stored in some dedicated branch. The first run will create that orphan branch, subsequent runs will update it with the latest commits. Both calls look the same:
$ path/to/crazy-rebase <rewritten-branch> <last-commit-to-transfer>
For example:
$ ./crazy-rebase cutoff master
How it works
During the first run, the script creates an orphan branch (e.g. cutoff
) from given revision (e.g. master
) without any previous history.
All further runs will cherry-pick every single commit (not yet present) to this orphaned branch (using a rebase). The needed commits are deduced from the last successful completion (in fact this is stored in special reference 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
Use this if you want to push the result to a remote repository:
$ git push <remote> cutoff:<name-of-cutoff-on-remote>