@@ -102,7 +102,14 @@ pub trait RepoCommands {
102102 fn get_local_config ( & self , key : & str ) -> Result < Option < String > > ;
103103 fn set_local_config ( & self , key : & str , value : & str ) -> Result < ( ) > ;
104104 fn check_signing_settings ( & self ) -> Result < bool > ;
105- /// Read `probably_relative_path` in the following order:
105+
106+ /// Read `path` from the tree of the given commit.
107+ ///
108+ /// Bails when given an absolute path since that would suggest we are looking for a file in
109+ /// the workspace. Returns `FileInfo::default()` if file could not be found.
110+ fn read_file_from_commit ( & self , commit_id : Oid , path : & Path ) -> Result < FileInfo > ;
111+
112+ /// Read `path` in the following order:
106113 ///
107114 /// * worktree
108115 /// * index
@@ -111,16 +118,8 @@ pub trait RepoCommands {
111118 /// This order makes sense if you imagine that deleted files are shown, like in a `git status`,
112119 /// so we want to know what's deleted.
113120 ///
114- /// If `probably_relative_path` is absolute, we will assure it's in the worktree.
115- /// If `treeish` is given, it will only be read from the given tree.
116- ///
117- /// If nothing could be found at `probably_relative_path`, the returned structure indicates this,
118- /// but it's no error.
119- fn read_file_from_workspace (
120- & self ,
121- treeish : Option < Oid > ,
122- probably_relative_path : & Path ,
123- ) -> Result < FileInfo > ;
121+ /// Returns `FileInfo::default()` if file could not be found.
122+ fn read_file_from_workspace ( & self , path : & Path ) -> Result < FileInfo > ;
124123}
125124
126125impl RepoCommands for Project {
@@ -182,23 +181,32 @@ impl RepoCommands for Project {
182181 Ok ( ( ) )
183182 }
184183
185- fn read_file_from_workspace (
186- & self ,
187- treeish : Option < Oid > ,
188- probably_relative_path : & Path ,
189- ) -> Result < FileInfo > {
184+ fn read_file_from_commit ( & self , commit_id : Oid , relative_path : & Path ) -> Result < FileInfo > {
185+ if !relative_path. is_relative ( ) {
186+ bail ! (
187+ "Refusing to read '{:?}' from commit {:?} as it's not relative to the worktree" ,
188+ relative_path,
189+ commit_id
190+ ) ;
191+ }
192+
190193 let ctx = CommandContext :: open ( self ) ?;
191194 let repo = ctx. repo ( ) ;
195+ let tree = repo. find_commit ( commit_id) ?. tree ( ) ?;
192196
193- if let Some ( treeish) = treeish {
194- if !probably_relative_path. is_relative ( ) {
195- bail ! (
196- "Refusing to read '{}' from tree as it's not relative to the worktree" ,
197- probably_relative_path. display( ) ,
198- ) ;
197+ Ok ( match tree. get_path ( relative_path) {
198+ Ok ( entry) => {
199+ let blob = repo. find_blob ( entry. id ( ) ) ?;
200+ FileInfo :: from_content ( relative_path, blob. content ( ) )
199201 }
200- return read_file_from_tree ( repo, Some ( treeish) , probably_relative_path) ;
201- }
202+ Err ( e) if e. code ( ) == git2:: ErrorCode :: NotFound => FileInfo :: deleted ( ) ,
203+ Err ( e) => return Err ( e. into ( ) ) ,
204+ } )
205+ }
206+
207+ fn read_file_from_workspace ( & self , probably_relative_path : & Path ) -> Result < FileInfo > {
208+ let ctx = CommandContext :: open ( self ) ?;
209+ let repo = ctx. repo ( ) ;
202210
203211 let ( path_in_worktree, relative_path) = if probably_relative_path. is_relative ( ) {
204212 (
@@ -234,34 +242,20 @@ impl RepoCommands for Project {
234242 }
235243 Err ( err) if err. kind ( ) == std:: io:: ErrorKind :: NotFound => {
236244 match repo. index ( ) ?. get_path ( & relative_path, 0 ) {
245+ // Read file that has been deleted and not staged for commit.
237246 Some ( entry) => {
238247 let blob = repo. find_blob ( entry. id ) ?;
239248 FileInfo :: from_content ( & relative_path, blob. content ( ) )
240249 }
241- None => read_file_from_tree ( repo, None , & relative_path) ?,
250+ // Read file that has been deleted and staged for commit. Note that file not
251+ // found returns FileInfo::default() rather than an error.
252+ None => self . read_file_from_commit (
253+ repo. head ( ) ?. peel_to_commit ( ) ?. id ( ) ,
254+ & relative_path,
255+ ) ?,
242256 }
243257 }
244258 Err ( err) => return Err ( err. into ( ) ) ,
245259 } )
246260 }
247261}
248-
249- fn read_file_from_tree (
250- repo : & git2:: Repository ,
251- treeish : Option < Oid > ,
252- relative_path : & Path ,
253- ) -> Result < FileInfo > {
254- let tree = if let Some ( id) = treeish {
255- repo. find_object ( id, None ) ?. peel_to_tree ( ) ?
256- } else {
257- repo. head ( ) ?. peel_to_tree ( ) ?
258- } ;
259- Ok ( match tree. get_path ( relative_path) {
260- Ok ( entry) => {
261- let blob = repo. find_blob ( entry. id ( ) ) ?;
262- FileInfo :: from_content ( relative_path, blob. content ( ) )
263- }
264- Err ( e) if e. code ( ) == git2:: ErrorCode :: NotFound => FileInfo :: deleted ( ) ,
265- Err ( e) => return Err ( e. into ( ) ) ,
266- } )
267- }
0 commit comments