38

Example:

$ cd lib
$ git absolute-path test.c # how to do this?
lib/test.c
Jo Liss
  • 30,333
  • 19
  • 121
  • 170

4 Answers4

40

Use git ls-files:

$ cd lib
$ git ls-files --full-name test.c
lib/test.c

This only works for files that have been committed into the repo, but it's better than nothing.

Jo Liss
  • 30,333
  • 19
  • 121
  • 170
  • I had to use a wildcard, or else didn't find the file unless it's in the root of the repo. Use $ git ls-files --full-name *test.c – Pedro García Medina Jan 13 '21 at 18:50
  • @PedroGarcíaMedina Both commands I posted expect `test.c` to be a path relative to the current working directory. So they're for when you already know where a file is located, but you want to convert the path to an "absolute" path relative to the repo root. If you're trying to instead *search* the entire repo for a file named `test.c`, I recommend running `cd "$(git rev-parse --show-toplevel)"; git ls-files --full-name '*/test.c' 'test.c'`. Note the quote marks to prevent your shell from interpolating the asterisk. – Jo Liss Jan 15 '21 at 15:07
7

Pasting the following into your bash terminal will work, regardless of whether "test.c" currently exists or not. You can copy the git-absolute-path function into your .bashrc file for future convenience.

git-absolute-path () {
    fullpath=$([[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}")
    gitroot="$(git rev-parse --show-toplevel)" || return 1
    [[ "$fullpath" =~ "$gitroot" ]] && echo "${fullpath/$gitroot\//}"
}

git-absolute-path test.c
gmatht
  • 835
  • 6
  • 14
1

In order to get the path of the current directory, relative to the git root, I ended up doing this:

if gitroot=$(git rev-parse --show-toplevel 2>/dev/null); then
    directory=$(realpath --relative-to="$gitroot" .)
fi

(I'm assuming Bash and I do not know how portable this is.)

YoungFrog
  • 1,080
  • 10
  • 16
1

I would like to improve on @gmatht's answer by making it work in an corner-case, by resolving the git root differently:

git-absolute-path () {
    fullpath=$([[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}")
    gitroot="$(echo $(cd $(git rev-parse --show-cdup) .; pwd))" || return 1
    [[ "$fullpath" =~ "$gitroot" ]] && echo "${fullpath/$gitroot\//}"
}

The corner-case I'm referring to is when your git repo is in /tmp and you're on Windows. /tmp seems to be a special case: it refers to your Windows user's temp folder i.e. C:/Users/<user>/AppData/Local/Temp. (Not sure "how" it refers to that, it doesn't appear to be a symlink. Like I said, a special case). In any case, fullpath can be like /tmp/your-temp-repo but gitroot can be like C:/Users/<user>/AppData/Local/Temp/your-temp-repo but then they're not equal and git-absolute-path returns nothing incorrectly.

JBSnorro
  • 6,048
  • 3
  • 41
  • 62