|
1 | | -use std::process::Command; |
| 1 | +use std::{path::PathBuf, process::Command}; |
2 | 2 |
|
3 | 3 | use anyhow::{Context, Result, bail}; |
4 | 4 |
|
@@ -69,6 +69,33 @@ fn get_git_rev(abbreviate_to: Option<usize>) -> Result<String> { |
69 | 69 | Ok(raw_rev.trim().to_owned()) |
70 | 70 | } |
71 | 71 |
|
| 72 | +/// Get the existing Git files that determine the current `HEAD` commit. |
| 73 | +/// |
| 74 | +/// This works for ordinary repositories, linked worktrees, both symbolic and detached `HEAD`s, |
| 75 | +/// and packed refs. |
| 76 | +pub fn get_git_head_paths() -> Result<Vec<PathBuf>> { |
| 77 | + let mut paths = vec![get_git_path("HEAD")?.context("Git HEAD is missing")?]; |
| 78 | + |
| 79 | + if let Ok(head_ref) = run_command(&["git", "symbolic-ref", "--quiet", "HEAD"]) |
| 80 | + && let Some(path) = get_git_path(head_ref.trim())? |
| 81 | + { |
| 82 | + paths.push(path); |
| 83 | + } |
| 84 | + |
| 85 | + if let Some(path) = get_git_path("packed-refs")? { |
| 86 | + paths.push(path); |
| 87 | + } |
| 88 | + |
| 89 | + Ok(paths) |
| 90 | +} |
| 91 | + |
| 92 | +/// Get the absolute path to a Git file when it exists. |
| 93 | +fn get_git_path(path: &str) -> Result<Option<PathBuf>> { |
| 94 | + let path = run_command(&["git", "rev-parse", "--path-format=absolute", "--git-path", path])?; |
| 95 | + let path = PathBuf::from(path.trim()); |
| 96 | + Ok(path.exists().then_some(path)) |
| 97 | +} |
| 98 | + |
72 | 99 | fn run_command(program_and_args: &[&str]) -> Result<String> { |
73 | 100 | let mut command = Command::new(program_and_args[0]); |
74 | 101 | command.args(&program_and_args[1..]); |
|
0 commit comments