1
1
import { JupyterFrontEnd } from '@jupyterlab/application' ;
2
2
import { IChangedArgs , PathExt } from '@jupyterlab/coreutils' ;
3
+ import { IDocumentManager } from '@jupyterlab/docmanager' ;
3
4
import { ServerConnection } from '@jupyterlab/services' ;
4
5
import { ISettingRegistry } from '@jupyterlab/settingregistry' ;
5
6
import { LinkedList } from '@lumino/collections' ;
@@ -28,11 +29,13 @@ export class GitExtension implements IGitExtension {
28
29
constructor (
29
30
serverRoot : string ,
30
31
app : JupyterFrontEnd = null ,
32
+ docmanager : IDocumentManager = null ,
31
33
settings ?: ISettingRegistry . ISettings
32
34
) {
33
35
const self = this ;
34
36
this . _serverRoot = serverRoot ;
35
37
this . _app = app ;
38
+ this . _docmanager = docmanager ;
36
39
this . _settings = settings || null ;
37
40
38
41
let interval : number ;
@@ -459,6 +462,20 @@ export class GitExtension implements IGitExtension {
459
462
const tid = this . _addTask ( 'git:checkout' ) ;
460
463
try {
461
464
response = await httpGitRequest ( '/git/checkout' , 'POST' , body ) ;
465
+
466
+ if ( response . ok ) {
467
+ if ( body . checkout_branch ) {
468
+ const files = ( await this . changedFiles (
469
+ this . _currentBranch . name ,
470
+ body . branchname
471
+ ) ) [ 'files' ] ;
472
+ if ( files ) {
473
+ files . forEach ( file => this . _revertFile ( file ) ) ;
474
+ }
475
+ } else {
476
+ this . _revertFile ( options . filename ) ;
477
+ }
478
+ }
462
479
} catch ( err ) {
463
480
throw new ServerConnection . NetworkError ( err ) ;
464
481
} finally {
@@ -468,6 +485,7 @@ export class GitExtension implements IGitExtension {
468
485
if ( ! response . ok ) {
469
486
throw new ServerConnection . ResponseError ( response , data . message ) ;
470
487
}
488
+
471
489
if ( body . checkout_branch ) {
472
490
await this . refreshBranch ( ) ;
473
491
this . _headChanged . emit ( ) ;
@@ -609,11 +627,17 @@ export class GitExtension implements IGitExtension {
609
627
return Promise . resolve ( new Response ( JSON . stringify ( response ) ) ) ;
610
628
}
611
629
const tid = this . _addTask ( 'git:commit:revert' ) ;
630
+ const files = ( await this . changedFiles ( null , null , hash + '^!' ) ) [ 'files' ] ;
612
631
try {
613
632
response = await httpGitRequest ( '/git/delete_commit' , 'POST' , {
614
633
commit_id : hash ,
615
634
top_repo_path : path
616
635
} ) ;
636
+ if ( response . ok && files ) {
637
+ files . forEach ( file => {
638
+ this . _revertFile ( file ) ;
639
+ } ) ;
640
+ }
617
641
} catch ( err ) {
618
642
throw new ServerConnection . NetworkError ( err ) ;
619
643
} finally {
@@ -905,12 +929,29 @@ export class GitExtension implements IGitExtension {
905
929
return Promise . resolve ( new Response ( JSON . stringify ( response ) ) ) ;
906
930
}
907
931
const tid = this . _addTask ( 'git:reset:changes' ) ;
932
+ const reset_all = filename === undefined ;
933
+ let files ;
934
+ if ( reset_all ) {
935
+ files = ( await this . changedFiles ( 'INDEX' , 'HEAD' ) ) [ 'files' ] ;
936
+ }
908
937
try {
909
938
response = await httpGitRequest ( '/git/reset' , 'POST' , {
910
939
reset_all : filename === undefined ,
911
940
filename : filename === undefined ? null : filename ,
912
941
top_repo_path : path
913
942
} ) ;
943
+
944
+ if ( response . ok ) {
945
+ if ( reset_all ) {
946
+ if ( files ) {
947
+ files . forEach ( file => {
948
+ this . _revertFile ( file ) ;
949
+ } ) ;
950
+ }
951
+ } else {
952
+ this . _revertFile ( filename ) ;
953
+ }
954
+ }
914
955
} catch ( err ) {
915
956
throw new ServerConnection . NetworkError ( err ) ;
916
957
} finally {
@@ -947,12 +988,20 @@ export class GitExtension implements IGitExtension {
947
988
} ;
948
989
return Promise . resolve ( new Response ( JSON . stringify ( response ) ) ) ;
949
990
}
991
+ const files = ( await this . changedFiles ( null , null , hash ) ) [ 'files' ] ;
950
992
const tid = this . _addTask ( 'git:reset:hard' ) ;
951
993
try {
952
994
response = await httpGitRequest ( '/git/reset_to_commit' , 'POST' , {
953
995
commit_id : hash ,
954
996
top_repo_path : path
955
997
} ) ;
998
+ if ( response . ok ) {
999
+ if ( files ) {
1000
+ files . forEach ( file => {
1001
+ this . _revertFile ( file ) ;
1002
+ } ) ;
1003
+ }
1004
+ }
956
1005
} catch ( err ) {
957
1006
throw new ServerConnection . NetworkError ( err ) ;
958
1007
} finally {
@@ -1226,6 +1275,37 @@ export class GitExtension implements IGitExtension {
1226
1275
return Promise . resolve ( response ) ;
1227
1276
}
1228
1277
1278
+ /**
1279
+ * Get list of files changed between two commits or two branches
1280
+ * @param base id of base commit or base branch for comparison
1281
+ * @param remote id of remote commit or remote branch for comparison
1282
+ * @param singleCommit id of a single commit
1283
+ *
1284
+ * @returns the names of the changed files
1285
+ */
1286
+ async changedFiles (
1287
+ base ?: string ,
1288
+ remote ?: string ,
1289
+ singleCommit ?: string
1290
+ ) : Promise < Git . IChangedFilesResult > {
1291
+ try {
1292
+ const response = await httpGitRequest ( '/git/changed_files' , 'POST' , {
1293
+ current_path : this . pathRepository ,
1294
+ base : base ,
1295
+ remote : remote ,
1296
+ single_commit : singleCommit
1297
+ } ) ;
1298
+ if ( ! response . ok ) {
1299
+ return response . json ( ) . then ( ( data : any ) => {
1300
+ throw new ServerConnection . ResponseError ( response , data . message ) ;
1301
+ } ) ;
1302
+ }
1303
+ return response . json ( ) ;
1304
+ } catch ( err ) {
1305
+ throw new ServerConnection . NetworkError ( err ) ;
1306
+ }
1307
+ }
1308
+
1229
1309
/**
1230
1310
* Make request for a list of all git branches in the repository
1231
1311
* Retrieve a list of repository branches.
@@ -1344,12 +1424,26 @@ export class GitExtension implements IGitExtension {
1344
1424
return this . _taskID ;
1345
1425
}
1346
1426
1427
+ /**
1428
+ * if file is open in JupyterLab find the widget and ensure the JupyterLab
1429
+ * version matches the version on disk. Do nothing if the file has unsaved changes
1430
+ *
1431
+ * @param path path to the file to be reverted
1432
+ */
1433
+ private _revertFile ( path : string ) : void {
1434
+ const widget = this . _docmanager . findWidget ( this . getRelativeFilePath ( path ) ) ;
1435
+ if ( widget && ! widget . context . model . dirty ) {
1436
+ widget . context . revert ( ) ;
1437
+ }
1438
+ }
1439
+
1347
1440
private _status : Git . IStatusFile [ ] = [ ] ;
1348
1441
private _pathRepository : string | null = null ;
1349
1442
private _branches : Git . IBranch [ ] ;
1350
1443
private _currentBranch : Git . IBranch ;
1351
1444
private _serverRoot : string ;
1352
1445
private _app : JupyterFrontEnd | null ;
1446
+ private _docmanager : IDocumentManager | null ;
1353
1447
private _diffProviders : { [ key : string ] : Git . IDiffCallback } = { } ;
1354
1448
private _isDisposed = false ;
1355
1449
private _markerCache : Markers = new Markers ( ( ) => this . _markChanged . emit ( ) ) ;
0 commit comments