|
|
|
@@ -1,8 +1,13 @@
|
|
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
|
|
|
|
|
# git-fresh
|
|
|
|
|
# https://github.com/imsky/git-fresh
|
|
|
|
|
# By Ivan Malopinsky - http://imsky.co
|
|
|
|
|
# MIT License
|
|
|
|
|
|
|
|
|
|
usage () {
|
|
|
|
|
cat << EOD
|
|
|
|
|
Usage: git fresh [-fmrF] [-sl] [remote] [root]
|
|
|
|
|
Usage: git fresh [-fmrtF] [-sl] [remote] [root]
|
|
|
|
|
By default, git-fresh will:
|
|
|
|
|
- rebase against remote current branch
|
|
|
|
|
- stash changes
|
|
|
|
@@ -11,6 +16,7 @@ By default, git-fresh will:
|
|
|
|
|
-f: Delete stale local and remote branches
|
|
|
|
|
-m: Merge remote root into current branch
|
|
|
|
|
-r: Rebase current branch against remote root
|
|
|
|
|
-t: Remove local tags that do not exist on remote
|
|
|
|
|
-F: Reset local root to remote root, wipe workspace
|
|
|
|
|
|
|
|
|
|
-s: Apply stashed changes after run
|
|
|
|
@@ -20,16 +26,25 @@ remote: remote name, origin by default
|
|
|
|
|
root: root branch, master by default
|
|
|
|
|
EOD
|
|
|
|
|
|
|
|
|
|
exit 0;
|
|
|
|
|
exit 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
say () {
|
|
|
|
|
echo "[git-fresh] $@" 1>&2
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
die () {
|
|
|
|
|
say $@
|
|
|
|
|
exit 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
error () {
|
|
|
|
|
echo -n "[git-fresh] error on line $1"
|
|
|
|
|
die "error on line $1"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
trap 'error $LINENO' ERR
|
|
|
|
|
|
|
|
|
|
while getopts ":fmrslF" opt; do
|
|
|
|
|
while getopts ":fmrtslF" opt; do
|
|
|
|
|
case $opt in
|
|
|
|
|
f)
|
|
|
|
|
FORCE_DELETE_STALE=true
|
|
|
|
@@ -40,6 +55,9 @@ while getopts ":fmrslF" opt; do
|
|
|
|
|
r)
|
|
|
|
|
REBASE=true
|
|
|
|
|
;;
|
|
|
|
|
t)
|
|
|
|
|
TAGS=true
|
|
|
|
|
;;
|
|
|
|
|
s)
|
|
|
|
|
APPLY_STASH=true
|
|
|
|
|
;;
|
|
|
|
@@ -58,20 +76,46 @@ done
|
|
|
|
|
|
|
|
|
|
shift $((OPTIND-1))
|
|
|
|
|
|
|
|
|
|
# Are we inside a git repository?
|
|
|
|
|
|
|
|
|
|
INSIDE_GIT_REPO=$(git rev-parse --is-inside-work-tree 2> /dev/null)
|
|
|
|
|
|
|
|
|
|
if [[ -z "$INSIDE_GIT_REPO" ]]; then
|
|
|
|
|
die "Not a git repository"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# Are we in a non-empty git repository?
|
|
|
|
|
|
|
|
|
|
TOP_LEVEL_DIRECTORY=$(git rev-parse --show-toplevel)
|
|
|
|
|
|
|
|
|
|
[[ $(ls -l "$TOP_LEVEL_DIRECTORY/.git/refs/heads" | wc -l) -eq "1" ]] && die "No HEAD ref available"
|
|
|
|
|
|
|
|
|
|
CURRENT=$(git rev-parse --abbrev-ref HEAD)
|
|
|
|
|
REMOTE=${1:-origin}
|
|
|
|
|
ROOT=${2:-master}
|
|
|
|
|
|
|
|
|
|
# Update remotes and prune stale remotes
|
|
|
|
|
|
|
|
|
|
git remote update
|
|
|
|
|
git remote prune $REMOTE
|
|
|
|
|
|
|
|
|
|
STASH_STAMP=git-fresh-$(date +%s)
|
|
|
|
|
|
|
|
|
|
# Stash changed files
|
|
|
|
|
|
|
|
|
|
if ! git diff-files --quiet; then
|
|
|
|
|
git stash save $STASH_STAMP
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
git rebase $REMOTE $CURRENT
|
|
|
|
|
# If the current branch exists on the remote, rebase against it
|
|
|
|
|
|
|
|
|
|
REMOTE_CURRENT=$(git ls-remote $REMOTE --heads 2> /dev/null | grep "heads/$CURRENT$" | cat)
|
|
|
|
|
|
|
|
|
|
if [[ ! -z "$REMOTE_CURRENT" ]]; then
|
|
|
|
|
git rebase $REMOTE $CURRENT
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# Switch to root branch (master)
|
|
|
|
|
|
|
|
|
|
git checkout $ROOT > /dev/null 2>&1
|
|
|
|
|
|
|
|
|
@@ -82,6 +126,8 @@ else
|
|
|
|
|
git rebase -q $REMOTE/$ROOT
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# Compute stale branches
|
|
|
|
|
|
|
|
|
|
SMART_STALE=$(git branch -a --merged | tr -d "\* " | grep -Ev ">|$ROOT" | cat)
|
|
|
|
|
|
|
|
|
|
LOCAL_STALE=$(grep -Ev "^remotes/" <<< "$SMART_STALE" | cat)
|
|
|
|
@@ -94,9 +140,9 @@ if [[ ! -z "${SMART_STALE// }" ]]; then
|
|
|
|
|
if [[ ! -z "${LOCAL_STALE// }" ]]; then
|
|
|
|
|
STALE_BRANCHES=true
|
|
|
|
|
if [[ "$FORCE_DELETE_STALE" = true ]]; then
|
|
|
|
|
echo -n $LOCAL_STALE | xargs git branch -d 2> /dev/null
|
|
|
|
|
echo -n $LOCAL_STALE | xargs -0 git branch -d 2> /dev/null
|
|
|
|
|
else
|
|
|
|
|
echo "Local stale branches found:" $(echo -n $LOCAL_STALE | tr "\n" " ")
|
|
|
|
|
say "Local stale branches found:" $(echo -n $LOCAL_STALE | tr "\n" " ")
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
@@ -104,23 +150,25 @@ if [[ ! -z "${SMART_STALE// }" ]]; then
|
|
|
|
|
STALE_BRANCHES=true
|
|
|
|
|
if [[ "$FORCE_DELETE_STALE" = true ]]; then
|
|
|
|
|
if [[ "$DELETE_ONLY_LOCAL" != true ]]; then
|
|
|
|
|
echo -n $REMOTE_STALE | xargs git push $REMOTE --delete
|
|
|
|
|
echo -n $REMOTE_STALE | xargs -0 git push $REMOTE --delete
|
|
|
|
|
fi
|
|
|
|
|
else
|
|
|
|
|
echo "Remote stale branches found:" $(echo -n $REMOTE_STALE | tr "\n" " ")
|
|
|
|
|
say "Remote stale branches found:" $(echo -n $REMOTE_STALE | tr "\n" " ")
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if [[ "$FORCE_DELETE_STALE" != true && "$STALE_BRANCHES" = true ]]; then
|
|
|
|
|
echo "Delete stale branches with: git fresh -f"
|
|
|
|
|
say "Delete stale branches with: git fresh -f"
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# Rebase or merge remote root against local branch
|
|
|
|
|
|
|
|
|
|
if [[ ! -z $(git rev-parse --verify --quiet "$CURRENT") ]]; then
|
|
|
|
|
git checkout $CURRENT 2> /dev/null
|
|
|
|
|
|
|
|
|
|
if [ "$REBASE" = true ] && [ "$MERGE" = true ]; then
|
|
|
|
|
echo "Rebase and merge enabled, skipping both"
|
|
|
|
|
say "Rebase and merge enabled, skipping both"
|
|
|
|
|
else
|
|
|
|
|
if [[ "$REBASE" = true ]]; then
|
|
|
|
|
git rebase $REMOTE/$ROOT
|
|
|
|
@@ -134,11 +182,27 @@ else
|
|
|
|
|
echo "$CURRENT branch was stale, staying on $ROOT"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# Remove local tags that are missing on the remote
|
|
|
|
|
|
|
|
|
|
if [[ "$TAGS" = true ]]; then
|
|
|
|
|
REMOTE_TAGS=$(git ls-remote --tags $REMOTE | cut -f 2)
|
|
|
|
|
LOCAL_TAGS=$(git show-ref --tags | cut -d' ' -f 2)
|
|
|
|
|
|
|
|
|
|
for tag in $LOCAL_TAGS; do
|
|
|
|
|
if [[ -z $(grep $tag <<< "$REMOTE_TAGS" | cat) ]]; then
|
|
|
|
|
MISSING_TAG="${tag//refs\/tags\/}"
|
|
|
|
|
git tag -d $MISSING_TAG
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# Restore stashed changes
|
|
|
|
|
|
|
|
|
|
if [[ ! -z $(git stash list | grep $STASH_STAMP | cat) ]]; then
|
|
|
|
|
if [[ "$APPLY_STASH" = true ]]; then
|
|
|
|
|
git stash pop
|
|
|
|
|
else
|
|
|
|
|
echo "Stashed changes present, apply with: git stash pop"
|
|
|
|
|
say "Stashed changes present, apply with: git stash pop"
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|