Aggressive git workflow helpers for merging and cleaning up branches with automatic stash handling, multi-remote support, and branch cleanup.
⚠️ Warning: These commands delete branches locally and remotely. Use with caution.
Install them as scripts on your PATH (named git-yolopull / git-yolopush, so git picks
them up as git yolopull / git yolopush). They used to be multi-line git config aliases, but
alias values with embedded newlines break naive config parsers (e.g. git-filter-repo chokes on
them) -- a standalone script avoids that and is easier to maintain.
# pick a dir on your PATH (e.g. ~/.local/bin or /usr/local/bin)
cat > ~/.local/bin/git-yolopull <<'SCRIPT'
#!/bin/sh
# git-yolopull: merge a branch into the current branch, then delete it
# Standalone command (a git subcommand on your PATH). Kept as a script rather than a
# multi-line git alias: alias values with embedded newlines break naive config parsers
# (e.g. git-filter-repo). Run as: git yolopull ...
f() {
if [ -z "$1" ]; then echo "Usage: git yolopull <frombranch> [remotes...]"; return 1; fi;
branch="$1"; shift;
current=$(git rev-parse --abbrev-ref HEAD);
if [ "$branch" = "$current" ]; then echo "Error: Cannot merge branch into itself"; return 1; fi;
all_remotes=$(git remote);
remote_count=$(echo "$all_remotes" | wc -l);
if [ $# -gt 0 ]; then
remotes="$*";
elif [ "$remote_count" -gt 1 ]; then
echo "Multiple remotes found:";
i=1; echo "$all_remotes" | while read r; do echo " $i) $r"; i=$((i+1)); done;
printf "Select remotes (e.g. 1-3,5) or enter to skip: ";
read selection;
if [ -n "$selection" ]; then
remotes=$(echo "$selection" | tr "," "\n" | while read part; do
if echo "$part" | grep -q "-"; then
start=$(echo "$part" | cut -d"-" -f1);
end=$(echo "$part" | cut -d"-" -f2);
seq "$start" "$end";
else
echo "$part";
fi;
done | while read num; do echo "$all_remotes" | sed -n "${num}p"; done | tr "\n" " ");
else
remotes="";
fi;
elif [ "$remote_count" -eq 1 ]; then
remotes="$all_remotes";
else
remotes="";
fi;
stashed=0;
if git merge "$branch" 2>/dev/null; then
echo "Merge successful";
else
echo "Merge failed, stashing changes...";
git merge --abort 2>/dev/null;
stash_result=$(git stash push -m "yolopull-auto-stash");
if echo "$stash_result" | grep -q "No local changes"; then
echo "Error: Merge failed and no changes to stash"; return 1;
fi;
stashed=1;
if ! git merge "$branch"; then
echo "Error: Merge still fails after stashing";
git merge --abort 2>/dev/null;
git stash pop;
return 1;
fi;
echo "Merge successful after stashing, popping stash...";
if ! git stash pop; then
echo "Error: Stash pop failed, reverting merge";
git reset --hard HEAD~1;
git stash pop 2>/dev/null;
return 1;
fi;
fi;
echo "Deleting $branch locally...";
git branch -d "$branch" 2>/dev/null || git branch -D "$branch";
for remote in $remotes; do
if git ls-remote --exit-code --heads "$remote" "$branch" >/dev/null 2>&1; then
echo "Deleting $branch from $remote...";
git push "$remote" --delete "$branch";
fi;
done;
git fetch --prune;
echo "Done!";
}; f "$@"
SCRIPT
cat > ~/.local/bin/git-yolopush <<'SCRIPT'
#!/bin/sh
# git-yolopush: merge the current branch into a target, then delete the current branch
# Standalone command (a git subcommand on your PATH). Kept as a script rather than a
# multi-line git alias: alias values with embedded newlines break naive config parsers
# (e.g. git-filter-repo). Run as: git yolopush ...
f() {
if [ -z "$1" ]; then echo "Usage: git yolopush <targetbranch> [remotes...]"; return 1; fi;
target="$1"; shift;
frombranch=$(git rev-parse --abbrev-ref HEAD);
if [ "$target" = "$frombranch" ]; then echo "Error: Already on target branch"; return 1; fi;
all_remotes=$(git remote);
remote_count=$(echo "$all_remotes" | wc -l);
if [ $# -gt 0 ]; then
remotes="$*";
elif [ "$remote_count" -gt 1 ]; then
echo "Multiple remotes found:";
i=1; echo "$all_remotes" | while read r; do echo " $i) $r"; i=$((i+1)); done;
printf "Select remotes (e.g. 1-3,5) or enter to skip: ";
read selection;
if [ -n "$selection" ]; then
remotes=$(echo "$selection" | tr "," "\n" | while read part; do
if echo "$part" | grep -q "-"; then
start=$(echo "$part" | cut -d"-" -f1);
end=$(echo "$part" | cut -d"-" -f2);
seq "$start" "$end";
else
echo "$part";
fi;
done | while read num; do echo "$all_remotes" | sed -n "${num}p"; done | tr "\n" " ");
else
remotes="";
fi;
elif [ "$remote_count" -eq 1 ]; then
remotes="$all_remotes";
else
remotes="";
fi;
if ! git rev-parse --verify "$target" >/dev/null 2>&1; then
echo "Target branch does not exist, renaming $frombranch to $target...";
git branch -m "$frombranch" "$target";
for remote in $remotes; do
if git ls-remote --exit-code --heads "$remote" "$frombranch" >/dev/null 2>&1; then
echo "Updating $remote: deleting old, pushing new...";
git push "$remote" --delete "$frombranch";
git push -u "$remote" "$target";
fi;
done;
git fetch --prune;
echo "Done!";
return 0;
fi;
stashed=0;
stash_result=$(git stash push -m "yolopush-auto-stash");
if ! echo "$stash_result" | grep -q "No local changes"; then
stashed=1;
echo "Stashed local changes";
fi;
git checkout "$target";
if git merge "$frombranch" 2>/dev/null; then
echo "Merge successful";
else
echo "Merge failed, aborting...";
git merge --abort 2>/dev/null;
git checkout "$frombranch";
if [ $stashed -eq 1 ]; then git stash pop; fi;
return 1;
fi;
if [ $stashed -eq 1 ]; then
echo "Popping stash...";
if ! git stash pop; then
echo "Error: Stash pop failed, reverting merge";
git reset --hard HEAD~1;
git checkout "$frombranch";
git stash pop 2>/dev/null;
return 1;
fi;
fi;
echo "Deleting $frombranch locally...";
git branch -d "$frombranch" 2>/dev/null || git branch -D "$frombranch";
for remote in $remotes; do
if git ls-remote --exit-code --heads "$remote" "$frombranch" >/dev/null 2>&1; then
echo "Deleting $frombranch from $remote...";
git push "$remote" --delete "$frombranch";
fi;
done;
git fetch --prune;
echo "Done!";
}; f "$@"
SCRIPT
chmod +x ~/.local/bin/git-yolopull ~/.local/bin/git-yolopushMerge a branch into your current branch, then delete it.
You are on the target branch, pulling changes from another branch.
feature-branch ──┐
▼
main (you are here)
# On main branch, merge feature-branch into main
git checkout main
git yolopull feature-branch
# Specify remotes explicitly
git yolopull feature-branch origin upstreamMerge your current branch into a target branch, then delete your current branch.
You are on the feature branch, pushing changes to another branch.
feature-branch (you are here)
│
▼
main
# On feature-branch, merge into main
git checkout feature-branch
git yolopush main
# Specify remotes explicitly
git yolopush main origin upstreamIf the target branch does not exist, yolopush will rename your current branch to the target branch (locally and on selected remotes) instead of merging.
# On feature-branch, but 'release-v2' doesn't exist
git yolopush release-v2
# Result: feature-branch is renamed to release-v2| Aspect | yolopull |
yolopush |
|---|---|---|
| You are on | Target branch | Source branch |
| Argument | Source branch to merge | Target branch to merge into |
| Merge direction | arg → current |
current → arg |
| Branch deleted | Argument branch | Current branch |
| After success | Stay on current branch | End up on target branch |
| Rename behavior | — | Renames if target doesn't exist |
Both commands support flexible remote selection for branch deletion.
| Scenario | Behavior |
|---|---|
| No remotes configured | Skips remote operations |
| Single remote | Automatically selected |
| Multiple remotes | Interactive prompt (if no args) |
Pass remote names as additional arguments:
git yolopull feature-branch origin upstream fork
git yolopush main origin backupWhen multiple remotes exist and none are specified, you'll see an interactive prompt:
Multiple remotes found:
1) origin
2) upstream
3) fork
4) backup
Select remotes (e.g. 1-3,5) or enter to skip: _
Selection syntax:
| Input | Selected |
|---|---|
1 |
origin |
1,3 |
origin, fork |
1-3 |
origin, upstream, fork |
1-2,4 |
origin, upstream, backup |
| (empty) | Skip remote deletion |
Both commands follow similar error-handling logic:
┌─────────────────────────────────────────────────────────────┐
│ Start │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Try merge │
└─────────────────────────────────────────────────────────────┘
│
┌────────────┴────────────┐
│ │
Success Fail
│ │
│ ▼
│ ┌───────────────────────────────┐
│ │ Abort merge, stash changes │
│ └───────────────────────────────┘
│ │
│ ▼
│ ┌───────────────────────────────┐
│ │ Try merge again │
│ └───────────────────────────────┘
│ │
│ ┌────────────┴────────────┐
│ │ │
│ Success Fail
│ │ │
│ ▼ ▼
│ ┌──────────────┐ ┌────────────────────────┐
│ │ Pop stash │ │ Unstash, report error │
│ └──────────────┘ │ EXIT │
│ │ └────────────────────────┘
│ │
│ ┌────────┴────────┐
│ │ │
│ Success Fail
│ │ │
│ │ ▼
│ │ ┌────────────────────────────┐
│ │ │ Revert merge, restore │
│ │ │ stash, EXIT │
│ │ └────────────────────────────┘
│ │
└───┴───────────┐
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Delete branch locally │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Delete branch from selected remotes (if exists) │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ git fetch --prune │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Done! │
└─────────────────────────────────────────────────────────────┘
Both commands are designed to leave your repository in a clean state on failure:
| Failure Point | Recovery Action |
|---|---|
| Initial merge fails | Stash changes, retry |
| Merge fails after stash | Abort merge, restore stash, exit |
| Stash pop fails | Revert merge (reset --hard), restore stash, exit |
| Remote deletion fails | Continue (non-fatal) |
# Create and work on feature
git checkout -b feature/awesome-thing
# ... make commits ...
# Ready to merge into main
git yolopush main
# Result:
# - main now contains feature/awesome-thing commits
# - feature/awesome-thing deleted locally and from origin
# - You're now on main# On main, pull in a hotfix branch
git checkout main
git yolopull hotfix/critical-bug
# Result:
# - main now contains the hotfix
# - hotfix/critical-bug deleted locally and from origin
# - You're still on main# On develop, create a release (target doesn't exist)
git checkout develop
git yolopush release/v2.0
# Result:
# - develop renamed to release/v2.0
# - Remote updated (old branch deleted, new branch pushed)# You have: origin (GitHub), upstream (main repo), fork (your fork)
git yolopull feature-branch origin fork
# Deletes feature-branch from origin and fork, but not upstreamgit config --global --unset alias.yolopull
git config --global --unset alias.yolopushMIT