views:

1186

answers:

10

Mercurial has a way of getting to the root directory (that contains .hg) via

hg root

Is there something equivalent in git to get to the directory that contains the .git directory?

+20  A: 

cd $(git rev-parse --show-cdup). is the closest thing I was able to find for that. It doesn't look like git itself has a way to do that.

docgnome
This is all I was able to find too; may want to alias it to git-top or something similar.
John Bellone
This gives me the path to the root of the top-level/root directory, which is exactly what I was looking for.
wojo
+5  A: 

How about "git rev-parse --git-dir" ?

F:\prog\git\test\copyMerge\dirWithConflicts>git rev-parse --git-dir
F:/prog/git/test/copyMerge/.git

The --git-dir option seems to work.

From git rev-parse manual page:

--git-dir

    Show $GIT_DIR if defined else show the path to the .git directory.

You can see it in action in this git setup-sh script.

VonC
Exactly what I was looking for, since it gives the absolute path. I tried to make an alias that will also cd into this directory, but that doesn't work with "cdroot = !cd $(git rev-parse --git-dir)" sadly.
wojo
Oh wait, this was close but it gets the actual .git dir, not the base of the git repo.Also, the .git directory could be elsewhere, so this isn't what I was looking for exactly.
wojo
Right, I see now what you were actually looking for. --show-cdup is more appropriate then. I leave my answer for illustrating the difference between the two options.
VonC
It also appears that this command gives a relative path for `.git` if you're already in the root directory. (At least, it does on msysgit.)
Blair Holloway
+9  A: 

If you're already in the top-level or not in a git repository cd $(git rev-parse --show-cdup) will take you home (just cd). cd ./$(git rev-parse --show-cdup) is one way of fixing that.

Karl
+4  A: 

the man page for git-config says (under alias)

If the alias expansion is prefixed with an exclamation point, it will be treated as a shell command. For example, defining "alias.new = !gitk --all --not ORIG_HEAD", the invocation "git new" is equivalent to running the shell command "gitk --all --not ORIG_HEAD". Note that shell commands will be executed from the top-level directory of a repository, which may not necessarily be the current directory.

so on a unix system you can do

git config --global --add alias.root '!pwd'

Scott Lindsay
I think this is the best answer. Much cleaner than the other ones.
Jason Axelson
+2  A: 

To calculate the absolute path of the current git root directory, say for use in a shell script, use this combination of readlink and git rev-parse:

gitroot=$(readlink -f ./$(git rev-parse --show-cdup))

git-rev-parse --show-cdup gives you the right number of ".."s to get to the root from your cwd, or the empty string if you are at the root. Then prepend "./" to deal with the empty string case and use readlink -f to translate to a full path.

You could also create a git-root command in your PATH as a shell script to apply this technique:

cat > ~/bin/git-root << EOF
#!/bin/sh -e
cdup=$(git rev-parse --show-cdup)
exec readlink -f ./$cdup
EOF
chmod 755 ~/bin/git-root

(The above can be pasted into a terminal to create git-root and set execute bits; the actual script is in lines 2, 3 and 4.)

And then you'd be able to run git root to get the root of your current tree. Note that in the shell script, use "-e" to cause the shell to exit if the rev-parse fails so that you can properly get the exit status and error message if you are not in a git directory.

Emil
A: 

Had to solve this myself today. Solved it in C# as I needed it for a program, but I guess it can be esily rewritten. Consider this Public Domain.

public static string GetGitRoot (string file_path) {

    file_path = System.IO.Path.GetDirectoryName (file_path);

    while (file_path != null) {

        if (Directory.Exists (System.IO.Path.Combine (file_path, ".git")))
            return file_path;

        file_path = Directory.GetParent (file_path).FullName;

    }

    return null;

}
Hylke Bons
+2  A: 

As others have noted, the core of the solution is to use git rev-parse --show-cdup. However, there are a few of edge cases to address:

  1. When the cwd already is the root of the working tree, the command yields an empty string.
    Actually it produces an empty line, but command substitution strip off the trailing line break. The final result is an empty string.

    Most answers suggest prepending the output with ./ so that an empty output becomes "./" before it is fed to cd.

  2. When GIT_WORK_TREE is set to a location that is not the parent of the cwd, the output may be an absolute pathname.

    Prepending ./ is wrong in this situation. If a ./ is prepended to an absolute path, it becomes a relative path (and they only refer to the same location if the cwd is the root directory of the system).

  3. The output may contain whitespace.

    This really only applies in the second case, but it has an easy fix: use double quotes around the command substitution (and any subsequent uses of the value).

As other answers have noted, we can do cd "./$(git rev-parse --show-cdup)", but this breaks in the second edge case (and the third edge case if we leave off the double quotes).

Many shells treat cd "" as a no-op, so for those shells we could do cd "$(git rev-parse --show-cdup)" (the double quotes protect the empty string as an argument in the first edge case, and preserve whitespace in the third edge case). POSIX says the result of cd "" is unspecified, so it may be best to avoid making this assumption.

A solution that works in all of the above cases requires a test of some sort. Done explicitly, it might look like this:

cdup="$(git rev-parse --show-cdup)" && test -n "$cdup" && cd "$cdup"

No cd is done for the first edge case.

If it is acceptable to run cd . for the first edge case, then the conditional can be done in the expansion of the parameter:

cdup="$(git rev-parse --show-cdup)" && cd "${cdup:-.}"
Chris Johnsen
Why don't you just use "git config --global --add alias.root '!pwd'" and a shell alias gitroot='cd `git root`' that the answer above you uses?
Jason Axelson
A: 

To amend the "git config" answer just a bit:

git config --global --add alias.root '!pwd -P'

and get the path cleaned up. Very nice.

A: 

Good script Emil. I make the script available online, and allowed the possibility to add a file/directory as argument. http://github.com/Dieterbe/git-scripts/commit/3b7be5e25052e99d9be8ca7d9e6d5c91f8c2a14a

Dieter_be
+2  A: 

Has --show-toplevel only recently been added to git rev-parse or why is nobody mentioning it?

From the git rev-parse man page:

   --show-toplevel
       Show the absolute path of the top-level directory.
marc.guenther