Reputation: 33073
I wanted a simple git command to go up to the "root" of the repository.
I started with a script, but figured that I cannot change active directory of the shell, I had to do a function. Unfortunately, I cannot call it directly with the non-dash form "git root", for instance.
function git-root() {
if [ -d .git ]; then
return 0
fi
A=..
while ! [ -d $A/.git ]; do
A="$A/.."
done
cd $A
}
Do you have a better solution? (the function has been written quickly, suggestions are welcome)
Upvotes: 49
Views: 35997
Reputation: 15
alias cdg='_t=$(git rev-parse --show-toplevel) && cd "$_t" && pwd'
Short alias, yet with handling case when you're not in git repo or whatever. Also it prints current working directory (pwd
) after cd'ing, but you can remove it if want.
Upvotes: 1
Reputation: 1647
If you are using oh-my-zsh and you added the git
plugin in your
plugins+=(git)
.zshrc
configuration file, the follwing command (alias) works:
grt
This alias is defined the following way:
grt='cd "$(git rev-parse --show-toplevel \|\| echo .)"'
Upvotes: 1
Reputation: 47043
Short solutions that work with submodules, in hooks, and inside the .git
directory
Here's the short answer that most will want:
r=$(git rev-parse --git-dir) && r=$(cd "$r" && pwd)/ && cd "${r%%/.git/*}"
This will work anywhere in a git working tree (including inside the .git
directory), but assumes that repository directory(s) are called .git
(which is the default). With submodules, this will go to the root of the outermost containing repository.
If you want to get to the root of the current submodule use:
cd ''$(r=$(git rev-parse --show-toplevel) && [[ -n $r ]] && echo "$r" || (cd $(git rev-parse --git-dir)/.. && pwd) )
To easily execute a command in your submodule root, under [alias]
in your .gitconfig
, add:
sh = "!f() { root=$(pwd)/ && cd ${root%%/.git/*} && git rev-parse && exec \"$@\"; }; f"
This allows you to easily do things like git sh ag <string>
Robust solution that supports differently named or external .git
or $GIT_DIR
directories.
Note that $GIT_DIR
may point somewhere external (and not be called .git
), hence the need for further checking.
Put this in your .bashrc
:
# Print the name of the git working tree's root directory
function git_root() {
local root first_commit
# git displays its own error if not in a repository
root=$(git rev-parse --show-toplevel) || return
if [[ -n $root ]]; then
echo $root
return
elif [[ $(git rev-parse --is-inside-git-dir) = true ]]; then
# We're inside the .git directory
# Store the commit id of the first commit to compare later
# It's possible that $GIT_DIR points somewhere not inside the repo
first_commit=$(git rev-list --parents HEAD | tail -1) ||
echo "$0: Can't get initial commit" 2>&1 && false && return
root=$(git rev-parse --git-dir)/.. &&
# subshell so we don't change the user's working directory
( cd "$root" &&
if [[ $(git rev-list --parents HEAD | tail -1) = $first_commit ]]; then
pwd
else
echo "$FUNCNAME: git directory is not inside its repository" 2>&1
false
fi
)
else
echo "$FUNCNAME: Can't determine repository root" 2>&1
false
fi
}
# Change working directory to git repository root
function cd_git_root() {
local root
root=$(git_root) || return 1 # git_root will print any errors
cd "$root"
}
Execute it by typing cd_git_root
(after restarting your shell: exec bash
)
Upvotes: 3
Reputation: 1210
Simpler still, steal from Is there a way to get the git root directory in one command? , and make an alias (as suggested by Peter) from
cd "$(git rev-parse --show-toplevel)"
This works whether you're in the root directory or not.
Upvotes: 66
Reputation: 132407
This has been asked before, Is there a way to get the git root directory in one command? Copying @docgnome's answer, he writes
cd $(git rev-parse --show-cdup)
Make an alias if you like:
alias git-root='cd $(git rev-parse --show-cdup)'
Upvotes: 63
Reputation: 29
A better alias working in bash and zsh is:
alias git-root='cd "$(git rev-parse --show-cdup)"'
Upvotes: 1
Reputation: 430
Peter's answer above works great if you're in a subdirectory of the git root. If you're already in the git root, it'll throw you back to $HOME. To prevent this, we can use some bash conditionals.
if [ "`git rev-parse --show-cdup`" != "" ]; then cd `git rev-parse --show-cdup`; fi
so the alias becomes:
alias git-root='if [ "`git rev-parse --show-cdup`" != "" ]; then cd `git rev-parse --show-cdup`; fi'
Upvotes: 16
Reputation: 177875
Unfortunately, changing your current directory can only be done by the shell, not by any subprocess. By the time git gets around to parsing your command, it's already too late -- git has already been spawned in a separate process.
Here's a really gross, untested shell function that just might do what you want:
function git() {
if [ "$1" == "root" ]; then
git-root
else
git "$@"
fi
}
Upvotes: 3