From c4c2437dd4de2efe787e17c923e181fbf7cac879 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint <qtc-committer@nokia.com> Date: Tue, 2 Dec 2008 15:43:58 +0100 Subject: [PATCH] Fixes: Ability to uncheck files in git. --- src/libs/utils/submiteditorwidget.ui | 11 ++-- src/plugins/git/gitclient.cpp | 90 ++++++++++++++++++++++++---- src/plugins/git/gitclient.h | 4 +- src/plugins/git/gitplugin.cpp | 6 +- src/plugins/git/gitplugin.h | 3 +- src/plugins/git/gitsubmiteditor.cpp | 15 ++--- src/plugins/git/gitsubmiteditor.h | 9 ++- 7 files changed, 106 insertions(+), 32 deletions(-) diff --git a/src/libs/utils/submiteditorwidget.ui b/src/libs/utils/submiteditorwidget.ui index 1a30e8b7919..4971f7e72d0 100644 --- a/src/libs/utils/submiteditorwidget.ui +++ b/src/libs/utils/submiteditorwidget.ui @@ -22,10 +22,9 @@ <property name="flat"> <bool>true</bool> </property> - <layout class="QGridLayout"> - <item row="0" column="0"> - <widget class="QPlainTextEdit" name="description"> - </widget> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QPlainTextEdit" name="description"/> </item> </layout> </widget> @@ -38,8 +37,8 @@ <property name="flat"> <bool>true</bool> </property> - <layout class="QGridLayout"> - <item row="0" column="0"> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> <widget class="QListWidget" name="fileList"> <property name="font"> <font/> diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index d021881dbb0..f7bba284410 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -59,6 +59,8 @@ const char* const kGitCommand = "git"; const char* const kGitDirectoryC = ".git"; const char* const kBranchIndicatorC = "# On branch"; +enum { untrackedFilesInCommit = 0 }; + static inline QString msgServerFailure() { return GitClient::tr( @@ -197,7 +199,9 @@ void GitClient::diff(const QString &workingDirectory, const QString &fileName) void GitClient::status(const QString &workingDirectory) { - executeGit(workingDirectory, QStringList(QLatin1String("status")), m_plugin->m_outputWindow, 0,true); + QStringList statusArgs(QLatin1String("status")); + statusArgs << QLatin1String("-u"); + executeGit(workingDirectory, statusArgs, m_plugin->m_outputWindow, 0,true); } void GitClient::log(const QString &workingDirectory, const QString &fileName) @@ -286,10 +290,12 @@ void GitClient::addFile(const QString &workingDirectory, const QString &fileName bool GitClient::synchronousAdd(const QString &workingDirectory, const QStringList &files) { + if (Git::Constants::debug) + qDebug() << Q_FUNC_INFO << workingDirectory << files; QByteArray outputText; QByteArray errorText; QStringList arguments; - arguments << "add" << files; + arguments << QLatin1String("add") << files; const bool rc = synchronousGit(workingDirectory, arguments, &outputText, &errorText); if (!rc) { const QString errorMessage = tr("Unable to add %n file(s) to %1: %2", 0, files.size()). @@ -300,6 +306,30 @@ bool GitClient::synchronousAdd(const QString &workingDirectory, const QStringLis return rc; } +bool GitClient::synchronousReset(const QString &workingDirectory, + const QStringList &files) +{ + if (Git::Constants::debug) + qDebug() << Q_FUNC_INFO << workingDirectory << files; + QByteArray outputText; + QByteArray errorText; + QStringList arguments; + arguments << QLatin1String("reset") << QLatin1String("HEAD") << files; + const bool rc = synchronousGit(workingDirectory, arguments, &outputText, &errorText); + const QString output = QString::fromLocal8Bit(outputText); + m_plugin->m_outputWindow->popup(false); + m_plugin->m_outputWindow->append(output); + // Note that git exits with 1 even if the operation is successful + // Assume real failure if the output does not contain "foo.cpp modified" + if (!rc && !output.contains(QLatin1String("modified"))) { + const QString errorMessage = tr("Unable to reset %n file(s) in %1: %2", 0, files.size()). + arg(workingDirectory, QString::fromLocal8Bit(errorText)); + m_plugin->m_outputWindow->append(errorMessage); + return false; + } + return true; +} + void GitClient::executeGit(const QString &workingDirectory, const QStringList &arguments, GitOutputWindow *outputWindow, VCSBase::VCSBaseEditor* editor, bool outputToWindow) @@ -365,6 +395,22 @@ bool GitClient::synchronousGit(const QString &workingDirectory return process.exitCode() == 0; } + +// Trim a git status file spec: "modified: foo .cpp" -> "modified: foo .cpp" +static inline QString trimFileSpecification(QString fileSpec) +{ + const int colonIndex = fileSpec.indexOf(QLatin1Char(':')); + if (colonIndex != -1) { + // Collapse the sequence of spaces + const int filePos = colonIndex + 2; + int nonBlankPos = filePos; + for ( ; fileSpec.at(nonBlankPos).isSpace(); nonBlankPos++); + if (nonBlankPos > filePos) + fileSpec.remove(filePos, nonBlankPos - filePos); + } + return fileSpec; +} + /* Parse a git status file list: * \code # Changes to be committed: @@ -385,8 +431,8 @@ static bool parseFiles(const QStringList &lines, CommitData *d) const QString untrackedIndicator = QLatin1String("# Untracked files:"); State s = None; - - const QRegExp filesPattern(QLatin1String("#\\t[^:]+:\\s+[^ ]+")); + // Match added/changed-not-updated files: "#<tab>modified: foo.cpp" + QRegExp filesPattern(QLatin1String("#\\t[^:]+:\\s+.+")); Q_ASSERT(filesPattern.isValid()); const QStringList::const_iterator cend = lines.constEnd(); @@ -402,19 +448,22 @@ static bool parseFiles(const QStringList &lines, CommitData *d) s = NotUpdatedFiles; } else { if (line.startsWith(untrackedIndicator)) { + // Now match untracked: "#<tab>foo.cpp" s = UntrackedFiles; + filesPattern = QRegExp(QLatin1String("#\\t.+")); + Q_ASSERT(filesPattern.isValid()); } else { if (filesPattern.exactMatch(line)) { - const QString fileSpec = line.mid(2).simplified(); + const QString fileSpec = line.mid(2).trimmed(); switch (s) { case CommitFiles: - d->commitFiles.push_back(fileSpec); + d->commitFiles.push_back(trimFileSpecification(fileSpec)); break; case NotUpdatedFiles: - d->notUpdatedFiles.push_back(fileSpec); + d->notUpdatedFiles.push_back(trimFileSpecification(fileSpec)); break; case UntrackedFiles: - d->untrackedFiles.push_back(fileSpec); + d->untrackedFiles.push_back(QLatin1String("untracked: ") + fileSpec); break; case None: break; @@ -461,7 +510,10 @@ bool GitClient::getCommitData(const QString &workingDirectory, // Run status. Note that it has exitcode 1 if there are no added files. QByteArray outputText; QByteArray errorText; - const bool statusRc = synchronousGit(workingDirectory, QStringList(QLatin1String("status")), &outputText, &errorText); + QStringList statusArgs(QLatin1String("status")); + if (untrackedFilesInCommit) + statusArgs << QLatin1String("-u"); + const bool statusRc = synchronousGit(workingDirectory, statusArgs, &outputText, &errorText); if (!statusRc) { // Something fatal if (!outputText.contains(kBranchIndicatorC)) { @@ -517,13 +569,25 @@ bool GitClient::getCommitData(const QString &workingDirectory, return true; } +// addAndCommit: bool GitClient::addAndCommit(const QString &workingDirectory, const GitSubmitEditorPanelData &data, const QString &messageFile, - const QStringList &files) + const QStringList &checkedFiles, + const QStringList &origCommitFiles) { + if (Git::Constants::debug) + qDebug() << "GitClient::addAndCommit:" << workingDirectory << checkedFiles << origCommitFiles; + + // Do we need to reset any files that had been added before + // (did the user uncheck any previously added files) + const QSet<QString> resetFiles = origCommitFiles.toSet().subtract(checkedFiles.toSet()); + if (!resetFiles.empty()) + if (!synchronousReset(workingDirectory, resetFiles.toList())) + return false; + // Re-add all to make sure we have the latest changes - if (!synchronousAdd(workingDirectory, files)) + if (!synchronousAdd(workingDirectory, checkedFiles)) return false; // Do the final commit @@ -536,8 +600,8 @@ bool GitClient::addAndCommit(const QString &workingDirectory, QByteArray errorText; const bool rc = synchronousGit(workingDirectory, args, &outputText, &errorText); const QString message = rc ? - tr("Committed %n file(s).", 0, files.size()) : - tr("Unable to commit %n file(s): %1", 0, files.size()).arg(QString::fromLocal8Bit(errorText)); + tr("Committed %n file(s).", 0, checkedFiles.size()) : + tr("Unable to commit %n file(s): %1", 0, checkedFiles.size()).arg(QString::fromLocal8Bit(errorText)); m_plugin->m_outputWindow->append(message); m_plugin->m_outputWindow->popup(false); diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h index 944041afa3d..1a7ebe8c983 100644 --- a/src/plugins/git/gitclient.h +++ b/src/plugins/git/gitclient.h @@ -90,6 +90,7 @@ public: void hardReset(const QString &workingDirectory, const QString &commit); void addFile(const QString &workingDirectory, const QString &fileName); bool synchronousAdd(const QString &workingDirectory, const QStringList &files); + bool synchronousReset(const QString &workingDirectory, const QStringList &files); void pull(const QString &workingDirectory); void push(const QString &workingDirectory); @@ -105,7 +106,8 @@ public: bool addAndCommit(const QString &workingDirectory, const GitSubmitEditorPanelData &data, const QString &messageFile, - const QStringList &files); + const QStringList &checkedFiles, + const QStringList &origCommitFiles); public slots: void show(const QString &source, const QString &id); diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index 3b6342db8ee..6ee7bab39b0 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -524,7 +524,10 @@ void GitPlugin::startCommit() return; } + // 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_submitOrigCommitFiles = GitSubmitEditor::statusListToFileList(data.commitFiles); if (Git::Constants::debug) qDebug() << Q_FUNC_INFO << data << commitTemplate; @@ -614,7 +617,8 @@ bool GitPlugin::editorAboutToClose(Core::IEditor *iEditor) m_gitClient->addAndCommit(m_submitRepository, editor->panelData(), m_changeTmpFile->fileName(), - fileList); + fileList, + m_submitOrigCommitFiles); } cleanChangeTmpFile(); return true; diff --git a/src/plugins/git/gitplugin.h b/src/plugins/git/gitplugin.h index 7becc05e7dc..51846c71d66 100644 --- a/src/plugins/git/gitplugin.h +++ b/src/plugins/git/gitplugin.h @@ -44,7 +44,7 @@ #include <QtCore/QObject> #include <QtCore/QProcess> -#include <QtCore/QList> +#include <QtCore/QStringList> QT_BEGIN_NAMESPACE class QFile; @@ -155,6 +155,7 @@ private: CoreListener *m_coreListener; Core::IEditorFactory *m_submitEditorFactory; QString m_submitRepository; + QStringList m_submitOrigCommitFiles; QTemporaryFile *m_changeTmpFile; }; diff --git a/src/plugins/git/gitsubmiteditor.cpp b/src/plugins/git/gitsubmiteditor.cpp index 4f0e201d666..516dc6570b7 100644 --- a/src/plugins/git/gitsubmiteditor.cpp +++ b/src/plugins/git/gitsubmiteditor.cpp @@ -52,11 +52,13 @@ GitSubmitEditorWidget *GitSubmitEditor::submitEditorWidget() return static_cast<GitSubmitEditorWidget *>(widget()); } -QStringList GitSubmitEditor::vcsFileListToFileList(const QStringList &rawList) const +QStringList GitSubmitEditor::statusListToFileList(const QStringList &rawList) { + if (rawList.empty()) + return rawList; QStringList rc; foreach (const QString &rf, rawList) - rc.push_back(fileFromChangeLine(rf)); + rc.push_back(fileFromStatusLine(rf)); return rc; } @@ -65,9 +67,8 @@ void GitSubmitEditor::setCommitData(const CommitData &d) submitEditorWidget()->setPanelData(d.panelData); submitEditorWidget()->setPanelInfo(d.panelInfo); - // Commited: Checked, user cannot uncheck - addFiles(d.commitFiles, true, false); - // Not Updated: User can check + addFiles(d.commitFiles, true, true); + // Not Updated: Initially unchecked addFiles(d.notUpdatedFiles, false, true); addFiles(d.untrackedFiles, false, true); } @@ -77,10 +78,10 @@ GitSubmitEditorPanelData GitSubmitEditor::panelData() const return const_cast<GitSubmitEditor*>(this)->submitEditorWidget()->panelData(); } -QString GitSubmitEditor::fileFromChangeLine(const QString &line) +QString GitSubmitEditor::fileFromStatusLine(const QString &line) { QString rc = line; - // "modified: mainwindow.cpp" + // "modified: mainwindow.cpp" const int index = rc.indexOf(QLatin1Char(':')); if (index != -1) rc.remove(0, index + 1); diff --git a/src/plugins/git/gitsubmiteditor.h b/src/plugins/git/gitsubmiteditor.h index e0554758a29..4219f5ae3dd 100644 --- a/src/plugins/git/gitsubmiteditor.h +++ b/src/plugins/git/gitsubmiteditor.h @@ -36,6 +36,8 @@ #include <vcsbase/vcsbasesubmiteditor.h> +#include <QtCore/QStringList> + namespace Git { namespace Internal { @@ -43,7 +45,6 @@ class GitSubmitEditorWidget; struct CommitData; struct GitSubmitEditorPanelData; -/* */ class GitSubmitEditor : public VCSBase::VCSBaseSubmitEditor { Q_OBJECT @@ -53,10 +54,12 @@ public: void setCommitData(const CommitData &); GitSubmitEditorPanelData panelData() const; - static QString fileFromChangeLine(const QString &line); + static QString fileFromStatusLine(const QString &line); + static QStringList statusListToFileList(const QStringList &); protected: - virtual QStringList vcsFileListToFileList(const QStringList &) const; + virtual QStringList vcsFileListToFileList(const QStringList &l) const + { return statusListToFileList(l); } private: inline GitSubmitEditorWidget *submitEditorWidget(); -- GitLab