Skip to main content

git_gardener/git/
status.rs

1use git2::{Repository, Status};
2use std::path::Path;
3use crate::error::{GitGardenerError, Result};
4
5// 🔴 RED: Gitワーキングツリーのステータス(まだ基本実装のみ)
6#[derive(Debug, Clone, PartialEq)]
7pub enum WorktreeStatus {
8    Clean,
9    Dirty,
10    Ahead,
11    Behind,
12    Diverged,
13}
14
15// 🔴 RED: Gitステータス情報を保持する構造体(まだ基本実装のみ)
16#[derive(Debug, Clone)]
17pub struct GitStatus {
18    pub working_tree_status: WorktreeStatus,
19    pub has_staged_changes: bool,
20    pub has_unstaged_changes: bool,
21    pub last_commit_time: Option<i64>,
22    pub ahead_count: u32,
23    pub behind_count: u32,
24}
25
26impl GitStatus {
27    pub fn from_path(path: &Path) -> Result<Self> {
28        let repo = Repository::open(path).map_err(|e| {
29            GitGardenerError::Custom(format!("Failed to open repository: {}", e))
30        })?;
31        
32        Self::from_repository(&repo)
33    }
34    
35    pub fn from_repository(repo: &Repository) -> Result<Self> {
36        // ワーキングツリーの状態をチェック
37        let statuses = repo.statuses(None).map_err(|e| {
38            GitGardenerError::Custom(format!("Failed to get repository status: {}", e))
39        })?;
40        
41        let mut has_staged_changes = false;
42        let mut has_unstaged_changes = false;
43        
44        for status_entry in statuses.iter() {
45            let flags = status_entry.status();
46            
47            if flags.intersects(
48                Status::INDEX_NEW | Status::INDEX_MODIFIED | Status::INDEX_DELETED | Status::INDEX_RENAMED | Status::INDEX_TYPECHANGE
49            ) {
50                has_staged_changes = true;
51            }
52            
53            if flags.intersects(
54                Status::WT_MODIFIED | Status::WT_DELETED | Status::WT_TYPECHANGE | Status::WT_RENAMED | Status::WT_NEW
55            ) {
56                has_unstaged_changes = true;
57            }
58        }
59        
60        // ワーキングツリーのステータスを決定
61        let working_tree_status = if has_staged_changes || has_unstaged_changes {
62            WorktreeStatus::Dirty
63        } else {
64            WorktreeStatus::Clean
65        };
66        
67        // 最終コミット時刻を取得
68        let last_commit_time = Self::get_last_commit_time(repo);
69        
70        // 今後の実装: Ahead/Behind の計算
71        let ahead_count = 0;
72        let behind_count = 0;
73        
74        Ok(GitStatus {
75            working_tree_status,
76            has_staged_changes,
77            has_unstaged_changes,
78            last_commit_time,
79            ahead_count,
80            behind_count,
81        })
82    }
83    
84    fn get_last_commit_time(repo: &Repository) -> Option<i64> {
85        // HEADコミットの時刻を取得
86        repo.head().ok()
87            .and_then(|reference| reference.target())
88            .and_then(|oid| repo.find_commit(oid).ok())
89            .map(|commit| commit.time().seconds())
90    }
91}