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