1# -*- coding: utf-8 -*-
2
3# Copyright (c) 2014 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4#
5
6"""
7Module implementing the VCS project browser helper for Git.
8"""
9
10import os
11
12from PyQt5.QtWidgets import QMenu, QDialog
13
14from E5Gui.E5Application import e5App
15
16from Project.ProjectBrowserModel import ProjectBrowserFileItem
17
18from VCS.ProjectBrowserHelper import VcsProjectBrowserHelper
19
20import UI.PixmapCache
21
22
23class GitProjectBrowserHelper(VcsProjectBrowserHelper):
24    """
25    Class implementing the VCS project browser helper for Git.
26    """
27    def __init__(self, vcsObject, browserObject, projectObject,
28                 isTranslationsBrowser, parent=None, name=None):
29        """
30        Constructor
31
32        @param vcsObject reference to the vcs object
33        @param browserObject reference to the project browser object
34        @param projectObject reference to the project object
35        @param isTranslationsBrowser flag indicating, the helper is requested
36            for the translations browser (this needs some special treatment)
37        @param parent parent widget (QWidget)
38        @param name name of this object (string)
39        """
40        VcsProjectBrowserHelper.__init__(self, vcsObject, browserObject,
41                                         projectObject, isTranslationsBrowser,
42                                         parent, name)
43
44    def showContextMenu(self, menu, standardItems):
45        """
46        Public slot called before the context menu is shown.
47
48        It enables/disables the VCS menu entries depending on the overall
49        VCS status and the file status.
50
51        @param menu reference to the menu to be shown
52        @param standardItems array of standard items that need
53            activation/deactivation depending on the overall VCS status
54        """
55        if self.browser.currentItem().data(1) == self.vcs.vcsName():
56            for act in self.vcsMenuActions:
57                act.setEnabled(True)
58            for act in standardItems:
59                act.setEnabled(False)
60        else:
61            for act in self.vcsMenuActions:
62                act.setEnabled(False)
63            for act in standardItems:
64                act.setEnabled(True)
65
66    def showContextMenuMulti(self, menu, standardItems):
67        """
68        Public slot called before the context menu (multiple selections) is
69        shown.
70
71        It enables/disables the VCS menu entries depending on the overall
72        VCS status and the files status.
73
74        @param menu reference to the menu to be shown
75        @param standardItems array of standard items that need
76            activation/deactivation depending on the overall VCS status
77        """
78        vcsName = self.vcs.vcsName()
79        items = self.browser.getSelectedItems()
80        vcsItems = 0
81        # determine number of selected items under VCS control
82        for itm in items:
83            if itm.data(1) == vcsName:
84                vcsItems += 1
85
86        if vcsItems > 0:
87            if vcsItems != len(items):
88                for act in self.vcsMultiMenuActions:
89                    act.setEnabled(False)
90            else:
91                for act in self.vcsMultiMenuActions:
92                    act.setEnabled(True)
93            for act in standardItems:
94                act.setEnabled(False)
95        else:
96            for act in self.vcsMultiMenuActions:
97                act.setEnabled(False)
98            for act in standardItems:
99                act.setEnabled(True)
100
101    def showContextMenuDir(self, menu, standardItems):
102        """
103        Public slot called before the context menu is shown.
104
105        It enables/disables the VCS menu entries depending on the overall
106        VCS status and the directory status.
107
108        @param menu reference to the menu to be shown
109        @param standardItems array of standard items that need
110            activation/deactivation depending on the overall VCS status
111        """
112        if self.browser.currentItem().data(1) == self.vcs.vcsName():
113            for act in self.vcsDirMenuActions:
114                act.setEnabled(True)
115            for act in standardItems:
116                act.setEnabled(False)
117        else:
118            for act in self.vcsDirMenuActions:
119                act.setEnabled(False)
120            for act in standardItems:
121                act.setEnabled(True)
122
123    def showContextMenuDirMulti(self, menu, standardItems):
124        """
125        Public slot called before the context menu is shown.
126
127        It enables/disables the VCS menu entries depending on the overall
128        VCS status and the directory status.
129
130        @param menu reference to the menu to be shown
131        @param standardItems array of standard items that need
132            activation/deactivation depending on the overall VCS status
133        """
134        vcsName = self.vcs.vcsName()
135        items = self.browser.getSelectedItems()
136        vcsItems = 0
137        # determine number of selected items under VCS control
138        for itm in items:
139            if itm.data(1) == vcsName:
140                vcsItems += 1
141
142        if vcsItems > 0:
143            if vcsItems != len(items):
144                for act in self.vcsDirMultiMenuActions:
145                    act.setEnabled(False)
146            else:
147                for act in self.vcsDirMultiMenuActions:
148                    act.setEnabled(True)
149            for act in standardItems:
150                act.setEnabled(False)
151        else:
152            for act in self.vcsDirMultiMenuActions:
153                act.setEnabled(False)
154            for act in standardItems:
155                act.setEnabled(True)
156
157    ###########################################################################
158    ## Protected menu generation methods below
159    ###########################################################################
160
161    def _addVCSMenu(self, mainMenu):
162        """
163        Protected method used to add the VCS menu to all project browsers.
164
165        @param mainMenu reference to the menu to be amended
166        """
167        self.vcsMenuActions = []
168        self.vcsAddMenuActions = []
169
170        menu = QMenu(self.tr("Version Control"))
171
172        act = menu.addAction(
173            UI.PixmapCache.getIcon(
174                os.path.join("VcsPlugins", "vcsGit", "icons", "git.svg")),
175            self.vcs.vcsName(), self._VCSInfoDisplay)
176        font = act.font()
177        font.setBold(True)
178        act.setFont(font)
179        menu.addSeparator()
180
181        act = menu.addAction(
182            UI.PixmapCache.getIcon("vcsCommit"),
183            self.tr('Commit changes to repository...'),
184            self._VCSCommit)
185        self.vcsMenuActions.append(act)
186        menu.addSeparator()
187        act = menu.addAction(
188            UI.PixmapCache.getIcon("vcsAdd"),
189            self.tr('Add/Stage to repository'),
190            self._VCSAdd)
191        act = menu.addAction(
192            UI.PixmapCache.getIcon("vcsRevert"),
193            self.tr('Unstage changes'),
194            self.__GitUnstage)
195        self.vcsMenuActions.append(act)
196        menu.addSeparator()
197        act = menu.addAction(
198            UI.PixmapCache.getIcon("vcsRemove"),
199            self.tr('Remove from repository (and disk)'),
200            self._VCSRemove)
201        self.vcsMenuActions.append(act)
202        act = menu.addAction(
203            UI.PixmapCache.getIcon("vcsRemove"),
204            self.tr('Remove from repository only'),
205            self.__GitForget)
206        self.vcsMenuActions.append(act)
207        menu.addSeparator()
208        act = menu.addAction(self.tr('Copy'), self.__GitCopy)
209        self.vcsMenuActions.append(act)
210        act = menu.addAction(self.tr('Move'), self.__GitMove)
211        self.vcsMenuActions.append(act)
212        menu.addSeparator()
213        act = menu.addAction(
214            UI.PixmapCache.getIcon("vcsLog"),
215            self.tr('Show log browser'), self._VCSLogBrowser)
216        self.vcsMenuActions.append(act)
217        menu.addSeparator()
218        act = menu.addAction(
219            UI.PixmapCache.getIcon("vcsStatus"),
220            self.tr('Show status'), self._VCSStatus)
221        self.vcsMenuActions.append(act)
222        menu.addSeparator()
223        act = menu.addAction(
224            UI.PixmapCache.getIcon("vcsDiff"),
225            self.tr('Show differences'), self._VCSDiff)
226        self.vcsMenuActions.append(act)
227        act = menu.addAction(
228            UI.PixmapCache.getIcon("vcsSbsDiff"),
229            self.tr('Show differences side-by-side'), self.__GitSbsDiff)
230        self.vcsMenuActions.append(act)
231        act = menu.addAction(
232            UI.PixmapCache.getIcon("vcsDiff"),
233            self.tr('Show differences (extended)'),
234            self.__GitExtendedDiff)
235        self.vcsMenuActions.append(act)
236        act = menu.addAction(
237            UI.PixmapCache.getIcon("vcsSbsDiff"),
238            self.tr('Show differences side-by-side (extended)'),
239            self.__GitSbsExtendedDiff)
240        self.vcsMenuActions.append(act)
241        menu.addSeparator()
242        self.annotateAct = menu.addAction(
243            self.tr('Show annotated file'),
244            self.__GitBlame)
245        self.vcsMenuActions.append(self.annotateAct)
246        menu.addSeparator()
247        act = menu.addAction(
248            UI.PixmapCache.getIcon("vcsRevert"),
249            self.tr('Revert changes'), self.__GitRevert)
250        self.vcsMenuActions.append(act)
251        menu.addSeparator()
252        menu.addAction(self.tr('Select all local file entries'),
253                       self.browser.selectLocalEntries)
254        menu.addAction(self.tr('Select all versioned file entries'),
255                       self.browser.selectVCSEntries)
256        menu.addAction(self.tr('Select all local directory entries'),
257                       self.browser.selectLocalDirEntries)
258        menu.addAction(self.tr('Select all versioned directory entries'),
259                       self.browser.selectVCSDirEntries)
260        menu.addSeparator()
261        menu.addAction(self.tr("Configure..."), self.__GitConfigure)
262
263        mainMenu.addSeparator()
264        mainMenu.addMenu(menu)
265        self.menu = menu
266
267    def _addVCSMenuMulti(self, mainMenu):
268        """
269        Protected method used to add the VCS menu for multi selection to all
270        project browsers.
271
272        @param mainMenu reference to the menu to be amended
273        """
274        self.vcsMultiMenuActions = []
275
276        menu = QMenu(self.tr("Version Control"))
277
278        act = menu.addAction(
279            UI.PixmapCache.getIcon(
280                os.path.join("VcsPlugins", "vcsGit", "icons", "git.svg")),
281            self.vcs.vcsName(), self._VCSInfoDisplay)
282        font = act.font()
283        font.setBold(True)
284        act.setFont(font)
285        menu.addSeparator()
286
287        act = menu.addAction(
288            UI.PixmapCache.getIcon("vcsCommit"),
289            self.tr('Commit changes to repository...'),
290            self._VCSCommit)
291        self.vcsMultiMenuActions.append(act)
292        menu.addSeparator()
293        act = menu.addAction(
294            UI.PixmapCache.getIcon("vcsAdd"),
295            self.tr('Add/Stage to repository'), self._VCSAdd)
296        act = menu.addAction(
297            UI.PixmapCache.getIcon("vcsRevert"),
298            self.tr('Unstage changes'),
299            self.__GitUnstage)
300        self.vcsMultiMenuActions.append(act)
301        menu.addSeparator()
302        act = menu.addAction(
303            UI.PixmapCache.getIcon("vcsRemove"),
304            self.tr('Remove from repository (and disk)'),
305            self._VCSRemove)
306        self.vcsMultiMenuActions.append(act)
307        act = menu.addAction(
308            UI.PixmapCache.getIcon("vcsRemove"),
309            self.tr('Remove from repository only'),
310            self.__GitForget)
311        self.vcsMultiMenuActions.append(act)
312        menu.addSeparator()
313        act = menu.addAction(
314            UI.PixmapCache.getIcon("vcsStatus"),
315            self.tr('Show status'), self._VCSStatus)
316        self.vcsMultiMenuActions.append(act)
317        menu.addSeparator()
318        act = menu.addAction(
319            UI.PixmapCache.getIcon("vcsDiff"),
320            self.tr('Show differences'), self._VCSDiff)
321        self.vcsMultiMenuActions.append(act)
322        act = menu.addAction(
323            UI.PixmapCache.getIcon("vcsDiff"),
324            self.tr('Show differences (extended)'),
325            self.__GitExtendedDiff)
326        self.vcsMultiMenuActions.append(act)
327        menu.addSeparator()
328        act = menu.addAction(
329            UI.PixmapCache.getIcon("vcsRevert"),
330            self.tr('Revert changes'), self.__GitRevert)
331        self.vcsMultiMenuActions.append(act)
332        menu.addSeparator()
333
334        menu.addSeparator()
335        menu.addAction(self.tr('Select all local file entries'),
336                       self.browser.selectLocalEntries)
337        menu.addAction(self.tr('Select all versioned file entries'),
338                       self.browser.selectVCSEntries)
339        menu.addAction(self.tr('Select all local directory entries'),
340                       self.browser.selectLocalDirEntries)
341        menu.addAction(self.tr('Select all versioned directory entries'),
342                       self.browser.selectVCSDirEntries)
343        menu.addSeparator()
344        menu.addAction(self.tr("Configure..."), self.__GitConfigure)
345
346        mainMenu.addSeparator()
347        mainMenu.addMenu(menu)
348        self.menuMulti = menu
349
350    def _addVCSMenuBack(self, mainMenu):
351        """
352        Protected method used to add the VCS menu to all project browsers.
353
354        @param mainMenu reference to the menu to be amended
355        """
356        menu = QMenu(self.tr("Version Control"))
357
358        act = menu.addAction(
359            UI.PixmapCache.getIcon(
360                os.path.join("VcsPlugins", "vcsGit", "icons", "git.svg")),
361            self.vcs.vcsName(), self._VCSInfoDisplay)
362        font = act.font()
363        font.setBold(True)
364        act.setFont(font)
365        menu.addSeparator()
366
367        menu.addAction(self.tr('Select all local file entries'),
368                       self.browser.selectLocalEntries)
369        menu.addAction(self.tr('Select all versioned file entries'),
370                       self.browser.selectVCSEntries)
371        menu.addAction(self.tr('Select all local directory entries'),
372                       self.browser.selectLocalDirEntries)
373        menu.addAction(self.tr('Select all versioned directory entries'),
374                       self.browser.selectVCSDirEntries)
375        menu.addSeparator()
376        menu.addAction(self.tr("Configure..."), self.__GitConfigure)
377
378        mainMenu.addSeparator()
379        mainMenu.addMenu(menu)
380        self.menuBack = menu
381
382    def _addVCSMenuDir(self, mainMenu):
383        """
384        Protected method used to add the VCS menu to all project browsers.
385
386        @param mainMenu reference to the menu to be amended
387        """
388        if mainMenu is None:
389            return
390
391        self.vcsDirMenuActions = []
392        self.vcsAddDirMenuActions = []
393
394        menu = QMenu(self.tr("Version Control"))
395
396        act = menu.addAction(
397            UI.PixmapCache.getIcon(
398                os.path.join("VcsPlugins", "vcsGit", "icons", "git.svg")),
399            self.vcs.vcsName(), self._VCSInfoDisplay)
400        font = act.font()
401        font.setBold(True)
402        act.setFont(font)
403        menu.addSeparator()
404
405        act = menu.addAction(
406            UI.PixmapCache.getIcon("vcsCommit"),
407            self.tr('Commit changes to repository...'),
408            self._VCSCommit)
409        self.vcsDirMenuActions.append(act)
410        menu.addSeparator()
411        act = menu.addAction(
412            UI.PixmapCache.getIcon("vcsAdd"),
413            self.tr('Add/Stage to repository'), self._VCSAdd)
414        act = menu.addAction(
415            UI.PixmapCache.getIcon("vcsRevert"),
416            self.tr('Unstage changes'),
417            self.__GitUnstage)
418        self.vcsDirMenuActions.append(act)
419        menu.addSeparator()
420        act = menu.addAction(
421            UI.PixmapCache.getIcon("vcsRemove"),
422            self.tr('Remove from repository (and disk)'),
423            self._VCSRemove)
424        self.vcsDirMenuActions.append(act)
425        menu.addSeparator()
426        act = menu.addAction(self.tr('Copy'), self.__GitCopy)
427        self.vcsDirMenuActions.append(act)
428        act = menu.addAction(self.tr('Move'), self.__GitMove)
429        self.vcsDirMenuActions.append(act)
430        menu.addSeparator()
431        act = menu.addAction(
432            UI.PixmapCache.getIcon("vcsLog"),
433            self.tr('Show log browser'), self._VCSLogBrowser)
434        self.vcsDirMenuActions.append(act)
435        menu.addSeparator()
436        act = menu.addAction(
437            UI.PixmapCache.getIcon("vcsStatus"),
438            self.tr('Show status'), self._VCSStatus)
439        self.vcsDirMenuActions.append(act)
440        menu.addSeparator()
441        act = menu.addAction(
442            UI.PixmapCache.getIcon("vcsDiff"),
443            self.tr('Show differences'), self._VCSDiff)
444        self.vcsDirMenuActions.append(act)
445        act = menu.addAction(
446            UI.PixmapCache.getIcon("vcsDiff"),
447            self.tr('Show differences (extended)'),
448            self.__GitExtendedDiff)
449        self.vcsDirMenuActions.append(act)
450        menu.addSeparator()
451        act = menu.addAction(
452            UI.PixmapCache.getIcon("vcsRevert"),
453            self.tr('Revert changes'), self.__GitRevert)
454        self.vcsDirMenuActions.append(act)
455        menu.addSeparator()
456
457        menu.addSeparator()
458        menu.addAction(self.tr('Select all local file entries'),
459                       self.browser.selectLocalEntries)
460        menu.addAction(self.tr('Select all versioned file entries'),
461                       self.browser.selectVCSEntries)
462        menu.addAction(self.tr('Select all local directory entries'),
463                       self.browser.selectLocalDirEntries)
464        menu.addAction(self.tr('Select all versioned directory entries'),
465                       self.browser.selectVCSDirEntries)
466        menu.addSeparator()
467        menu.addAction(self.tr("Configure..."), self.__GitConfigure)
468
469        mainMenu.addSeparator()
470        mainMenu.addMenu(menu)
471        self.menuDir = menu
472
473    def _addVCSMenuDirMulti(self, mainMenu):
474        """
475        Protected method used to add the VCS menu to all project browsers.
476
477        @param mainMenu reference to the menu to be amended
478        """
479        if mainMenu is None:
480            return
481
482        self.vcsDirMultiMenuActions = []
483
484        menu = QMenu(self.tr("Version Control"))
485
486        act = menu.addAction(
487            UI.PixmapCache.getIcon(
488                os.path.join("VcsPlugins", "vcsGit", "icons", "git.svg")),
489            self.vcs.vcsName(), self._VCSInfoDisplay)
490        font = act.font()
491        font.setBold(True)
492        act.setFont(font)
493        menu.addSeparator()
494
495        act = menu.addAction(
496            UI.PixmapCache.getIcon("vcsCommit"),
497            self.tr('Commit changes to repository...'),
498            self._VCSCommit)
499        self.vcsDirMultiMenuActions.append(act)
500        menu.addSeparator()
501        act = menu.addAction(
502            UI.PixmapCache.getIcon("vcsAdd"),
503            self.tr('Add/Stage to repository'), self._VCSAdd)
504        act = menu.addAction(
505            UI.PixmapCache.getIcon("vcsRevert"),
506            self.tr('Unstage changes'),
507            self.__GitUnstage)
508        self.vcsDirMultiMenuActions.append(act)
509        menu.addSeparator()
510        act = menu.addAction(
511            UI.PixmapCache.getIcon("vcsRemove"),
512            self.tr('Remove from repository (and disk)'),
513            self._VCSRemove)
514        self.vcsDirMultiMenuActions.append(act)
515        menu.addSeparator()
516        act = menu.addAction(
517            UI.PixmapCache.getIcon("vcsStatus"),
518            self.tr('Show status'), self._VCSStatus)
519        self.vcsDirMultiMenuActions.append(act)
520        menu.addSeparator()
521        act = menu.addAction(
522            UI.PixmapCache.getIcon("vcsDiff"),
523            self.tr('Show differences'), self._VCSDiff)
524        self.vcsDirMultiMenuActions.append(act)
525        act = menu.addAction(
526            UI.PixmapCache.getIcon("vcsDiff"),
527            self.tr('Show differences (extended)'),
528            self.__GitExtendedDiff)
529        self.vcsDirMultiMenuActions.append(act)
530        menu.addSeparator()
531        act = menu.addAction(
532            UI.PixmapCache.getIcon("vcsRevert"),
533            self.tr('Revert changes'), self.__GitRevert)
534        self.vcsDirMultiMenuActions.append(act)
535        menu.addSeparator()
536
537        menu.addSeparator()
538        menu.addAction(self.tr('Select all local file entries'),
539                       self.browser.selectLocalEntries)
540        menu.addAction(self.tr('Select all versioned file entries'),
541                       self.browser.selectVCSEntries)
542        menu.addAction(self.tr('Select all local directory entries'),
543                       self.browser.selectLocalDirEntries)
544        menu.addAction(self.tr('Select all versioned directory entries'),
545                       self.browser.selectVCSDirEntries)
546        menu.addSeparator()
547        menu.addAction(self.tr("Configure..."), self.__GitConfigure)
548
549        mainMenu.addSeparator()
550        mainMenu.addMenu(menu)
551        self.menuDirMulti = menu
552
553    def __GitConfigure(self):
554        """
555        Private method to open the configuration dialog.
556        """
557        e5App().getObject("UserInterface").showPreferences("zzz_gitPage")
558
559    def __GitForget(self):
560        """
561        Private slot called by the context menu to remove the selected file
562        from the Git repository leaving a copy in the project directory.
563        """
564        from UI.DeleteFilesConfirmationDialog import (
565            DeleteFilesConfirmationDialog
566        )
567        if self.isTranslationsBrowser:
568            items = self.browser.getSelectedItems([ProjectBrowserFileItem])
569            names = [itm.fileName() for itm in items]
570
571            dlg = DeleteFilesConfirmationDialog(
572                self.parent(),
573                self.tr("Remove from repository only"),
574                self.tr(
575                    "Do you really want to remove these files"
576                    " from the repository?"),
577                names)
578        else:
579            items = self.browser.getSelectedItems()
580            names = [itm.fileName() for itm in items]
581            files = [self.browser.project.getRelativePath(name)
582                     for name in names]
583
584            dlg = DeleteFilesConfirmationDialog(
585                self.parent(),
586                self.tr("Remove from repository only"),
587                self.tr(
588                    "Do you really want to remove these files"
589                    " from the repository?"),
590                files)
591
592        if dlg.exec() == QDialog.DialogCode.Accepted:
593            self.vcs.vcsRemove(names, stageOnly=True)
594
595        for fn in names:
596            self._updateVCSStatus(fn)
597
598    def __GitCopy(self):
599        """
600        Private slot called by the context menu to copy the selected file.
601        """
602        itm = self.browser.currentItem()
603        try:
604            fn = itm.fileName()
605        except AttributeError:
606            fn = itm.dirName()
607        self.vcs.gitCopy(fn, self.project)
608
609    def __GitMove(self):
610        """
611        Private slot called by the context menu to move the selected file.
612        """
613        itm = self.browser.currentItem()
614        try:
615            fn = itm.fileName()
616        except AttributeError:
617            fn = itm.dirName()
618        isFile = os.path.isfile(fn)
619        movefiles = self.browser.project.getFiles(fn)
620        self.browser.project.stopFileSystemMonitoring()
621        if self.vcs.vcsMove(fn, self.project):
622            if isFile:
623                self.browser.closeSourceWindow.emit(fn)
624            else:
625                for mf in movefiles:
626                    self.browser.closeSourceWindow.emit(mf)
627        self.browser.project.startFileSystemMonitoring()
628
629    def __GitExtendedDiff(self):
630        """
631        Private slot called by the context menu to show the difference of a
632        file to the repository.
633
634        This gives the chance to enter the revisions to compare.
635        """
636        names = []
637        for itm in self.browser.getSelectedItems():
638            try:
639                names.append(itm.fileName())
640            except AttributeError:
641                names.append(itm.dirName())
642        self.vcs.gitExtendedDiff(names)
643
644    def __GitSbsDiff(self):
645        """
646        Private slot called by the context menu to show the difference of a
647        file to the repository side-by-side.
648        """
649        itm = self.browser.currentItem()
650        fn = itm.fileName()
651        self.vcs.gitSbsDiff(fn)
652
653    def __GitSbsExtendedDiff(self):
654        """
655        Private slot called by the context menu to show the difference of a
656        file to the repository side-by-side.
657
658        It allows the selection of revisions to compare.
659        """
660        itm = self.browser.currentItem()
661        fn = itm.fileName()
662        self.vcs.gitSbsDiff(fn, extended=True)
663
664    def __GitUnstage(self):
665        """
666        Private slot to unstage changes.
667        """
668        names = []
669        for itm in self.browser.getSelectedItems():
670            try:
671                name = itm.fileName()
672            except AttributeError:
673                name = itm.dirName()
674            names.append(name)
675        self.vcs.gitUnstage(names)
676
677    def __GitRevert(self):
678        """
679        Private slot to revert changes of the working area.
680        """
681        names = []
682        for itm in self.browser.getSelectedItems():
683            try:
684                name = itm.fileName()
685            except AttributeError:
686                name = itm.dirName()
687            names.append(name)
688        self.vcs.gitRevert(names)
689
690    def __GitBlame(self):
691        """
692        Private slot called by the context menu to show the annotations of a
693        file.
694        """
695        itm = self.browser.currentItem()
696        fn = itm.fileName()
697        self.vcs.gitBlame(fn)
698