bin/git: move history editing functions into scripts
This commit is contained in:
parent
723393fee3
commit
a98ac98de4
|
@ -69,98 +69,5 @@ gitretag() {
|
||||||
git push origin refs/tags/${1}:refs/tags/${2} :refs/tags/$1 && git tag -d $1
|
git push origin refs/tags/${1}:refs/tags/${2} :refs/tags/$1 && git tag -d $1
|
||||||
}
|
}
|
||||||
|
|
||||||
# Rewriting history {{{
|
|
||||||
|
|
||||||
# gets the AuthorDate of a given committish
|
|
||||||
git-authordate() {
|
|
||||||
local date=$(git log --pretty=fuller --date=raw -1 $1 | grep AuthorDate)
|
|
||||||
echo ${date##*: }
|
|
||||||
}
|
|
||||||
# executes a git command (usually commit) with the date of a given committish
|
|
||||||
git-withdate() {
|
|
||||||
local date=$(git-authordate $1)
|
|
||||||
GIT_AUTHOR_DATE="$date" GIT_COMMITTER_DATE="$date" git "${@:2}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# takes all changes in the current working tree and amends them to the given commit
|
|
||||||
gitedit() {
|
|
||||||
git stash
|
|
||||||
gitcommits -q $1
|
|
||||||
git reset --keep $1
|
|
||||||
git stash pop
|
|
||||||
git-withdate $1 commit --all --amend "${@:2}"
|
|
||||||
gitcommits
|
|
||||||
}
|
|
||||||
|
|
||||||
# takes two committishs and squashes them with all commits between them into a single commit
|
|
||||||
# this will rewrite the full history from then on, but should not create any conflicts
|
|
||||||
gitsquash() {
|
|
||||||
local -a options
|
|
||||||
while [ $# -gt 0 ]; do
|
|
||||||
case $1 in
|
|
||||||
-i) local ignore=true; shift 1;;
|
|
||||||
-f|--force) local force=true; shift 1;;
|
|
||||||
-*) options+=($1); exit 1;;
|
|
||||||
*) break;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
((#!=2)) && echo "Usage: [options] <startcommit> <endcommit>" && return 1
|
|
||||||
[[ -n $(git status -s) ]] && [ ! $force ] && echo -e "Tree is dirty, commit or stash your changes first!\nIf you want to execute the command regardless, run again with --force" && return 1
|
|
||||||
|
|
||||||
local 1=$(git rev-parse $1)
|
|
||||||
local 2=$(git rev-parse $2)
|
|
||||||
[ $(git rev-list $1 --count) -lt $(git rev-list $2 --count) ] && t=$1 && 1=$2 && 2=$t
|
|
||||||
|
|
||||||
gitcommits -q $1
|
|
||||||
git reset --hard $1
|
|
||||||
if [ $(git rev-list $2 --count) = 1 ]; then
|
|
||||||
git update-ref -d HEAD
|
|
||||||
git add .
|
|
||||||
git-withdate $1 commit -c $1
|
|
||||||
else
|
|
||||||
git reset -q $2
|
|
||||||
git add .
|
|
||||||
git commit --amend
|
|
||||||
fi
|
|
||||||
gitcommits
|
|
||||||
}
|
|
||||||
|
|
||||||
# given a committish, this command saves a list of commits between the HEAD and the given committish into the .git directory
|
|
||||||
# when ran without parameters it applies the saved list of commits onto the current HEAD
|
|
||||||
gitcommits() {
|
|
||||||
local verbosity=1
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
case $1 in
|
|
||||||
-v) verbosity=2; shift 1;;
|
|
||||||
-q|--quiet) verbosity=0; shift 1;;
|
|
||||||
--theirs) local params=(-X theirs); shift 1;;
|
|
||||||
*) break;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
local stashed="$(git rev-parse --git-path stashed-commits)"
|
|
||||||
if [ $1 ]; then
|
|
||||||
if [ $verbosity -eq 0 ]
|
|
||||||
then git rev-list --reverse HEAD...$1 >$stashed
|
|
||||||
else git rev-list --reverse HEAD...$1 | tee $stashed
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
local aborted
|
|
||||||
for commit in $(cat $stashed); do
|
|
||||||
[ $aborted ] && rest+=($commit) && continue
|
|
||||||
[ $verbosity -gt 0 ] && git --no-pager log --oneline -1 $commit
|
|
||||||
git-withdate $commit cherry-pick $commit ${params:0} >/dev/null
|
|
||||||
local last=$?
|
|
||||||
[ $last -gt 0 ] && local aborted=true && typeset -a rest && continue
|
|
||||||
[ $verbosity -gt 0 ] && echo -e "\e[1A$(git log --color=always --pretty=format:"%C(yellow)$(git rev-parse --short HEAD^^)%C(bold) -> %Creset%C(yellow)%h%Creset %s" -1)"
|
|
||||||
[ $verbosity -gt 1 ] && git status -s
|
|
||||||
done
|
|
||||||
echo $rest >$stashed
|
|
||||||
[ $aborted ] && echo "A problem was encountered. Fix it and run 'gitcommits' again to apply the remaining ${#rest} commits."
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
gittestcommit() { touch file$((++i)) && git add 'file*' && git commit -m "Create file$i"; }
|
gittestcommit() { touch file$((++i)) && git add 'file*' && git commit -m "Create file$i"; }
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
#!/bin/sh -e
|
||||||
|
# The git [c]ommit st[ash]
|
||||||
|
# Given a committish, this command saves a list of commits between the HEAD and the given committish into the .git directory.
|
||||||
|
# Without parameters it applies the saved list of commits onto the current HEAD.
|
||||||
|
# NOTE: You should prefer rebase -i to this brewery.
|
||||||
|
local verbosity=1
|
||||||
|
while test $# -gt 0; do
|
||||||
|
case $1 in
|
||||||
|
(-v) verbosity=2; shift 1;;
|
||||||
|
(-q|--quiet) verbosity=0; shift 1;;
|
||||||
|
(--theirs) local params=(-X theirs); shift 1;;
|
||||||
|
(*) break;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
local stashed="$(git rev-parse --git-path stashed-commits)"
|
||||||
|
if [ $1 ]; then
|
||||||
|
if [ $verbosity -eq 0 ]
|
||||||
|
then git rev-list --reverse "HEAD...$1" >$stashed
|
||||||
|
else git rev-list --reverse "HEAD...$1" | tee $stashed
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
local aborted
|
||||||
|
for commit in $(cat $stashed); do
|
||||||
|
[ $aborted ] && rest+=($commit) && continue
|
||||||
|
[ $verbosity -gt 0 ] && git --no-pager log --oneline -1 $commit
|
||||||
|
git-withdate $commit cherry-pick $commit ${params:0} >/dev/null
|
||||||
|
local last=$?
|
||||||
|
[ $last -gt 0 ] && local aborted=true && typeset -a rest && continue
|
||||||
|
[ $verbosity -gt 0 ] && echo -e "\e[1A$(git log --color=always --pretty=format:"%C(yellow)$(git rev-parse --short 'HEAD^^')%C(bold) -> %Creset%C(yellow)%h%Creset %s" -1)"
|
||||||
|
[ $verbosity -gt 1 ] && git status -s
|
||||||
|
done
|
||||||
|
echo $rest >$stashed
|
||||||
|
[ $aborted ] && echo "A problem was encountered. Fix it and run '$0' again to apply the remaining ${#rest} commits."
|
||||||
|
fi
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
#!/bin/sh -e
|
||||||
|
# Takes all changes in the current working tree and amends them to the given commit.
|
||||||
|
# NOTE: You should prefer rebase -i to this brewery.
|
||||||
|
# The only potential advantage is the preservation of commit time,
|
||||||
|
# but that is a questionable ambition...
|
||||||
|
git stash push
|
||||||
|
git-cash -q "$1"
|
||||||
|
git reset --keep "$1"
|
||||||
|
git stash pop
|
||||||
|
git-withdate "$1" commit --all --amend "${@:2}"
|
||||||
|
git-cash
|
|
@ -0,0 +1,33 @@
|
||||||
|
#!/bin/sh -e
|
||||||
|
# Takes two committishs and squashes them with all commits inbetween into a single commit.
|
||||||
|
# This will rewrite the full history from then on, but should not create any conflicts.
|
||||||
|
# NOTE: You should prefer rebase -i to this brewery.
|
||||||
|
local -a options
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case $1 in
|
||||||
|
-i) local ignore=true; shift 1;;
|
||||||
|
-f|--force) local force=true; shift 1;;
|
||||||
|
-*) options+=($1); exit 1;;
|
||||||
|
*) break;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
test $# != 2 && echo "Usage: [options] <startcommit> <endcommit>" && return 1
|
||||||
|
[[ -n $(git status -s) ]] && [ ! $force ] && echo -e "Tree is dirty, commit or stash your changes first!\nIf you want to execute the command regardless, run again with --force" && return 1
|
||||||
|
|
||||||
|
local 1=$(git rev-parse $1)
|
||||||
|
local 2=$(git rev-parse $2)
|
||||||
|
[ $(git rev-list $1 --count) -lt $(git rev-list $2 --count) ] && t=$1 && 1=$2 && 2=$t
|
||||||
|
|
||||||
|
git-cash -q $1
|
||||||
|
git reset --hard $1
|
||||||
|
if [ $(git rev-list $2 --count) = 1 ]; then
|
||||||
|
git update-ref -d HEAD
|
||||||
|
git add .
|
||||||
|
git-withdate $1 commit -c $1
|
||||||
|
else
|
||||||
|
git reset -q $2
|
||||||
|
git add .
|
||||||
|
git commit --amend
|
||||||
|
fi
|
||||||
|
git-cash
|
|
@ -0,0 +1,4 @@
|
||||||
|
#!/bin/sh -e
|
||||||
|
# Execute a git command (usually commit) using the AuthorDate of a given committish
|
||||||
|
local date=$(git log --pretty=format:%at -1 "$1")
|
||||||
|
GIT_AUTHOR_DATE="$date" GIT_COMMITTER_DATE="$date" git "${@:2}"
|
Loading…
Reference in New Issue