From 0f0c17111d970f77e5582669a0bd180fcf3ad05a Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Date: Mon, 23 Aug 2010 12:15:48 +0200
Subject: [PATCH] VCS[git]: Add menu option for git amend.

Task-number: QTCREATORBUG-1642
---
 src/libs/utils/submiteditorwidget.cpp       | 17 +++-
 src/libs/utils/submiteditorwidget.h         |  6 ++
 src/plugins/git/commitdata.cpp              |  1 +
 src/plugins/git/commitdata.h                |  1 +
 src/plugins/git/gitclient.cpp               | 99 ++++++++++++++-------
 src/plugins/git/gitclient.h                 |  6 +-
 src/plugins/git/gitplugin.cpp               | 29 +++++-
 src/plugins/git/gitplugin.h                 |  5 +-
 src/plugins/git/gitsubmiteditor.cpp         |  1 -
 src/plugins/vcsbase/vcsbasesubmiteditor.cpp | 11 +++
 src/plugins/vcsbase/vcsbasesubmiteditor.h   |  5 ++
 11 files changed, 139 insertions(+), 42 deletions(-)

diff --git a/src/libs/utils/submiteditorwidget.cpp b/src/libs/utils/submiteditorwidget.cpp
index 99f1d60c8ba..b4a5be89341 100644
--- a/src/libs/utils/submiteditorwidget.cpp
+++ b/src/libs/utils/submiteditorwidget.cpp
@@ -142,6 +142,7 @@ struct SubmitEditorWidgetPrivate
     bool m_filesChecked;
     int m_fileNameColumn;
     int m_activatedRow;
+    bool m_emptyFileListEnabled;
 
     QList<AdditionalContextMenuAction> descriptionEditContextMenuActions;
     QVBoxLayout *m_fieldLayout;
@@ -154,6 +155,7 @@ SubmitEditorWidgetPrivate::SubmitEditorWidgetPrivate() :
     m_filesChecked(false),
     m_fileNameColumn(1),
     m_activatedRow(-1),
+    m_emptyFileListEnabled(false),
     m_fieldLayout(0),
     m_lineWidth(defaultLineWidth)
 {
@@ -446,7 +448,7 @@ void SubmitEditorWidget::updateActions()
 void SubmitEditorWidget::updateSubmitAction()
 {
     const unsigned checkedCount = checkedFilesCount();
-    const bool newFilesCheckedState = checkedCount;
+    const bool newFilesCheckedState = m_d->m_emptyFileListEnabled || checkedCount > 0;
     // Emit signal to update action
     if (m_d->m_filesChecked != newFilesCheckedState) {
         m_d->m_filesChecked = newFilesCheckedState;
@@ -581,6 +583,19 @@ void SubmitEditorWidget::fileListCustomContextMenuRequested(const QPoint & pos)
     }
 }
 
+bool SubmitEditorWidget::isEmptyFileListEnabled() const
+{
+    return m_d->m_emptyFileListEnabled;
+}
+
+void SubmitEditorWidget::setEmptyFileListEnabled(bool e)
+{
+    if (e != m_d->m_emptyFileListEnabled) {
+        m_d->m_emptyFileListEnabled = e;
+        updateSubmitAction();
+    }
+}
+
 } // namespace Utils
 
 #include "submiteditorwidget.moc"
diff --git a/src/libs/utils/submiteditorwidget.h b/src/libs/utils/submiteditorwidget.h
index e31fb8cd3cf..457783a9d7f 100644
--- a/src/libs/utils/submiteditorwidget.h
+++ b/src/libs/utils/submiteditorwidget.h
@@ -76,6 +76,8 @@ class QTCREATOR_UTILS_EXPORT SubmitEditorWidget : public QWidget
     Q_PROPERTY(QAbstractItemView::SelectionMode fileListSelectionMode READ fileListSelectionMode WRITE setFileListSelectionMode DESIGNABLE true)
     Q_PROPERTY(bool lineWrap READ lineWrap WRITE setLineWrap DESIGNABLE true)
     Q_PROPERTY(int lineWrapWidth READ lineWrapWidth WRITE setLineWrapWidth DESIGNABLE true)
+    Q_PROPERTY(bool emptyFileListEnabled READ isEmptyFileListEnabled WRITE setEmptyFileListEnabled DESIGNABLE true)
+
 public:
     explicit SubmitEditorWidget(QWidget *parent = 0);
     virtual ~SubmitEditorWidget();
@@ -91,6 +93,10 @@ public:
     QString descriptionText() const;
     void setDescriptionText(const QString &text);
 
+    // 'Commit' action enabled despite empty file list
+    bool isEmptyFileListEnabled() const;
+    void setEmptyFileListEnabled(bool e);
+
     int fileNameColumn() const;
     void setFileNameColumn(int c);
 
diff --git a/src/plugins/git/commitdata.cpp b/src/plugins/git/commitdata.cpp
index 0a160eff2d4..10a39b77f44 100644
--- a/src/plugins/git/commitdata.cpp
+++ b/src/plugins/git/commitdata.cpp
@@ -82,6 +82,7 @@ void CommitData::clear()
 {
     panelInfo.clear();
     panelData.clear();
+    amendSHA1.clear();
 
     stagedFiles.clear();
     unstagedFiles.clear();
diff --git a/src/plugins/git/commitdata.h b/src/plugins/git/commitdata.h
index f0380c4dbc2..6b8b99971e5 100644
--- a/src/plugins/git/commitdata.h
+++ b/src/plugins/git/commitdata.h
@@ -80,6 +80,7 @@ struct CommitData
     QStringList stagedFileNames(const QString &stateFilter = QString()) const;
     QStringList unstagedFileNames(const QString &stateFilter = QString()) const;
 
+    QString amendSHA1;
     GitSubmitEditorPanelInfo panelInfo;
     GitSubmitEditorPanelData panelData;
 
diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp
index d2293d55668..c15817db9ef 100644
--- a/src/plugins/git/gitclient.cpp
+++ b/src/plugins/git/gitclient.cpp
@@ -1336,14 +1336,15 @@ void GitClient::launchGitK(const QString &workingDirectory)
 }
 
 bool GitClient::getCommitData(const QString &workingDirectory,
+                              bool amend,
                               QString *commitTemplate,
-                              CommitData *d,
+                              CommitData *commitData,
                               QString *errorMessage)
 {
     if (Git::Constants::debug)
         qDebug() << Q_FUNC_INFO << workingDirectory;
 
-    d->clear();
+    commitData->clear();
 
     // Find repo
     const QString repoDirectory = GitClient::findRepositoryForDirectory(workingDirectory);
@@ -1352,7 +1353,7 @@ bool GitClient::getCommitData(const QString &workingDirectory,
         return false;
     }
 
-    d->panelInfo.repository = repoDirectory;
+    commitData->panelInfo.repository = repoDirectory;
 
     QDir gitDir(repoDirectory);
     if (!gitDir.cd(QLatin1String(kGitDirectoryC))) {
@@ -1365,13 +1366,14 @@ bool GitClient::getCommitData(const QString &workingDirectory,
     if (QFileInfo(descriptionFile).isFile()) {
         QFile file(descriptionFile);
         if (file.open(QIODevice::ReadOnly|QIODevice::Text))
-            d->panelInfo.description = commandOutputFromLocal8Bit(file.readAll()).trimmed();
+            commitData->panelInfo.description = commandOutputFromLocal8Bit(file.readAll()).trimmed();
     }
 
     // Run status. Note that it has exitcode 1 if there are no added files.
     bool onBranch;
     QString output;
-    switch (gitStatus(repoDirectory, true, &output, errorMessage, &onBranch)) {
+    const StatusResult status = gitStatus(repoDirectory, true, &output, errorMessage, &onBranch);
+    switch (status) {
     case  StatusChanged:
         if (!onBranch) {
             *errorMessage = tr("You did not checkout a branch.");
@@ -1379,6 +1381,8 @@ bool GitClient::getCommitData(const QString &workingDirectory,
         }
         break;
     case StatusUnchanged:
+        if (amend)
+            break;
         *errorMessage = msgNoChangedFiles();
         return false;
     case StatusFailed:
@@ -1403,42 +1407,71 @@ bool GitClient::getCommitData(const QString &workingDirectory,
     //    #
     //    #       list of files...
 
-    if (!d->parseFilesFromStatus(output)) {
-        *errorMessage = msgParseFilesFailed();
-        return false;
-    }
-    // Filter out untracked files that are not part of the project
-    VCSBase::VCSBaseSubmitEditor::filterUntrackedFilesOfProject(repoDirectory, &d->untrackedFiles);
-    if (d->filesEmpty()) {
-        *errorMessage = msgNoChangedFiles();
-        return false;
+    if (status != StatusUnchanged) {
+        if (!commitData->parseFilesFromStatus(output)) {
+            *errorMessage = msgParseFilesFailed();
+            return false;
+        }
+        // Filter out untracked files that are not part of the project
+        VCSBase::VCSBaseSubmitEditor::filterUntrackedFilesOfProject(repoDirectory, &commitData->untrackedFiles);
+        if (commitData->filesEmpty()) {
+            *errorMessage = msgNoChangedFiles();
+            return false;
+        }
     }
 
-    d->panelData.author = readConfigValue(workingDirectory, QLatin1String("user.name"));
-    d->panelData.email = readConfigValue(workingDirectory, QLatin1String("user.email"));
+    commitData->panelData.author = readConfigValue(workingDirectory, QLatin1String("user.name"));
+    commitData->panelData.email = readConfigValue(workingDirectory, QLatin1String("user.email"));
 
-    // Get the commit template
-    QString templateFilename = readConfigValue(workingDirectory, QLatin1String("commit.template"));
-    if (!templateFilename.isEmpty()) {
-        // Make relative to repository
-        const QFileInfo templateFileInfo(templateFilename);
-        if (templateFileInfo.isRelative())
-            templateFilename = repoDirectory + QLatin1Char('/') + templateFilename;
-        QFile templateFile(templateFilename);
-        if (templateFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
-            *commitTemplate = QString::fromLocal8Bit(templateFile.readAll());
-        } else {
-            qWarning("Unable to read commit template %s: %s",
-                     qPrintable(templateFilename),
-                     qPrintable(templateFile.errorString()));
+    // Get the commit template or the last commit message
+    if (amend) {
+        // Amend: get last commit data as "SHA1@message". TODO: Figure out codec.
+        QStringList args(QLatin1String("log"));
+        args << QLatin1String("--max-count=1") << QLatin1String("--pretty=format:%h@%B");
+        const Utils::SynchronousProcessResponse sp = synchronousGit(repoDirectory, args);
+        if (sp.result != Utils::SynchronousProcessResponse::Finished) {
+            *errorMessage = tr("Unable to retrieve the last commit data from %1.").arg(repoDirectory);
+            return false;
+        }
+        const int separatorPos = sp.stdOut.indexOf(QLatin1Char('@'));
+        QTC_ASSERT(separatorPos != -1, return false)
+        commitData->amendSHA1= sp.stdOut.left(separatorPos);
+        *commitTemplate = sp.stdOut.mid(separatorPos + 1);
+    } else {
+        // Commit: Get the commit template
+        QString templateFilename = readConfigValue(workingDirectory, QLatin1String("commit.template"));
+        if (!templateFilename.isEmpty()) {
+            // Make relative to repository
+            const QFileInfo templateFileInfo(templateFilename);
+            if (templateFileInfo.isRelative())
+                templateFilename = repoDirectory + QLatin1Char('/') + templateFilename;
+            QFile templateFile(templateFilename);
+            if (templateFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
+                *commitTemplate = QString::fromLocal8Bit(templateFile.readAll());
+            } else {
+                qWarning("Unable to read commit template %s: %s",
+                         qPrintable(templateFilename),
+                         qPrintable(templateFile.errorString()));
+            }
         }
     }
     return true;
 }
 
+// Log message for commits/amended commits to go to output window
+static inline QString msgCommitted(const QString &amendSHA1, int fileCount)
+{
+    if (amendSHA1.isEmpty())
+        return GitClient::tr("Committed %n file(s).\n", 0, fileCount);
+    if (fileCount)
+        return GitClient::tr("Amended %1 (%n file(s)).\n", 0, fileCount).arg(amendSHA1);
+    return GitClient::tr("Amended %1.").arg(amendSHA1);
+}
+
 // addAndCommit:
 bool GitClient::addAndCommit(const QString &repositoryDirectory,
                              const GitSubmitEditorPanelData &data,
+                             const QString &amendSHA1,
                              const QString &messageFile,
                              const QStringList &checkedFiles,
                              const QStringList &origCommitFiles,
@@ -1447,6 +1480,7 @@ bool GitClient::addAndCommit(const QString &repositoryDirectory,
     if (Git::Constants::debug)
         qDebug() << "GitClient::addAndCommit:" << repositoryDirectory << checkedFiles << origCommitFiles;
     const QString renamedSeparator = QLatin1String(" -> ");
+    const bool amend = !amendSHA1.isEmpty();
 
     // Do we need to reset any files that had been added before
     // (did the user uncheck any previously added files)
@@ -1483,7 +1517,8 @@ bool GitClient::addAndCommit(const QString &repositoryDirectory,
     QStringList args;
     args << QLatin1String("commit")
          << QLatin1String("-F") << QDir::toNativeSeparators(messageFile);
-
+    if (amend)
+        args << QLatin1String("--amend");
     const QString &authorString =  data.authorString();
     if (!authorString.isEmpty())
          args << QLatin1String("--author") << authorString;
@@ -1492,7 +1527,7 @@ bool GitClient::addAndCommit(const QString &repositoryDirectory,
     QByteArray errorText;
     const bool rc = fullySynchronousGit(repositoryDirectory, args, &outputText, &errorText);
     if (rc) {
-        outputWindow()->append(tr("Committed %n file(s).\n", 0, checkedFiles.size()));
+        outputWindow()->append(msgCommitted(amendSHA1, checkedFiles.size()));
     } else {
         outputWindow()->appendError(tr("Unable to commit %n file(s): %1\n", 0, checkedFiles.size()).arg(commandOutputFromLocal8Bit(errorText)));
     }
diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h
index ef0ca8dac85..11162a93414 100644
--- a/src/plugins/git/gitclient.h
+++ b/src/plugins/git/gitclient.h
@@ -185,13 +185,13 @@ public:
     StashResult ensureStash(const QString &workingDirectory, QString *errorMessage);
     StashResult ensureStash(const QString &workingDirectory);
 
-    bool getCommitData(const QString &workingDirectory,
-                       QString *commitTemplate,
-                       CommitData *d,
+    bool getCommitData(const QString &workingDirectory, bool amend,
+                       QString *commitTemplate, CommitData *commitData,
                        QString *errorMessage);
 
     bool addAndCommit(const QString &workingDirectory,
                       const GitSubmitEditorPanelData &data,
+                      const QString &amendSHA1,
                       const QString &messageFile,
                       const QStringList &checkedFiles,
                       const QStringList &origCommitFiles,
diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp
index efc7af9b2fa..404869ce6dd 100644
--- a/src/plugins/git/gitplugin.cpp
+++ b/src/plugins/git/gitplugin.cpp
@@ -451,6 +451,10 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage)
                                            globalcontext, true, SLOT(startCommit()));
     actionCommand.second->setDefaultKeySequence(QKeySequence(tr("Alt+G,Alt+C")));
 
+    createRepositoryAction(actionManager, gitContainer,
+                           tr("Amend Last Commit..."), QLatin1String("Git.AmendCommit"),
+                           globalcontext, true, SLOT(startAmendCommit()));
+
     actionCommand = createRepositoryAction(actionManager, gitContainer,
                                            tr("Push"), QLatin1String("Git.Push"),
                                            globalcontext, true, SLOT(push()));
@@ -610,8 +614,19 @@ void GitPlugin::unstageFile()
     m_gitClient->synchronousReset(state.currentFileTopLevel(), QStringList(state.relativeCurrentFile()));
 }
 
+void GitPlugin::startAmendCommit()
+{
+    startCommit(true);
+}
+
 void GitPlugin::startCommit()
 {
+    startCommit(false);
+}
+
+void GitPlugin::startCommit(bool amend)
+{
+
     if (VCSBase::VCSBaseSubmitEditor::raiseSubmitEditor())
         return;
     if (isCommitEditorOpen()) {
@@ -624,7 +639,7 @@ void GitPlugin::startCommit()
 
     QString errorMessage, commitTemplate;
     CommitData data;
-    if (!m_gitClient->getCommitData(state.topLevel(), &commitTemplate, &data, &errorMessage)) {
+    if (!m_gitClient->getCommitData(state.topLevel(), amend, &commitTemplate, &data, &errorMessage)) {
         VCSBase::VCSBaseOutputWindow::instance()->append(errorMessage);
         return;
     }
@@ -632,6 +647,7 @@ void GitPlugin::startCommit()
     // Store repository for diff and the original list of
     // files to be able to unstage files the user unchecks
     m_submitRepository = data.panelInfo.repository;
+    m_commitAmendSHA1 = data.amendSHA1;
     m_submitOrigCommitFiles = data.stagedFileNames();
     m_submitOrigDeleteFiles = data.stagedFileNames("deleted");
 
@@ -651,10 +667,10 @@ void GitPlugin::startCommit()
     // Keep the file alive, else it removes self and forgets
     // its name
     changeTmpFile.close();
-    openSubmitEditor(m_commitMessageFileName, data);
+    openSubmitEditor(m_commitMessageFileName, data, amend);
 }
 
-Core::IEditor *GitPlugin::openSubmitEditor(const QString &fileName, const CommitData &cd)
+Core::IEditor *GitPlugin::openSubmitEditor(const QString &fileName, const CommitData &cd, bool amend)
 {
     Core::IEditor *editor = m_core->editorManager()->openEditor(fileName, QLatin1String(Constants::GITSUBMITEDITOR_ID));
     if (Git::Constants::debug)
@@ -667,6 +683,10 @@ Core::IEditor *GitPlugin::openSubmitEditor(const QString &fileName, const Commit
     submitEditor->registerActions(m_undoAction, m_redoAction, m_submitCurrentAction, m_diffSelectedFilesAction);
     submitEditor->setCommitData(cd);
     submitEditor->setCheckScriptWorkingDirectory(m_submitRepository);
+    const QString title = amend ? tr("Amend %1").arg(cd.amendSHA1) : tr("Git Commit");
+    submitEditor->setDisplayName(title);
+    if (amend) // Allow for just correcting the message
+        submitEditor->setEmptyFileListEnabled(true);
     connect(submitEditor, SIGNAL(diff(QStringList,QStringList)), this, SLOT(submitEditorDiff(QStringList,QStringList)));
     return editor;
 }
@@ -721,7 +741,7 @@ bool GitPlugin::submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEdi
     if (Git::Constants::debug)
         qDebug() << Q_FUNC_INFO << fileList;
     bool closeEditor = true;
-    if (!fileList.empty()) {
+    if (!fileList.empty() || !m_commitAmendSHA1.isEmpty()) {
         // get message & commit
         m_core->fileManager()->blockFileChange(fileIFace);
         fileIFace->save();
@@ -729,6 +749,7 @@ bool GitPlugin::submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEdi
 
         closeEditor = m_gitClient->addAndCommit(m_submitRepository,
                                                 editor->panelData(),
+                                                m_commitAmendSHA1,
                                                 m_commitMessageFileName,
                                                 fileList,
                                                 m_submitOrigCommitFiles,
diff --git a/src/plugins/git/gitplugin.h b/src/plugins/git/gitplugin.h
index 85a4f967590..cec2821bd72 100644
--- a/src/plugins/git/gitplugin.h
+++ b/src/plugins/git/gitplugin.h
@@ -122,6 +122,7 @@ private slots:
 
     void showCommit();
     void startCommit();
+    void startAmendCommit();
     void stash();
     void stashSnapshot();
     void branchList();
@@ -170,10 +171,11 @@ private:
                                            bool addToLocator, GitClientMemberFunc);
 
     bool isCommitEditorOpen() const;
-    Core::IEditor *openSubmitEditor(const QString &fileName, const CommitData &cd);
+    Core::IEditor *openSubmitEditor(const QString &fileName, const CommitData &cd, bool amend);
     void cleanCommitMessageFile();
     void cleanRepository(const QString &directory);
     void applyPatch(const QString &workingDirectory, QString file = QString());
+    void startCommit(bool amend);
 
     static GitPlugin *m_instance;
     Core::ICore *m_core;
@@ -201,6 +203,7 @@ private:
     QStringList                 m_submitOrigCommitFiles;
     QStringList                 m_submitOrigDeleteFiles;
     QString                     m_commitMessageFileName;
+    QString                     m_commitAmendSHA1;
     bool                        m_submitActionTriggered;
 
 };
diff --git a/src/plugins/git/gitsubmiteditor.cpp b/src/plugins/git/gitsubmiteditor.cpp
index 5aa11347bf4..8452142e7e4 100644
--- a/src/plugins/git/gitsubmiteditor.cpp
+++ b/src/plugins/git/gitsubmiteditor.cpp
@@ -52,7 +52,6 @@ GitSubmitEditor::GitSubmitEditor(const VCSBase::VCSBaseSubmitEditorParameters *p
     VCSBaseSubmitEditor(parameters, new GitSubmitEditorWidget(parent)),
     m_model(0)
 {
-    setDisplayName(tr("Git Commit"));
     connect(this, SIGNAL(diffSelectedFiles(QStringList)), this, SLOT(slotDiffSelected(QStringList)));
 }
 
diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp
index ca20460aa3b..736a7981685 100644
--- a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp
+++ b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp
@@ -230,6 +230,7 @@ void VCSBaseSubmitEditor::unregisterActions(QAction *editorUndoAction,  QAction
     m_d->m_widget->unregisterActions(editorUndoAction, editorRedoAction, submitAction, diffAction);
     m_d->m_diffAction = m_d->m_submitAction = 0;
 }
+
 int VCSBaseSubmitEditor::fileNameColumn() const
 {
     return m_d->m_widget->fileNameColumn();
@@ -250,6 +251,16 @@ void VCSBaseSubmitEditor::setFileListSelectionMode(QAbstractItemView::SelectionM
     m_d->m_widget->setFileListSelectionMode(sm);
 }
 
+bool VCSBaseSubmitEditor::isEmptyFileListEnabled() const
+{
+    return m_d->m_widget->isEmptyFileListEnabled();
+}
+
+void VCSBaseSubmitEditor::setEmptyFileListEnabled(bool e)
+{
+    m_d->m_widget->setEmptyFileListEnabled(e);
+}
+
 bool VCSBaseSubmitEditor::lineWrap() const
 {
     return m_d->m_widget->lineWrap();
diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.h b/src/plugins/vcsbase/vcsbasesubmiteditor.h
index 414aa4bdb14..2880043c533 100644
--- a/src/plugins/vcsbase/vcsbasesubmiteditor.h
+++ b/src/plugins/vcsbase/vcsbasesubmiteditor.h
@@ -90,6 +90,7 @@ class VCSBASE_EXPORT VCSBaseSubmitEditor : public Core::IEditor
     Q_PROPERTY(bool lineWrap READ lineWrap WRITE setLineWrap DESIGNABLE true)
     Q_PROPERTY(int lineWrapWidth READ lineWrapWidth WRITE setLineWrapWidth DESIGNABLE true)
     Q_PROPERTY(QString checkScriptWorkingDirectory READ checkScriptWorkingDirectory WRITE setCheckScriptWorkingDirectory DESIGNABLE true)
+    Q_PROPERTY(bool emptyFileListEnabled READ isEmptyFileListEnabled WRITE setEmptyFileListEnabled DESIGNABLE true)
 
 protected:
     explicit VCSBaseSubmitEditor(const VCSBaseSubmitEditorParameters *parameters,
@@ -122,6 +123,10 @@ public:
     QAbstractItemView::SelectionMode fileListSelectionMode() const;
     void setFileListSelectionMode(QAbstractItemView::SelectionMode sm);
 
+    // 'Commit' action enabled despite empty file list
+    bool isEmptyFileListEnabled() const;
+    void setEmptyFileListEnabled(bool e);
+
     bool lineWrap() const;
     void setLineWrap(bool);
 
-- 
GitLab