clink/modules/gitutil.lua
2022-02-28 20:15:23 +01:00

84 lines
2.9 KiB
Lua

local path = require('path')
local exports = {}
---
-- Resolves closest .git directory location.
-- Navigates subsequently up one level and tries to find .git directory
-- @param {string} path Path to directory will be checked. If not provided
-- current directory will be used
-- @return {string} Path to .git directory or nil if such dir not found
exports.get_git_dir = function (start_dir)
-- Checks if provided directory contains '.git' directory
-- and returns path to that directory
local function has_git_dir(dir)
return #clink.find_dirs(dir..'/.git') > 0 and dir..'/.git'
end
-- checks if directory contains '.git' _file_ and if it does
-- parses it and returns a path to git directory from that file
local function has_git_file(dir)
local gitfile = io.open(dir..'/.git')
if not gitfile then return false end
local git_dir = gitfile:read():match('gitdir: (.*)')
gitfile:close()
if not git_dir then return false end
-- If found path is absolute don't prepend initial
-- directory - return absolute path value
return path.is_absolute(git_dir) and git_dir
or dir..'/'..git_dir
end
-- Set default path to current directory
if not start_dir or start_dir == '.' then start_dir = clink.get_cwd() end
-- Calculate parent path now otherwise we won't be
-- able to do that inside of logical operator
local parent_path = path.pathname(start_dir)
return has_git_dir(start_dir)
or has_git_file(start_dir)
-- Otherwise go up one level and make a recursive call
or (parent_path ~= start_dir and exports.get_git_dir(parent_path) or nil)
end
exports.get_git_common_dir = function (start_dir)
local git_dir = exports.get_git_dir(start_dir)
if not git_dir then return git_dir end
local commondirfile = io.open(git_dir..'/commondir')
if commondirfile then
-- If there's a commondir file, we're in a git worktree
local commondir = commondirfile:read()
commondirfile.close()
return path.is_absolute(commondir) and commondir
or git_dir..'/'..commondir
end
return git_dir
end
---
-- Find out current branch
-- @return {nil|git branch name}
---
exports.get_git_branch = function (dir)
local git_dir = dir or exports.get_git_dir()
-- If git directory not found then we're probably outside of repo
-- or something went wrong. The same is when head_file is nil
local head_file = git_dir and io.open(git_dir..'/HEAD')
if not head_file then return end
local HEAD = head_file:read()
head_file:close()
-- if HEAD matches branch expression, then we're on named branch
-- otherwise it is a detached commit
local branch_name = HEAD:match('ref: refs/heads/(.+)')
return branch_name or 'HEAD detached at '..HEAD:sub(1, 7)
end
return exports