git-hop includes optional shell integration that enables automatic directory switching when you hop between worktrees.
Without shell integration, navigating to a worktree requires two steps:
git hop feature-branch # Updates git-hop state
cd /path/to/worktree # Manually navigateWith shell integration, it's a single command:
git-hop feature-branch # Automatically cd to worktreeEnable the shell wrapper during init (or re-init):
git hop init --enable-chdirThis adds a shell function to your RC file (~/.bashrc, ~/.zshrc, or ~/.config/fish/config.fish).
Supported shells: bash, zsh, fish
After installation, restart your shell or run:
source ~/.bashrc # or ~/.zshrc for zshOnce installed, use git-hop (note: with hyphen, not space) for automatic navigation:
git-hop feature-branch # Automatically cd to worktree
git-hop main # Switch back to main
git-hop add new-feature # Create and navigate to new worktreeRegular git hop (with space) still works but won't change directories.
git-hop maintains a current symlink in each repository hub that always points to the last worktree you navigated to:
my-repo/
├── .git/ (bare repository)
├── hop.json
├── current -> hops/main (symlink - always points to last hop)
└── hops/
├── main/
├── feature-a/
└── feature-b/
Every time you run a git-hop command that navigates to a worktree, the current symlink updates:
git-hop feature-a # current -> hops/feature-a
git-hop main # current -> hops/main
git-hop add feat-b # current -> hops/feat-bThe shell integration installs a git-hop() function that:
- Detects if the command should trigger navigation (add, clone, init, branch names)
- Calls the real
git hopbinary - On success, automatically
cdto thecurrentsymlink
# What the wrapper does:
git-hop feature-branch
# → runs: git hop feature-branch
# → updates: current -> hops/feature-branch
# → runs: cd $(git rev-parse --show-toplevel)/../currentInstalls the shell wrapper function to your RC file.
git hop init --enable-chdirWhat it does:
- Detects your shell (bash/zsh/fish)
- Appends the wrapper function to your RC file
- Updates global config to track installation status
- Preserves existing RC file content
- Safe to re-run on already-initialized repos
Output:
Shell integration installed to: /home/user/.bashrc
Restart your shell or run: source /home/user/.bashrc
To remove the wrapper, delete the git-hop shell integration block from your RC file (~/.bashrc, ~/.zshrc, or ~/.config/fish/config.fish) manually.
After removing: You'll need to manually navigate to worktrees:
git hop feature-branch
cd $(git rev-parse --show-toplevel)/../currentShell integration status is tracked in your global config (~/.config/git-hop/global.json):
{
"shellIntegration": {
"status": "approved",
"installedShell": "bash",
"installedPath": "/home/user/.bashrc",
"installedAt": "2025-02-05T..."
}
}Status values:
unknown- Never prompted (default for new installs)approved- User installed shell integrationdeclined- User declined or uninstalleddisabled- User used--no-setupflag (never prompt)
The current symlink is shared across all terminal sessions. The last git-hop command in any terminal determines where current points:
# Terminal 1
git-hop feature-a # current -> hops/feature-a
# Terminal 2 (later)
git-hop feature-b # current -> hops/feature-b
# Terminal 1 (current now points to feature-b)
cd ../current # Goes to feature-b, not feature-aNote: Each terminal maintains its own $PWD (current directory), so this only affects new navigation commands, not your existing shell sessions.
Problem: Running git-hop says "command not found"
Solution:
- Verify installation:
git hop init --enable-chdir - Restart your shell:
exec $SHELL - Check your RC file has the wrapper:
grep "git-hop shell integration" ~/.bashrc
Problem: git-hop <branch> doesn't change directory
Solutions:
-
Using wrong command: Use
git-hop(hyphen), notgit hop(space)git-hop feature-branch ✓ Correct git hop feature-branch ✗ Won't auto-cd -
Not in a git-hop repository:
git hop init # Initialize git-hop first -
Symlink doesn't exist: The current symlink should be created automatically. Verify:
ls -la $(git rev-parse --show-toplevel)/../current
Problem: Wrapper function appears multiple times in RC file
Solution: The installation is idempotent (safe to run multiple times). If you see duplicates:
- Manually remove duplicate entries from RC file
- Or uninstall and reinstall:
# Remove the git-hop shell integration block from your RC file manually, then: git hop init --enable-chdir
Problem: Shell integration prompts/interferes in CI/scripts
Solution: The wrapper automatically detects non-interactive environments:
- Checks for
CIenvironment variable - Checks for
HOP_NO_SHELL_INTEGRATIONflag - Only installs in interactive terminals
To explicitly disable:
export HOP_NO_SHELL_INTEGRATION=1
git hop <command>If you prefer not to use shell integration, you can still navigate manually:
git hop feature-branch
cd $(git rev-parse --show-toplevel)/../currentOr create your own alias:
alias hopc='git hop "$@" && cd $(git rev-parse --show-toplevel)/../current'You can customize the wrapper function by editing your RC file. The installed function looks like:
# git-hop shell integration (installed by git-hop)
git-hop() {
local should_cd=false
local first_arg="$1"
# Determine if this command should trigger cd
case "$first_arg" in
add|init|clone|''|[!-]*)
should_cd=true
;;
list|status|doctor|prune|env|--help|-h|--version|-v)
should_cd=false
;;
esac
# Call the real binary with wrapper marker
HOP_WRAPPER_ACTIVE=1 command git hop "$@"
local exit_code=$?
# Only cd if successful and eligible
if [[ $exit_code -eq 0 ]] && [[ "$should_cd" = true ]]; then
local hub_root
hub_root=$(git rev-parse --show-toplevel 2>/dev/null)
if [[ -n "$hub_root" ]]; then
local current="$hub_root/../current"
if [[ ! -e "$current" ]]; then
current="$hub_root/current"
fi
if [[ -d "$current" ]]; then
cd "$current" || true
fi
fi
fi
return $exit_code
}Customization ideas:
- Change which commands trigger cd
- Add pre/post-hop hooks
- Customize error handling
For fish users, the wrapper uses fish syntax:
# git-hop shell integration (installed by git-hop)
function git-hop
set -l should_cd false
set -l first_arg $argv[1]
switch "$first_arg"
case add init clone '' '[!-]*'
set should_cd true
case list status doctor prune env --help -h --version -v
set should_cd false
end
env HOP_WRAPPER_ACTIVE=1 command git hop $argv
set -l exit_code $status
if test $exit_code -eq 0; and test "$should_cd" = true
set -l hub_root (git rev-parse --show-toplevel 2>/dev/null)
if test -n "$hub_root"
set -l current "$hub_root/../current"
if not test -e "$current"
set current "$hub_root/current"
end
if test -d "$current"
cd "$current" 2>/dev/null; or true
end
end
end
return $exit_code
endQ: Do I need shell integration?
A: No, it's optional. git-hop works perfectly fine without it, you'll just need to manually cd to worktrees.
Q: What's the difference between git hop and git-hop?
A:
git hop(space) - The actual binary, doesn't change directoriesgit-hop(hyphen) - The shell wrapper function, auto-cd enabled
Q: Can I use both git hop and git-hop?
A: Yes! Use git-hop when you want auto-cd, use git hop when you don't.
Q: Does this work with oh-my-zsh/prezto/other frameworks? A: Yes, the wrapper function is compatible with all shell frameworks. It's just a regular function appended to your RC file.
Q: Is the current symlink safe with git operations?
A: Yes, git ignores symlinks in the root directory. The current symlink won't interfere with git operations.
Q: What if I delete the current symlink? A: It will be recreated the next time you run a git-hop navigation command (hop, add, clone, init).
Q: Does this work on Windows? A: The current symlink works on Windows with WSL. Native Windows (without WSL) has limited symlink support and is not currently tested.
- Main README - Full git-hop documentation
- Configuration Guide - Global and local config options
- Command Reference - All git-hop commands