Add custom git commands to dotfiles repo

Include git-branch-backup, git-fix-author, git-name-stash,
git-name-stash-apply, git-rebase-on, and git-rename-branch in a new
bin/ directory. Update install.sh to symlink them into ~/bin and
document them in the README.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-03-09 10:43:09 -04:00
parent 5818d60cc4
commit a20358865a
8 changed files with 97 additions and 0 deletions

View File

@@ -146,6 +146,19 @@ pyenv global 3.13.3
tfenv install latest tfenv install latest
``` ```
## Custom git commands
The `bin/` directory contains custom git subcommands that are symlinked into `~/bin` by the install script. Make sure `~/bin` is on your PATH (the dotfiles handle this).
| Command | Description |
|---------|-------------|
| `git branch-backup` | Create a timestamped backup branch of the current branch |
| `git fix-author` | Rewrite commit author/email on historical commits |
| `git name-stash <name>` | Stash changes with a named message |
| `git name-stash-apply <name>` | Apply a stash by name |
| `git rebase-on <branch>` | Back up current branch, then pull and rebase onto the given branch |
| `git rename-branch <old> <new>` | Rename a branch locally and on the remote |
## What's included ## What's included
| File | Purpose | | File | Purpose |
@@ -159,5 +172,6 @@ tfenv install latest
| `gitconfig` | Git aliases, colors, push config | | `gitconfig` | Git aliases, colors, push config |
| `gitignore_global` | Global gitignore (.DS_Store, *~) | | `gitignore_global` | Global gitignore (.DS_Store, *~) |
| `fzf.zsh` | fzf PATH and shell integration | | `fzf.zsh` | fzf PATH and shell integration |
| `bin/git-*` | Custom git subcommands (see above) |
| `Brewfile` | All Homebrew packages and casks | | `Brewfile` | All Homebrew packages and casks |
| `install.sh` | Symlink installer script | | `install.sh` | Symlink installer script |

9
bin/git-branch-backup Executable file
View File

@@ -0,0 +1,9 @@
#!/bin/zsh -f
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
if [[ $CURRENT_BRANCH == HEAD ]] ; then
CURRENT_BRANCH=$(git rev-parse --short HEAD) # in case detached HEAD
fi
NEW_BRANCH=${CURRENT_BRANCH}-backup-$(date +%Y%m%d-%H%M%S)
git checkout -b $NEW_BRANCH
git checkout -

51
bin/git-fix-author Executable file
View File

@@ -0,0 +1,51 @@
#!/bin/bash
OLD=""
NEW_NAME=""
NEW_EMAIL=""
ARGS=$(getopt -o o:n:h -l "old:,new:,help" -n $0 -- "$@")
[ $? -eq 0 ] || exit 1
eval set -- "$ARGS"
while true
do
case "$1" in
-o|--old)
OLD=$2
shift 2
;;
-n|--new)
NEW=$2
NEW_NAME=$(echo "$NEW" | awk -F'[<>]' '{print $1}' | sed 's/ *$//')
NEW_EMAIL=$(echo "$NEW" | awk -F'[<>]' '{print $2}')
shift 2
;;
-h|--help)
echo "usage: git fix-author --old diz@cpan.org --new 'Mike Eldridge <mike.eldridge@iinteractive.com>' ref"
exit
;;
--)
shift
break
;;
esac
done
echo "OLD=\"$OLD\""
echo "NEW_NAME=\"$NEW_NAME\""
echo "NEW_EMAIL=\"$NEW_EMAIL\""
git filter-branch --commit-filter "
if [ \"\$GIT_COMMITTER_EMAIL\" = \"$OLD\" ];
then
GIT_COMMITTER_NAME=\"$NEW_NAME\";
GIT_AUTHOR_NAME=\"$NEW_NAME\";
GIT_COMMITTER_EMAIL=\"$NEW_EMAIL\";
GIT_AUTHOR_EMAIL=\"$NEW_EMAIL\";
git commit-tree \"\$@\";
else
git commit-tree \"\$@\";
fi" $@

3
bin/git-name-stash Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/zsh -f
git stash push -m $1

3
bin/git-name-stash-apply Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/zsh -f
git stash apply stash^{/$1}

4
bin/git-rebase-on Executable file
View File

@@ -0,0 +1,4 @@
#!/bin/zsh -f
git branch-backup
git checkout $1 && git pull && git checkout - && git rebase $1

4
bin/git-rename-branch Executable file
View File

@@ -0,0 +1,4 @@
#!/bin/zsh -f
git branch-backup
git checkout $1 && git branch -m $2 && git push origin -u $2 && git push origin --delete $1

View File

@@ -55,6 +55,15 @@ link_file "gitconfig" ".gitconfig"
link_file "gitignore_global" ".gitignore_global" link_file "gitignore_global" ".gitignore_global"
link_file "fzf.zsh" ".fzf.zsh" link_file "fzf.zsh" ".fzf.zsh"
# Symlink custom git commands into ~/bin
echo ""
echo "=== Custom git commands ==="
mkdir -p "$HOME/bin"
for cmd in "$DOTFILES_DIR"/bin/git-*; do
name="$(basename "$cmd")"
link_file "bin/$name" "bin/$name"
done
echo "" echo ""
echo "=== Symlinks complete ===" echo "=== Symlinks complete ==="
echo "" echo ""