@@ -115,111 +115,80 @@ fn read_git_object(object_path: &Path) -> Result<Vec<u8>> {
115115 Ok ( content)
116116}
117117
118- /// Import Git commits into MUG database
118+ /// Import Git commits into MUG database (supports pack files)
119119fn import_git_commits ( git_path : & Path , mug_repo : & Repository ) -> Result < ( ) > {
120120 use chrono:: Utc ;
121121
122- let objects_dir = git_path. join ( ".git/objects" ) ;
123- let mut imported_commits = std:: collections:: HashSet :: new ( ) ;
124-
125- // First: collect all branch tip commits from refs
126- let refs_heads = git_path. join ( ".git/refs/heads" ) ;
127- let mut ref_commits = Vec :: new ( ) ;
128-
129- if refs_heads. exists ( ) {
130- if let Ok ( entries) = fs:: read_dir ( & refs_heads) {
131- for entry in entries. flatten ( ) {
132- if let Ok ( hash) = fs:: read_to_string ( entry. path ( ) ) {
133- ref_commits. push ( hash. trim ( ) . to_string ( ) ) ;
134- }
135- }
136- }
137- }
122+ // Use git2 to open repo - handles pack files automatically
123+ let git_repo = git2:: Repository :: open ( git_path)
124+ . map_err ( |e| crate :: core:: error:: Error :: Custom ( format ! ( "Failed to open git repo: {}" , e) ) ) ?;
138125
139- // Try to import commits from objects directory first
140- if objects_dir. exists ( ) {
141- if let Ok ( entries) = fs:: read_dir ( & objects_dir) {
142- for entry in entries. flatten ( ) {
143- let path = entry. path ( ) ;
144-
145- // Skip pack directory
146- if path. file_name ( ) . map_or ( false , |n| n == "pack" ) {
147- continue ;
148- }
149-
150- if path. is_dir ( ) {
151- if let Ok ( subentries) = fs:: read_dir ( & path) {
152- for obj_entry in subentries. flatten ( ) {
153- let obj_path = obj_entry. path ( ) ;
154-
155- // Reconstruct commit hash (dir_name + file_name)
156- if let ( Some ( dir_name) , Some ( file_name) ) = ( path. file_name ( ) , obj_path. file_name ( ) ) {
157- if let ( Some ( dir_str) , Some ( file_str) ) = ( dir_name. to_str ( ) , file_name. to_str ( ) ) {
158- let commit_hash = format ! ( "{}{}" , dir_str, file_str) ;
159-
160- // Try to read and parse the object
161- if let Ok ( content) = read_git_object ( & obj_path) {
162- // Git object format: "commit <size>\0<content>"
163- if content. starts_with ( b"commit " ) {
164- if let Some ( null_pos) = content. iter ( ) . position ( |& b| b == 0 ) {
165- let object_content = & content[ null_pos + 1 ..] ;
166-
167- if let Ok ( ( tree_hash, message, parent, author) ) = parse_git_commit ( object_content) {
168- let commit_json = if let Some ( parent_hash) = parent {
169- serde_json:: json!( {
170- "id" : commit_hash,
171- "tree_hash" : tree_hash,
172- "parent" : parent_hash,
173- "author" : if author. is_empty( ) { "Unknown" } else { & author } ,
174- "message" : if message. is_empty( ) { "No message" } else { & message } ,
175- "timestamp" : Utc :: now( ) . to_rfc3339( ) ,
176- } )
177- } else {
178- serde_json:: json!( {
179- "id" : commit_hash,
180- "tree_hash" : tree_hash,
181- "parent" : serde_json:: Value :: Null ,
182- "author" : if author. is_empty( ) { "Unknown" } else { & author } ,
183- "message" : if message. is_empty( ) { "No message" } else { & message } ,
184- "timestamp" : Utc :: now( ) . to_rfc3339( ) ,
185- } )
186- } ;
187-
188- if let Ok ( serialized) = serde_json:: to_vec ( & commit_json) {
189- let _ = mug_repo. get_db ( ) . set ( "COMMITS" , commit_hash. as_bytes ( ) , & serialized) ;
190- imported_commits. insert ( commit_hash. clone ( ) ) ;
191- }
192- }
193- }
194- }
195- }
196- }
197- }
198- }
199- }
126+ let mut revwalk = git_repo. revwalk ( )
127+ . map_err ( |e| crate :: core:: error:: Error :: Custom ( format ! ( "Failed to walk commits: {}" , e) ) ) ?;
128+
129+ revwalk. push_head ( )
130+ . map_err ( |e| crate :: core:: error:: Error :: Custom ( format ! ( "Failed to add HEAD: {}" , e) ) ) ?;
131+
132+ let mut count = 0 ;
133+ for oid_result in revwalk {
134+ let oid = oid_result
135+ . map_err ( |e| crate :: core:: error:: Error :: Custom ( format ! ( "OID error: {}" , e) ) ) ?;
136+
137+ match git_repo. find_commit ( oid) {
138+ Ok ( commit) => {
139+ let commit_hash = oid. to_string ( ) ;
140+ let tree_hash = commit. tree ( )
141+ . map ( |t| t. id ( ) . to_string ( ) )
142+ . unwrap_or_else ( |_| "0000000000000000000000000000000000000000" . to_string ( ) ) ;
143+
144+ let author = commit. author ( ) ;
145+ let author_str = format ! ( "{}" , author. name( ) . unwrap_or( "Unknown" ) ) ;
146+
147+ let message = commit. message ( )
148+ . unwrap_or ( "(no message)" )
149+ . trim ( )
150+ . to_string ( ) ;
151+
152+ let parent = if commit. parent_count ( ) > 0 {
153+ Some ( commit. parent ( 0 )
154+ . map ( |p| p. id ( ) . to_string ( ) )
155+ . ok ( ) )
156+ } else {
157+ None
158+ } . flatten ( ) ;
159+
160+ let commit_json = if let Some ( parent_hash) = parent {
161+ serde_json:: json!( {
162+ "id" : commit_hash,
163+ "tree_hash" : tree_hash,
164+ "parent" : parent_hash,
165+ "author" : author_str,
166+ "message" : message,
167+ "timestamp" : Utc :: now( ) . to_rfc3339( ) ,
168+ } )
169+ } else {
170+ serde_json:: json!( {
171+ "id" : commit_hash,
172+ "tree_hash" : tree_hash,
173+ "parent" : serde_json:: Value :: Null ,
174+ "author" : author_str,
175+ "message" : message,
176+ "timestamp" : Utc :: now( ) . to_rfc3339( ) ,
177+ } )
178+ } ;
179+
180+ if let Ok ( serialized) = serde_json:: to_vec ( & commit_json) {
181+ let _ = mug_repo. get_db ( ) . set ( "COMMITS" , commit_hash. as_bytes ( ) , & serialized) ;
182+ count += 1 ;
200183 }
201184 }
202- }
203- }
204-
205- // Fallback: create stub commits for refs that weren't found in objects
206- for ref_commit in ref_commits {
207- if !imported_commits. contains ( & ref_commit) {
208- let commit_json = serde_json:: json!( {
209- "id" : ref_commit,
210- "tree_hash" : "0000000000000000000000000000000000000000" ,
211- "parent" : serde_json:: Value :: Null ,
212- "author" : "Unknown (from Git ref)" ,
213- "message" : "Imported from Git (full content unavailable)" ,
214- "timestamp" : Utc :: now( ) . to_rfc3339( ) ,
215- } ) ;
216-
217- if let Ok ( serialized) = serde_json:: to_vec ( & commit_json) {
218- let _ = mug_repo. get_db ( ) . set ( "COMMITS" , ref_commit. as_bytes ( ) , & serialized) ;
185+ Err ( e) => {
186+ eprintln ! ( "[WARN] Failed to read commit {}: {}" , oid, e) ;
219187 }
220188 }
221189 }
222190
191+ eprintln ! ( "[INFO] Imported {} commits from git" , count) ;
223192 Ok ( ( ) )
224193}
225194
0 commit comments