Does Git have its own way to canonicalize (resolve) symbolic links like readlink -f?
readlink -f, according to its page:
"canonicalize [s], following each symbolic link in each component of the given name recursively, only the last component must exist
I want a "readlink -f" equivalent for Git. In other words, a way to keep track of every symbolic link in the path at a given commit in the repository, ending with the canonical version of the path.
I wrote my own function that does this (below), but I would like to know if Git has built in functionality that does the same. And, if that's not the case, it might be worth considering including equivalent functionality in the new version of Git. Thank.
SYMLINK_FILE_TYPE_OCTAL="12"
MAX_SYMLINK_COUNT=10
git-is-symlink() {
local commit="$1"
local dir="$2"
local base="$3"
git ls-tree "${commit}:$dir" "$base" | grep -q -P "^$SYMLINK_FILE_TYPE_OCTAL"
}
git-get-symlink-target() {
local commit="$1"
local dir="$2"
local base="$3"
if test -z "$dir"; then
local path="$base"
else
local path="$dir/$base"
fi
git cat-file blob "$commit:$path"
}
git-resolve-path-recursive() {
local commit="$1"
local resolved_prefix="$2"
local segment_to_be_resolved="$3"
local unresolved_suffix="$4"
local symlink_count="$5"
if test -z "$segment_to_be_resolved" && test -z "$unresolved_suffix"; then
echo "$resolved_prefix"
return
fi
if test "$symlink_count" -gt "$MAX_SYMLINK_COUNT"; then
echo "Exceeded symlink count of $MAX_SYMLINK_COUNT on '$prefix' '$segment_to_be_resolved'" >&2
exit 1
fi
if test -n "$segment_to_be_resolved" && git-is-symlink "$commit" "$resolved_prefix" "$segment_to_be_resolved"; then
local symlink_target="$(git-get-symlink-target "$commit" "$resolved_prefix" "$segment_to_be_resolved")"
git-resolve-path-recursive "$commit" "$resolved_prefix" "$symlink_target" "$unresolved_suffix" $((++symlink_count))
else
if test -z "$resolved_prefix"; then
local new_resolved_prefix="$segment_to_be_resolved"
else
local new_resolved_prefix="$resolved_prefix/$segment_to_be_resolved"
fi
local new_segment_to_be_resolved="$(echo "$unresolved_suffix" | cut -d / -f 1)"
local new_unresolved_suffix="$(echo "$unresolved_suffix" | cut -s -d / -f 2-)"
git-resolve-path-recursive "$commit" "$new_resolved_prefix" "$new_segment_to_be_resolved" "$new_unresolved_suffix" 0
fi
}
## Main entry point
## USAGE: git-resolve-path COMMIT PATH
git-resolve-path() {
local commit="$1"
local path="$2"
git-resolve-path-recursive "$commit" "" "" "$path" 0
}
Usage example:
> mkdir -p targetdir
> ln -s targetdir linkdir
> touch targetdir/targetfile
> ln -s targetfile targetdir/linkfile
> git add targetdir linkdir targetdir/targetfile targetdir/linkfile
> git commit -m "Add files"
> git-resolve-path HEAD linkdir/linkfile
targetdir/targetfile
+3
source to share
No one has answered this question yet
Check out similar questions:
one hundred