Fixes: Ability to uncheck files in git.

This commit is contained in:
Friedemann Kleint
2008-12-02 15:43:58 +01:00
parent df7aacd637
commit c4c2437dd4
7 changed files with 106 additions and 32 deletions

View File

@@ -22,10 +22,9 @@
<property name="flat"> <property name="flat">
<bool>true</bool> <bool>true</bool>
</property> </property>
<layout class="QGridLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item row="0" column="0"> <item>
<widget class="QPlainTextEdit" name="description"> <widget class="QPlainTextEdit" name="description"/>
</widget>
</item> </item>
</layout> </layout>
</widget> </widget>
@@ -38,8 +37,8 @@
<property name="flat"> <property name="flat">
<bool>true</bool> <bool>true</bool>
</property> </property>
<layout class="QGridLayout"> <layout class="QVBoxLayout" name="verticalLayout_2">
<item row="0" column="0"> <item>
<widget class="QListWidget" name="fileList"> <widget class="QListWidget" name="fileList">
<property name="font"> <property name="font">
<font/> <font/>

View File

@@ -59,6 +59,8 @@ const char* const kGitCommand = "git";
const char* const kGitDirectoryC = ".git"; const char* const kGitDirectoryC = ".git";
const char* const kBranchIndicatorC = "# On branch"; const char* const kBranchIndicatorC = "# On branch";
enum { untrackedFilesInCommit = 0 };
static inline QString msgServerFailure() static inline QString msgServerFailure()
{ {
return GitClient::tr( return GitClient::tr(
@@ -197,7 +199,9 @@ void GitClient::diff(const QString &workingDirectory, const QString &fileName)
void GitClient::status(const QString &workingDirectory) 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) 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) bool GitClient::synchronousAdd(const QString &workingDirectory, const QStringList &files)
{ {
if (Git::Constants::debug)
qDebug() << Q_FUNC_INFO << workingDirectory << files;
QByteArray outputText; QByteArray outputText;
QByteArray errorText; QByteArray errorText;
QStringList arguments; QStringList arguments;
arguments << "add" << files; arguments << QLatin1String("add") << files;
const bool rc = synchronousGit(workingDirectory, arguments, &outputText, &errorText); const bool rc = synchronousGit(workingDirectory, arguments, &outputText, &errorText);
if (!rc) { if (!rc) {
const QString errorMessage = tr("Unable to add %n file(s) to %1: %2", 0, files.size()). 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; 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, void GitClient::executeGit(const QString &workingDirectory, const QStringList &arguments,
GitOutputWindow *outputWindow, VCSBase::VCSBaseEditor* editor, GitOutputWindow *outputWindow, VCSBase::VCSBaseEditor* editor,
bool outputToWindow) bool outputToWindow)
@@ -365,6 +395,22 @@ bool GitClient::synchronousGit(const QString &workingDirectory
return process.exitCode() == 0; 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: /* Parse a git status file list:
* \code * \code
# Changes to be committed: # Changes to be committed:
@@ -385,8 +431,8 @@ static bool parseFiles(const QStringList &lines, CommitData *d)
const QString untrackedIndicator = QLatin1String("# Untracked files:"); const QString untrackedIndicator = QLatin1String("# Untracked files:");
State s = None; State s = None;
// Match added/changed-not-updated files: "#<tab>modified: foo.cpp"
const QRegExp filesPattern(QLatin1String("#\\t[^:]+:\\s+[^ ]+")); QRegExp filesPattern(QLatin1String("#\\t[^:]+:\\s+.+"));
Q_ASSERT(filesPattern.isValid()); Q_ASSERT(filesPattern.isValid());
const QStringList::const_iterator cend = lines.constEnd(); const QStringList::const_iterator cend = lines.constEnd();
@@ -402,19 +448,22 @@ static bool parseFiles(const QStringList &lines, CommitData *d)
s = NotUpdatedFiles; s = NotUpdatedFiles;
} else { } else {
if (line.startsWith(untrackedIndicator)) { if (line.startsWith(untrackedIndicator)) {
// Now match untracked: "#<tab>foo.cpp"
s = UntrackedFiles; s = UntrackedFiles;
filesPattern = QRegExp(QLatin1String("#\\t.+"));
Q_ASSERT(filesPattern.isValid());
} else { } else {
if (filesPattern.exactMatch(line)) { if (filesPattern.exactMatch(line)) {
const QString fileSpec = line.mid(2).simplified(); const QString fileSpec = line.mid(2).trimmed();
switch (s) { switch (s) {
case CommitFiles: case CommitFiles:
d->commitFiles.push_back(fileSpec); d->commitFiles.push_back(trimFileSpecification(fileSpec));
break; break;
case NotUpdatedFiles: case NotUpdatedFiles:
d->notUpdatedFiles.push_back(fileSpec); d->notUpdatedFiles.push_back(trimFileSpecification(fileSpec));
break; break;
case UntrackedFiles: case UntrackedFiles:
d->untrackedFiles.push_back(fileSpec); d->untrackedFiles.push_back(QLatin1String("untracked: ") + fileSpec);
break; break;
case None: case None:
break; 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. // Run status. Note that it has exitcode 1 if there are no added files.
QByteArray outputText; QByteArray outputText;
QByteArray errorText; 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) { if (!statusRc) {
// Something fatal // Something fatal
if (!outputText.contains(kBranchIndicatorC)) { if (!outputText.contains(kBranchIndicatorC)) {
@@ -517,13 +569,25 @@ bool GitClient::getCommitData(const QString &workingDirectory,
return true; return true;
} }
// addAndCommit:
bool GitClient::addAndCommit(const QString &workingDirectory, bool GitClient::addAndCommit(const QString &workingDirectory,
const GitSubmitEditorPanelData &data, const GitSubmitEditorPanelData &data,
const QString &messageFile, 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 // Re-add all to make sure we have the latest changes
if (!synchronousAdd(workingDirectory, files)) if (!synchronousAdd(workingDirectory, checkedFiles))
return false; return false;
// Do the final commit // Do the final commit
@@ -536,8 +600,8 @@ bool GitClient::addAndCommit(const QString &workingDirectory,
QByteArray errorText; QByteArray errorText;
const bool rc = synchronousGit(workingDirectory, args, &outputText, &errorText); const bool rc = synchronousGit(workingDirectory, args, &outputText, &errorText);
const QString message = rc ? const QString message = rc ?
tr("Committed %n file(s).", 0, files.size()) : tr("Committed %n file(s).", 0, checkedFiles.size()) :
tr("Unable to commit %n file(s): %1", 0, files.size()).arg(QString::fromLocal8Bit(errorText)); 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->append(message);
m_plugin->m_outputWindow->popup(false); m_plugin->m_outputWindow->popup(false);

View File

@@ -90,6 +90,7 @@ public:
void hardReset(const QString &workingDirectory, const QString &commit); void hardReset(const QString &workingDirectory, const QString &commit);
void addFile(const QString &workingDirectory, const QString &fileName); void addFile(const QString &workingDirectory, const QString &fileName);
bool synchronousAdd(const QString &workingDirectory, const QStringList &files); bool synchronousAdd(const QString &workingDirectory, const QStringList &files);
bool synchronousReset(const QString &workingDirectory, const QStringList &files);
void pull(const QString &workingDirectory); void pull(const QString &workingDirectory);
void push(const QString &workingDirectory); void push(const QString &workingDirectory);
@@ -105,7 +106,8 @@ public:
bool addAndCommit(const QString &workingDirectory, bool addAndCommit(const QString &workingDirectory,
const GitSubmitEditorPanelData &data, const GitSubmitEditorPanelData &data,
const QString &messageFile, const QString &messageFile,
const QStringList &files); const QStringList &checkedFiles,
const QStringList &origCommitFiles);
public slots: public slots:
void show(const QString &source, const QString &id); void show(const QString &source, const QString &id);

View File

@@ -524,7 +524,10 @@ void GitPlugin::startCommit()
return; 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_submitRepository = data.panelInfo.repository;
m_submitOrigCommitFiles = GitSubmitEditor::statusListToFileList(data.commitFiles);
if (Git::Constants::debug) if (Git::Constants::debug)
qDebug() << Q_FUNC_INFO << data << commitTemplate; qDebug() << Q_FUNC_INFO << data << commitTemplate;
@@ -614,7 +617,8 @@ bool GitPlugin::editorAboutToClose(Core::IEditor *iEditor)
m_gitClient->addAndCommit(m_submitRepository, m_gitClient->addAndCommit(m_submitRepository,
editor->panelData(), editor->panelData(),
m_changeTmpFile->fileName(), m_changeTmpFile->fileName(),
fileList); fileList,
m_submitOrigCommitFiles);
} }
cleanChangeTmpFile(); cleanChangeTmpFile();
return true; return true;

View File

@@ -44,7 +44,7 @@
#include <QtCore/QObject> #include <QtCore/QObject>
#include <QtCore/QProcess> #include <QtCore/QProcess>
#include <QtCore/QList> #include <QtCore/QStringList>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QFile; class QFile;
@@ -155,6 +155,7 @@ private:
CoreListener *m_coreListener; CoreListener *m_coreListener;
Core::IEditorFactory *m_submitEditorFactory; Core::IEditorFactory *m_submitEditorFactory;
QString m_submitRepository; QString m_submitRepository;
QStringList m_submitOrigCommitFiles;
QTemporaryFile *m_changeTmpFile; QTemporaryFile *m_changeTmpFile;
}; };

View File

@@ -52,11 +52,13 @@ GitSubmitEditorWidget *GitSubmitEditor::submitEditorWidget()
return static_cast<GitSubmitEditorWidget *>(widget()); 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; QStringList rc;
foreach (const QString &rf, rawList) foreach (const QString &rf, rawList)
rc.push_back(fileFromChangeLine(rf)); rc.push_back(fileFromStatusLine(rf));
return rc; return rc;
} }
@@ -65,9 +67,8 @@ void GitSubmitEditor::setCommitData(const CommitData &d)
submitEditorWidget()->setPanelData(d.panelData); submitEditorWidget()->setPanelData(d.panelData);
submitEditorWidget()->setPanelInfo(d.panelInfo); submitEditorWidget()->setPanelInfo(d.panelInfo);
// Commited: Checked, user cannot uncheck addFiles(d.commitFiles, true, true);
addFiles(d.commitFiles, true, false); // Not Updated: Initially unchecked
// Not Updated: User can check
addFiles(d.notUpdatedFiles, false, true); addFiles(d.notUpdatedFiles, false, true);
addFiles(d.untrackedFiles, false, true); addFiles(d.untrackedFiles, false, true);
} }
@@ -77,10 +78,10 @@ GitSubmitEditorPanelData GitSubmitEditor::panelData() const
return const_cast<GitSubmitEditor*>(this)->submitEditorWidget()->panelData(); return const_cast<GitSubmitEditor*>(this)->submitEditorWidget()->panelData();
} }
QString GitSubmitEditor::fileFromChangeLine(const QString &line) QString GitSubmitEditor::fileFromStatusLine(const QString &line)
{ {
QString rc = line; QString rc = line;
// "modified: mainwindow.cpp" // "modified: mainwindow.cpp"
const int index = rc.indexOf(QLatin1Char(':')); const int index = rc.indexOf(QLatin1Char(':'));
if (index != -1) if (index != -1)
rc.remove(0, index + 1); rc.remove(0, index + 1);

View File

@@ -36,6 +36,8 @@
#include <vcsbase/vcsbasesubmiteditor.h> #include <vcsbase/vcsbasesubmiteditor.h>
#include <QtCore/QStringList>
namespace Git { namespace Git {
namespace Internal { namespace Internal {
@@ -43,7 +45,6 @@ class GitSubmitEditorWidget;
struct CommitData; struct CommitData;
struct GitSubmitEditorPanelData; struct GitSubmitEditorPanelData;
/* */
class GitSubmitEditor : public VCSBase::VCSBaseSubmitEditor class GitSubmitEditor : public VCSBase::VCSBaseSubmitEditor
{ {
Q_OBJECT Q_OBJECT
@@ -53,10 +54,12 @@ public:
void setCommitData(const CommitData &); void setCommitData(const CommitData &);
GitSubmitEditorPanelData panelData() const; GitSubmitEditorPanelData panelData() const;
static QString fileFromChangeLine(const QString &line); static QString fileFromStatusLine(const QString &line);
static QStringList statusListToFileList(const QStringList &);
protected: protected:
virtual QStringList vcsFileListToFileList(const QStringList &) const; virtual QStringList vcsFileListToFileList(const QStringList &l) const
{ return statusListToFileList(l); }
private: private:
inline GitSubmitEditorWidget *submitEditorWidget(); inline GitSubmitEditorWidget *submitEditorWidget();