forked from qt-creator/qt-creator
Fixes: Ability to uncheck files in git.
This commit is contained in:
@@ -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/>
|
||||||
|
@@ -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);
|
||||||
|
@@ -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);
|
||||||
|
@@ -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;
|
||||||
|
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -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);
|
||||||
|
@@ -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();
|
||||||
|
Reference in New Issue
Block a user