Skip to content

Commit 2fa5f34

Browse files
authored
feat: git worktree support (#478)
1 parent 56f4b0f commit 2fa5f34

File tree

2 files changed

+37
-1
lines changed

2 files changed

+37
-1
lines changed

cli/src/args.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ impl Args {
8686
return Ok(messages);
8787
}
8888

89-
let default_path = std::path::PathBuf::from(".git").join("COMMIT_EDITMSG");
89+
// Use git::edit_msg_path to correctly resolve COMMIT_EDITMSG, supporting git worktrees.
90+
let default_path = git::edit_msg_path(&self.cwd);
9091
let msg = std::fs::read_to_string(&default_path).expect(
9192
format!(
9293
"Failed to read commit message from {}",

cli/src/git.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use regex::Regex;
2+
use std::path::PathBuf;
23
use std::{collections::HashMap, process::Command};
34
/// ReadCommitMessageOptions represents the options for reading commit messages.
45
/// Transparently, it is defined to be similar to the behavior of the git log command.
@@ -14,6 +15,34 @@ pub struct ReadCommitMessageOptions {
1415
pub to: Option<String>,
1516
}
1617

18+
/// Get the path to the COMMIT_EDITMSG file.
19+
///
20+
/// Note that we use `git rev-parse --git-path COMMIT_EDITMSG` to resolve the path correctly.
21+
/// This is necessary because in a git worktree, `.git` is a file rather than a directory,
22+
/// and the actual git directory is stored elsewhere.
23+
pub fn edit_msg_path(cwd: &str) -> PathBuf {
24+
let output = Command::new("git")
25+
.current_dir(cwd)
26+
.arg("rev-parse")
27+
.arg("--git-path")
28+
.arg("COMMIT_EDITMSG")
29+
.output();
30+
31+
let git_path = match output {
32+
Ok(output) if output.status.success() => {
33+
let path_str = String::from_utf8_lossy(&output.stdout).trim().to_string();
34+
PathBuf::from(path_str)
35+
}
36+
_ => PathBuf::from(".git").join("COMMIT_EDITMSG"),
37+
};
38+
39+
if git_path.is_absolute() {
40+
git_path
41+
} else {
42+
PathBuf::from(cwd).join(git_path)
43+
}
44+
}
45+
1746
/// Get commit messages from git.
1847
pub fn read(options: ReadCommitMessageOptions) -> Vec<String> {
1948
// Configure revision range following the git spec.
@@ -138,6 +167,12 @@ pub fn parse_subject(subject: &str) -> (Option<String>, Option<String>, Option<S
138167
mod tests {
139168
use super::*;
140169

170+
#[test]
171+
fn test_edit_msg_path() {
172+
let path = edit_msg_path(".");
173+
assert!(path.to_str().unwrap().contains("COMMIT_EDITMSG"));
174+
}
175+
141176
#[test]
142177
fn test_single_line_parse_commit_message() {
143178
let input = "feat(cli): add dummy option";

0 commit comments

Comments
 (0)