@@ -5,13 +5,14 @@ use std::os::windows::process::CommandExt;
55use  std:: { io:: Write ,  path:: Path ,  process:: Stdio ,  str} ; 
66
77use  anyhow:: { anyhow,  bail,  Context ,  Result } ; 
8- use  bstr:: BString ; 
8+ use  bstr:: { BString ,   ByteSlice } ; 
99use  git2:: { BlameOptions ,  Tree } ; 
1010use  gitbutler_branch:: { gix_to_git2_signature,  SignaturePurpose } ; 
1111use  gitbutler_commit:: { commit_buffer:: CommitBuffer ,  commit_headers:: CommitHeadersV2 } ; 
1212use  gitbutler_config:: git:: { GbConfig ,  GitConfig } ; 
1313use  gitbutler_error:: error:: Code ; 
1414use  gitbutler_reference:: { Refname ,  RemoteRefname } ; 
15+ use  gix:: status:: plumbing:: index_as_worktree:: { Change ,  EntryStatus } ; 
1516use  tracing:: instrument; 
1617
1718use  crate :: { Config ,  LogUntil } ; 
@@ -147,14 +148,71 @@ impl RepositoryExt for git2::Repository {
147148        } 
148149    } 
149150
150-     /// Note that this will add all untracked files in the worktree to the index, 
151- /// and write a tree from it. 
152- /// The index won't be stored though. 
151+     /// Note that this will add all untracked and modified files in the worktree to 
152+ /// the object database, and create a tree from it. 
153+ /// 
154+ /// Note that right now, it doesn't skip big files. 
153155#[ instrument( level = tracing:: Level :: DEBUG ,  skip( self ) ,  err( Debug ) ) ]  
154156    fn  create_wd_tree ( & self )  -> Result < Tree >  { 
155-         let  mut  index = self . index ( ) ?; 
156-         index. add_all ( [ "*" ] ,  git2:: IndexAddOption :: DEFAULT ,  None ) ?; 
157-         let  oid = index. write_tree ( ) ?; 
157+         let  repo = gix:: open ( self . path ( ) ) ?; 
158+         let  workdir = repo. work_dir ( ) . context ( "Need non-bare repository" ) ?; 
159+         let  mut  head_tree = repo. edit_tree ( repo. head_tree_id ( ) ?) ?; 
160+         let  status_changes = repo
161+             . status ( gix:: progress:: Discard ) ?
162+             . index_worktree_rewrites ( None ) 
163+             . index_worktree_submodules ( None ) 
164+             . into_index_worktree_iter ( None :: < BString > ) ?; 
165+         for  change in  status_changes { 
166+             let  change = change?; 
167+             match  change { 
168+                 // modified or tracked files are unconditionally added as blob. 
169+                 gix:: status:: index_worktree:: iter:: Item :: Modification  { 
170+                     rela_path, 
171+                     status :  EntryStatus :: Change ( Change :: Type  | Change :: Modification  {  .. } ) , 
172+                     ..
173+                 } 
174+                 | gix:: status:: index_worktree:: iter:: Item :: DirectoryContents  { 
175+                     entry :  gix:: dir:: Entry  {  rela_path,  .. } , 
176+                     ..
177+                 }  => { 
178+                     let  path = workdir. join ( gix:: path:: from_bstr ( & rela_path) ) ; 
179+                     let  Ok ( md)  = std:: fs:: symlink_metadata ( & path)  else  { 
180+                         continue ; 
181+                     } ; 
182+                     let  ( id,  kind)  = if  md. is_symlink ( )  { 
183+                         let  target = std:: fs:: read_link ( & path) . with_context ( || { 
184+                             format ! ( 
185+                                 "Failed to read link at '{}' for adding to the object database" , 
186+                                 path. display( ) 
187+                             ) 
188+                         } ) ?; 
189+                         let  id = repo. write_blob ( gix:: path:: into_bstr ( target) . as_bytes ( ) ) ?; 
190+                         ( id,  gix:: object:: tree:: EntryKind :: Link ) 
191+                     }  else  { 
192+                         let  mut  file = std:: fs:: File :: open ( & path) . with_context ( || { 
193+                             format ! ( 
194+                                 "Could not open file at '{}' for adding it to the object database" , 
195+                                 path. display( ) 
196+                             ) 
197+                         } ) ?; 
198+                         let  kind = if  gix:: fs:: is_executable ( & md)  { 
199+                             gix:: object:: tree:: EntryKind :: BlobExecutable 
200+                         }  else  { 
201+                             gix:: object:: tree:: EntryKind :: Blob 
202+                         } ; 
203+                         ( repo. write_blob_stream ( & mut  file) ?,  kind) 
204+                     } ; 
205+ 
206+                     head_tree. upsert ( rela_path,  kind,  id) ?; 
207+                 } 
208+                 gix:: status:: index_worktree:: iter:: Item :: Rewrite  {  .. }  => { 
209+                     unreachable ! ( "disabled" ) 
210+                 } 
211+                 _ => { } 
212+             } 
213+         } 
214+ 
215+         let  oid = git2:: Oid :: from_bytes ( head_tree. write ( ) ?. as_bytes ( ) ) ?; 
158216        self . find_tree ( oid) . map ( Into :: into) . map_err ( Into :: into) 
159217    } 
160218
0 commit comments