@@ -115,3 +115,84 @@ pub(crate) fn show_oplog(repo_path: &Path, json: bool, since: Option<&str>) -> a
115
115
116
116
Ok ( ( ) )
117
117
}
118
+
119
+ pub ( crate ) fn restore_to_oplog (
120
+ repo_path : & Path ,
121
+ _json : bool ,
122
+ oplog_sha : & str ,
123
+ ) -> anyhow:: Result < ( ) > {
124
+ let project = Project :: find_by_path ( repo_path) ?;
125
+
126
+ // Parse the oplog SHA (support partial SHAs)
127
+ let commit_sha_string = if oplog_sha. len ( ) >= 7 {
128
+ // Try to find a snapshot that starts with this SHA
129
+ let snapshots = but_api:: undo:: list_snapshots ( project. id , 100 , None , None ) ?;
130
+
131
+ let matching_snapshot = snapshots
132
+ . iter ( )
133
+ . find ( |snapshot| snapshot. commit_id . to_string ( ) . starts_with ( oplog_sha) )
134
+ . ok_or_else ( || anyhow:: anyhow!( "No oplog snapshot found matching '{}'" , oplog_sha) ) ?;
135
+
136
+ matching_snapshot. commit_id . to_string ( )
137
+ } else {
138
+ anyhow:: bail!( "Oplog SHA must be at least 7 characters long" ) ;
139
+ } ;
140
+
141
+ // Get information about the target snapshot
142
+ let snapshots = but_api:: undo:: list_snapshots ( project. id , 100 , None , None ) ?;
143
+ let target_snapshot = snapshots
144
+ . iter ( )
145
+ . find ( |snapshot| snapshot. commit_id . to_string ( ) == commit_sha_string)
146
+ . ok_or_else ( || anyhow:: anyhow!( "Snapshot {} not found in oplog" , commit_sha_string) ) ?;
147
+
148
+ let target_operation = target_snapshot
149
+ . details
150
+ . as_ref ( )
151
+ . map ( |d| d. title . as_str ( ) )
152
+ . unwrap_or ( "Unknown operation" ) ;
153
+
154
+ let target_time = chrono:: DateTime :: from_timestamp ( target_snapshot. created_at . seconds ( ) , 0 )
155
+ . ok_or ( anyhow:: anyhow!( "Could not parse timestamp" ) ) ?
156
+ . format ( "%Y-%m-%d %H:%M:%S" )
157
+ . to_string ( ) ;
158
+
159
+ println ! ( "{}" , "Restoring to oplog snapshot..." . blue( ) . bold( ) ) ;
160
+ println ! (
161
+ " Target: {} ({})" ,
162
+ target_operation. green( ) ,
163
+ target_time. dimmed( )
164
+ ) ;
165
+ println ! ( " Snapshot: {}" , commit_sha_string[ ..7 ] . cyan( ) . underline( ) ) ;
166
+
167
+ // Confirm the restoration (safety check)
168
+ println ! (
169
+ "\n {}" ,
170
+ "⚠️ This will overwrite your current workspace state."
171
+ . yellow( )
172
+ . bold( )
173
+ ) ;
174
+ print ! ( "Continue with restore? [y/N]: " ) ;
175
+ use std:: io:: { self , Write } ;
176
+ io:: stdout ( ) . flush ( ) ?;
177
+
178
+ let mut input = String :: new ( ) ;
179
+ io:: stdin ( ) . read_line ( & mut input) ?;
180
+
181
+ let input = input. trim ( ) . to_lowercase ( ) ;
182
+ if input != "y" && input != "yes" {
183
+ println ! ( "{}" , "Restore cancelled." . yellow( ) ) ;
184
+ return Ok ( ( ) ) ;
185
+ }
186
+
187
+ // Restore to the target snapshot using the but-api crate
188
+ but_api:: undo:: restore_snapshot ( project. id , commit_sha_string) ?;
189
+
190
+ println ! ( "\n {} Restore completed successfully!" , "✓" . green( ) . bold( ) , ) ;
191
+
192
+ println ! (
193
+ "{}" ,
194
+ "\n Workspace has been restored to the selected snapshot." . green( )
195
+ ) ;
196
+
197
+ Ok ( ( ) )
198
+ }
0 commit comments