If you're using zsh with extended globbing enabled, you can do it with a oneliner:
(../)#.git(:h) # relative path to containing directory, eg. '../../..', '.'
(../)#.git(:a) # absolute path to actual file, eg. '/home/you/src/prj1/.git'
(../)#.git(:ah) # absolute path to containing directory, eg. '/home/you/src/prj1'
Explanation (quoted from man zshexpn):
Recursive Globbing
A pathname component of the form (foo/)# matches a path consisting of zero or more directories matching the pattern foo. As a shorthand, **/ is equivalent to (*/)#.
Modifiers
After the optional word designator, you can add a sequence of one or more of the following modifiers, each preceded by a ':'. These modifiers also work on the result of filename generation and parameter expansion, except where noted.
- a
- Turn a file name into an absolute path: prepends the current directory, if necessary, and resolves any use of '..' and '.'
- A
- As 'a', but also resolve use of symbolic links where possible. Note that resolution of '..' occurs before resolution of symbolic links. This call is equivalent to a unless your system has the
realpath system call (modern systems do).
- h
- Remove a trailing pathname component, leaving the head. This works like '
dirname'.
Credits: Faux on #zsh for the initial suggestion of using (../)#.git(:h).