git_state/
lib.rs

1use std::fmt;
2use std::path::Path;
3
4/// Determine the state of a git repository.
5///
6/// This checks whether the progress is in a merging/rebasing/bisecing/etc state.
7/// If in no such state, `Clean` is returned.
8///
9/// Based on:
10/// - https://github.com/libgit2/libgit2/blob/52294c413100ed4930764addc69beadd82382a4c/src/repository.c#L2867-L2908
11/// - https://libgit2.org/libgit2/#HEAD/group/repository/git_repository_state
12pub fn git_state(repo: &Path) -> Result<RepositoryState, ()> {
13    let git_dir = repo.join(".git");
14    let git_dir = if git_dir.is_dir() { &git_dir } else { repo };
15
16    if git_dir.join("rebase-merge/interactive").is_file() {
17        Ok(RepositoryState::RebaseInteractive)
18    } else if git_dir.join("rebase-merge").is_dir() {
19        Ok(RepositoryState::RebaseMerge)
20    } else if git_dir.join("rebase-apply/rebasing").is_file() {
21        Ok(RepositoryState::Rebase)
22    } else if git_dir.join("rebase-apply/applying").is_file() {
23        Ok(RepositoryState::ApplyMailbox)
24    } else if git_dir.join("rebase-apply").is_dir() {
25        Ok(RepositoryState::ApplyMailboxOrRebase)
26    } else if git_dir.join("MERGE_HEAD").is_file() {
27        Ok(RepositoryState::Merge)
28    } else if git_dir.join("REVERT_HEAD").is_file() {
29        if git_dir.join("sequencer/todo").is_file() {
30            Ok(RepositoryState::RevertSequence)
31        } else {
32            Ok(RepositoryState::Revert)
33        }
34    } else if git_dir.join("CHERRY_PICK_HEAD").is_file() {
35        if git_dir.join("sequencer/todo").is_file() {
36            Ok(RepositoryState::CherryPickSequence)
37        } else {
38            Ok(RepositoryState::CherryPick)
39        }
40    } else if git_dir.join("BISECT_LOG").is_file() {
41        Ok(RepositoryState::Bisect)
42    } else {
43        Ok(RepositoryState::Clean)
44    }
45}
46
47/// Git repository state.
48///
49/// Based on:
50/// - https://libgit2.org/libgit2/#HEAD/type/git_repository_state_t
51#[derive(Debug, PartialEq, Eq, Copy, Clone)]
52pub enum RepositoryState {
53    Clean,
54    Merge,
55    Revert,
56    RevertSequence,
57    CherryPick,
58    CherryPickSequence,
59    Bisect,
60    Rebase,
61    RebaseInteractive,
62    RebaseMerge,
63    ApplyMailbox,
64    ApplyMailboxOrRebase,
65}
66
67impl fmt::Display for RepositoryState {
68    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69        write!(f, "{:?}", self)
70    }
71}