Commit c4c2437d authored by Friedemann Kleint's avatar Friedemann Kleint
Browse files

Fixes: Ability to uncheck files in git.

parent df7aacd6
......@@ -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/>
......
......@@ -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);
......
......@@ -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);
......
......@@ -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;
......
......@@ -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;
};
......
......@@ -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);
......
......@@ -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();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment