I believe the key is the realization that you are performing a double rename: master
to master-old
and also master-new
to master
.
From all the other answers I have synthesized this:
doublerename master-new master master-old
where we first have to define the doublerename
Bash function:
# doublerename NEW CURRENT OLD
# - arguments are branch names
# - see COMMIT_MESSAGE below
# - the result is pushed to origin, with upstream tracking info updated
doublerename() {
local NEW=$1
local CUR=$2
local OLD=$3
local COMMIT_MESSAGE="Double rename: $NEW -> $CUR -> $OLD.
This commit replaces the contents of '$CUR' with the contents of '$NEW'.
The old contents of '$CUR' now lives in '$OLD'.
The name '$NEW' will be deleted.
This way the public history of '$CUR' is not rewritten and clients do not have
to perform a Rebase Recovery.
"
git branch --move $CUR $OLD
git branch --move $NEW $CUR
git checkout $CUR
git merge -s ours $OLD -m $COMMIT_MESSAGE
git push --set-upstream --atomic origin $OLD $CUR :$NEW
}
This is similar to a history-changing git rebase
in that the branch contents is quite different, but it differs in that the clients can still safely fast-forward with git pull master
.