summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTobias Hunger <tobias.hunger@nokia.com>2011-10-19 15:49:13 +0000
committerTobias Hunger <tobias.hunger@nokia.com>2011-10-31 11:49:39 +0100
commit494fbdb0d2d486ba43dd655e2fa126bfa881f44b (patch)
treed280bed55ad9293119d96e668f322b313c352d6b /src
parent366a9d0d0eb450d1af58bc2c2d54c5e05bff82ee (diff)
downloadqt-creator-494fbdb0d2d486ba43dd655e2fa126bfa881f44b.tar.gz
Git: Do the right thing when commiting
Do the right thing when commiting in git. This allows staged files to be commited without additional changes, etc. Change-Id: Ib04c91cf9c105c4a2bbe013926112d6d5d3bade6 Reviewed-by: Tobias Hunger <tobias.hunger@nokia.com>
Diffstat (limited to 'src')
-rw-r--r--src/plugins/git/commitdata.cpp211
-rw-r--r--src/plugins/git/commitdata.h38
-rw-r--r--src/plugins/git/gitclient.cpp169
-rw-r--r--src/plugins/git/gitclient.h8
-rw-r--r--src/plugins/git/gitplugin.cpp18
-rw-r--r--src/plugins/git/gitplugin.h2
-rw-r--r--src/plugins/git/gitsubmiteditor.cpp46
-rw-r--r--src/plugins/vcsbase/submitfilemodel.cpp50
-rw-r--r--src/plugins/vcsbase/submitfilemodel.h5
9 files changed, 272 insertions, 275 deletions
diff --git a/src/plugins/git/commitdata.cpp b/src/plugins/git/commitdata.cpp
index 41e7c2aa89..aa9845be85 100644
--- a/src/plugins/git/commitdata.cpp
+++ b/src/plugins/git/commitdata.cpp
@@ -33,11 +33,10 @@
#include "commitdata.h"
#include <utils/qtcassert.h>
+#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
#include <QtCore/QRegExp>
-const char *const kBranchIndicatorC = "# On branch";
-
namespace Git {
namespace Internal {
@@ -87,151 +86,121 @@ void CommitData::clear()
panelData.clear();
amendSHA1.clear();
- stagedFiles.clear();
- unstagedFiles.clear();
- untrackedFiles.clear();
+ files.clear();
}
-// Split a state/file spec from git status output
-// '#<tab>modified:<blanks>git .pro'
-// into state and file ('modified', 'git .pro').
-CommitData::StateFilePair splitStateFileSpecification(const QString &line)
+static CommitData::FileState stateFor(const QChar &c)
{
- QPair<QString, QString> rc;
- const int statePos = 2;
- const int colonIndex = line.indexOf(QLatin1Char(':'), statePos);
- if (colonIndex == -1)
- return rc;
- rc.first = line.mid(statePos, colonIndex - statePos);
- int filePos = colonIndex + 1;
- const QChar blank = QLatin1Char(' ');
- while (line.at(filePos) == blank)
- filePos++;
- if (filePos < line.size())
- rc.second = line.mid(filePos, line.size() - filePos);
- return rc;
+ switch (c.unicode()) {
+ case ' ':
+ return CommitData::UntrackedFile;
+ case 'M':
+ return CommitData::ModifiedFile;
+ case 'A':
+ return CommitData::AddedFile;
+ case 'D':
+ return CommitData::DeletedFile;
+ case 'R':
+ return CommitData::RenamedFile;
+ case 'C':
+ return CommitData::CopiedFile;
+ case 'U':
+ return CommitData::UpdatedFile;
+ default:
+ return CommitData::UnknownFileState;
+ }
}
-// Convenience to add a state/file spec to a list
-static inline bool addStateFileSpecification(const QString &line, QList<CommitData::StateFilePair> *list)
+static bool checkLine(const QString &stateInfo, const QString &file, QList<CommitData::StateFilePair> *files)
{
- const CommitData::StateFilePair sf = splitStateFileSpecification(line);
- if (sf.first.isEmpty() || sf.second.isEmpty())
+ Q_ASSERT(stateInfo.count() == 2);
+ Q_ASSERT(files);
+
+ if (stateInfo == "??") {
+ files->append(qMakePair(CommitData::UntrackedFile, file));
+ return true;
+ }
+
+ CommitData::FileState stagedState = stateFor(stateInfo.at(0));
+ if (stagedState == CommitData::UnknownFileState)
+ return false;
+
+ stagedState = static_cast<CommitData::FileState>(stagedState | CommitData::StagedFile);
+ if (stagedState != CommitData::StagedFile)
+ files->append(qMakePair(stagedState, file));
+
+ CommitData::FileState state = stateFor(stateInfo.at(1));
+ if (state == CommitData::UnknownFileState)
return false;
- list->push_back(sf);
+
+ if (state != CommitData::UntrackedFile) {
+ QString newFile = file;
+ if (stagedState == CommitData::RenamedStagedFile || stagedState == CommitData::CopiedStagedFile)
+ newFile = file.mid(file.indexOf(QLatin1String(" -> ")) + 4);
+
+ files->append(qMakePair(state, newFile));
+ }
+
return true;
}
/* Parse a git status file list:
* \code
- # Changes to be committed:
- #<tab>modified:<blanks>git.pro
- # Changed but not updated:
- #<tab>modified:<blanks>git.pro
- # Untracked files:
- #<tab>git.pro
- \endcode
-*/
-
-bool CommitData::filesEmpty() const
-{
- return stagedFiles.empty() && unstagedFiles.empty() && untrackedFiles.empty();
-}
-
+ ## branch_name
+ XY file
+ \endcode */
bool CommitData::parseFilesFromStatus(const QString &output)
{
- enum State { None, CommitFiles, NotUpdatedFiles, UntrackedFiles };
-
const QStringList lines = output.split(QLatin1Char('\n'));
- const QString branchIndicator = QLatin1String(kBranchIndicatorC);
- const QString commitIndicator = QLatin1String("# Changes to be committed:");
- const QString notUpdatedIndicator = QLatin1String("# Changed but not updated:");
- const QString notUpdatedIndicatorGit174 = QLatin1String("# Changes not staged for commit:");
- const QString untrackedIndicator = QLatin1String("# Untracked files:");
-
- State s = None;
- // Match added/changed-not-updated files: "#<tab>modified: foo.cpp"
- QRegExp filesPattern(QLatin1String("#\\t[^:]+:\\s+.+"));
- QTC_ASSERT(filesPattern.isValid(), return false);
-
- const QStringList::const_iterator cend = lines.constEnd();
- for (QStringList::const_iterator it = lines.constBegin(); it != cend; ++it) {
- QString line = *it;
- if (line.startsWith(branchIndicator)) {
- panelInfo.branch = line.mid(branchIndicator.size() + 1);
- continue;
- }
- if (line.startsWith(commitIndicator)) {
- s = CommitFiles;
- continue;
- }
- if (line.startsWith(notUpdatedIndicator) || line.startsWith(notUpdatedIndicatorGit174)) {
- s = NotUpdatedFiles;
+
+ foreach (const QString &line, lines) {
+ if (line.isEmpty())
continue;
- }
- if (line.startsWith(untrackedIndicator)) {
- // Now match untracked: "#<tab>foo.cpp"
- s = UntrackedFiles;
- filesPattern = QRegExp(QLatin1String("#\\t.+"));
- QTC_ASSERT(filesPattern.isValid(), return false);
+
+ if (line.startsWith("## ")) {
+ // Branch indication:
+ panelInfo.branch = line.mid(3);
continue;
}
- if (filesPattern.exactMatch(line)) {
- switch (s) {
- case CommitFiles:
- addStateFileSpecification(line, &stagedFiles);
- break;
- case NotUpdatedFiles:
- // skip submodules:
- if (line.endsWith(QLatin1String(" (modified content)"))
- || line.endsWith(" (new commits)"))
- line = line.left(line.lastIndexOf(QLatin1Char('(')) - 1);
- addStateFileSpecification(line, &unstagedFiles);
- break;
- case UntrackedFiles:
- untrackedFiles.push_back(line.mid(2).trimmed());
- break;
- case None:
- break;
- }
- }
+ QTC_ASSERT(line.at(2) == ' ', continue);
+ if (!checkLine(line.mid(0, 2), line.mid(3), &files))
+ return false;
}
- return true;
-}
-
-// Convert a spec pair list to a list of file names, optionally
-// filter for a state
-static QStringList specToFileNames(const QList<CommitData::StateFilePair> &files,
- const QString &stateFilter)
-{
- typedef QList<CommitData::StateFilePair>::const_iterator ConstIterator;
- if (files.empty())
- return QStringList();
- const bool emptyFilter = stateFilter.isEmpty();
- QStringList rc;
- const ConstIterator cend = files.constEnd();
- for (ConstIterator it = files.constBegin(); it != cend; ++it)
- if (emptyFilter || stateFilter == it->first)
- rc.push_back(it->second);
- return rc;
-}
-QStringList CommitData::stagedFileNames(const QString &stateFilter) const
-{
- return specToFileNames(stagedFiles, stateFilter);
+ return true;
}
-QStringList CommitData::unstagedFileNames(const QString &stateFilter) const
+QStringList CommitData::filterFiles(const CommitData::FileState &state) const
{
- return specToFileNames(unstagedFiles, stateFilter);
+ QStringList result;
+ foreach (const StateFilePair &p, files) {
+ if (state == AllStates || state == p.first)
+ result.append(p.second);
+ }
+ return result;
}
-QDebug operator<<(QDebug d, const CommitData &data)
+QString CommitData::stateDisplayName(const FileState &state)
{
- d << data.panelInfo << data.panelData;
- d.nospace() << "Commit: " << data.stagedFiles << " Not updated: "
- << data.unstagedFiles << " Untracked: " << data.untrackedFiles;
- return d;
+ QString resultState;
+ if (state == UntrackedFile)
+ return QCoreApplication::translate("Git::Internal::CommitData", "untracked");
+
+ if (state & StagedFile)
+ resultState = QCoreApplication::translate("Git::Internal::CommitData", "staged + ");
+ if (state & ModifiedFile)
+ resultState.append(QCoreApplication::translate("Git::Internal::CommitData", "modified"));
+ else if (state & AddedFile)
+ resultState.append(QCoreApplication::translate("Git::Internal::CommitData", "added"));
+ else if (state & DeletedFile)
+ resultState.append(QCoreApplication::translate("Git::Internal::CommitData", "deleted"));
+ else if (state & RenamedFile)
+ resultState.append(QCoreApplication::translate("Git::Internal::CommitData", "renamed"));
+ else if (state & CopiedFile)
+ resultState.append(QCoreApplication::translate("Git::Internal::CommitData", "copied"));
+ else if (state & UpdatedFile)
+ resultState.append(QCoreApplication::translate("Git::Internal::CommitData", "updated"));
+ return resultState;
}
} // namespace Internal
diff --git a/src/plugins/git/commitdata.h b/src/plugins/git/commitdata.h
index b31bf73c2f..e76f1e1b52 100644
--- a/src/plugins/git/commitdata.h
+++ b/src/plugins/git/commitdata.h
@@ -69,34 +69,50 @@ QDebug operator<<(QDebug d, const GitSubmitEditorPanelData &);
class CommitData
{
public:
+ enum FileState {
+ UntrackedFile = 0,
+
+ StagedFile = 1,
+ ModifiedFile = 2,
+ AddedFile = 3,
+ DeletedFile = 4,
+ RenamedFile = 8,
+ CopiedFile = 16,
+ UpdatedFile = 32,
+
+ ModifiedStagedFile = StagedFile | ModifiedFile,
+ AddedStagedFile = StagedFile | AddedFile,
+ DeletedStagedFile = StagedFile | DeletedFile,
+ RenamedStagedFile = StagedFile | RenamedFile,
+ CopiedStagedFile = StagedFile | CopiedFile,
+ UpdatedStagedFile = StagedFile | UpdatedFile,
+
+ AllStates = UpdatedFile | CopiedFile | RenamedFile | DeletedFile | AddedFile | ModifiedFile | StagedFile,
+ UnknownFileState
+ };
+
// A pair of state string/file name ('modified', 'file.cpp').
- typedef QPair<QString, QString> StateFilePair;
+ typedef QPair<FileState, QString> StateFilePair;
void clear();
// Parse the files and the branch of panelInfo
// from a git status output
bool parseFilesFromStatus(const QString &output);
- bool filesEmpty() const;
-
// Convenience to retrieve the file names from
// the specification list. Optionally filter for a certain state
- QStringList stagedFileNames(const QString &stateFilter = QString()) const;
- QStringList unstagedFileNames(const QString &stateFilter = QString()) const;
+ QStringList filterFiles(const FileState &state = AllStates) const;
+
+ static QString stateDisplayName(const FileState &state);
QString amendSHA1;
QString commitEncoding;
GitSubmitEditorPanelInfo panelInfo;
GitSubmitEditorPanelData panelData;
- QList<StateFilePair> stagedFiles;
- QList<StateFilePair> unstagedFiles;
- QStringList untrackedFiles;
+ QList<StateFilePair> files;
};
-QDebug operator<<(QDebug d, const CommitData &);
-
-
} // namespace Internal
} // namespace Git
diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp
index c90fc6dce5..687fce8abe 100644
--- a/src/plugins/git/gitclient.cpp
+++ b/src/plugins/git/gitclient.cpp
@@ -39,6 +39,8 @@
#include "gitsubmiteditor.h"
#include "gitversioncontrol.h"
+#include <vcsbase/submitfilemodel.h>
+
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/editormanager/editormanager.h>
@@ -75,8 +77,7 @@
#include <QtGui/QToolButton>
#include <QtCore/QTextCodec>
-static const char kGitDirectoryC[] = ".git";
-static const char kBranchIndicatorC[] = "# On branch";
+static const char GIT_DIRECTORY[] = ".git";
namespace Git {
namespace Internal {
@@ -323,7 +324,7 @@ const char *GitClient::decorateOption = "--decorate";
QString GitClient::findRepositoryForDirectory(const QString &dir)
{
// Check for ".git/config"
- const QString checkFile = QLatin1String(kGitDirectoryC) + QLatin1String("/config");
+ const QString checkFile = QLatin1String(GIT_DIRECTORY) + QLatin1String("/config");
return VCSBase::VCSBasePlugin::findRepositoryForDirectory(dir, checkFile);
}
@@ -1415,28 +1416,29 @@ static inline QString trimFileSpecification(QString fileSpec)
return fileSpec;
}
-GitClient::StatusResult GitClient::gitStatus(const QString &workingDirectory,
- bool untracked,
- QString *output,
- QString *errorMessage,
- bool *onBranch)
+GitClient::StatusResult GitClient::gitStatus(const QString &workingDirectory, bool untracked,
+ QString *output, QString *errorMessage, bool *onBranch)
{
// Run 'status'. Note that git returns exitcode 1 if there are no added files.
QByteArray outputText;
QByteArray errorText;
- // @TODO: Use "--no-color" once it is supported
+
QStringList statusArgs(QLatin1String("status"));
if (untracked)
statusArgs << QLatin1String("-u");
+ statusArgs << QLatin1String("-s") << QLatin1String("-b");
+
const bool statusRc = fullySynchronousGit(workingDirectory, statusArgs, &outputText, &errorText);
- VCSBase::Command::removeColorCodes(&outputText);
if (output)
*output = commandOutputFromLocal8Bit(outputText);
- const bool branchKnown = outputText.contains(kBranchIndicatorC);
+
+ static const char * NO_BRANCH = "## HEAD (no branch)\n";
+
+ const bool branchKnown = !outputText.startsWith(NO_BRANCH);
if (onBranch)
*onBranch = branchKnown;
// Is it something really fatal?
- if (!statusRc && !branchKnown && !outputText.contains("# Not currently on any branch.")) {
+ if (!statusRc && !branchKnown) {
if (errorMessage) {
const QString error = commandOutputFromLocal8Bit(errorText);
*errorMessage = tr("Cannot obtain status: %1").arg(error);
@@ -1444,10 +1446,8 @@ GitClient::StatusResult GitClient::gitStatus(const QString &workingDirectory,
return StatusFailed;
}
// Unchanged (output text depending on whether -u was passed)
- if (outputText.contains("nothing to commit"))
+ if (outputText.count('\n') == 1)
return StatusUnchanged;
- if (outputText.contains("nothing added to commit but untracked files present"))
- return untracked ? StatusChanged : StatusUnchanged;
return StatusChanged;
}
@@ -1570,7 +1570,7 @@ bool GitClient::getCommitData(const QString &workingDirectory,
commitData->panelInfo.repository = repoDirectory;
QDir gitDir(repoDirectory);
- if (!gitDir.cd(QLatin1String(kGitDirectoryC))) {
+ if (!gitDir.cd(QLatin1String(GIT_DIRECTORY))) {
*errorMessage = tr("The repository \"%1\" is not initialized.").arg(repoDirectory);
return false;
}
@@ -1605,33 +1605,31 @@ bool GitClient::getCommitData(const QString &workingDirectory,
}
// Output looks like:
- // # On branch [branchname]
- // # Changes to be committed:
- // # (use "git reset HEAD <file>..." to unstage)
- // #
- // # modified: somefile.cpp
- // # new File: somenew.h
- // #
- // # Changed but not updated:
- // # (use "git add <file>..." to update what will be committed)
- // #
- // # modified: someother.cpp
- // # modified: submodule (modified content)
- // # modified: submodule2 (new commit)
- // #
- // # Untracked files:
- // # (use "git add <file>..." to include in what will be committed)
- // #
- // # list of files...
-
+ // ## branch_name
+ // MM filename
+ // A new_unstaged_file
+ // R old -> new
+ // ?? missing_file
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()) {
+ QStringList untrackedFiles = commitData->filterFiles(CommitData::UntrackedFile);
+
+ VCSBase::VCSBaseSubmitEditor::filterUntrackedFilesOfProject(repoDirectory, &untrackedFiles);
+ QList<CommitData::StateFilePair> filteredFiles;
+ QList<CommitData::StateFilePair>::const_iterator it = commitData->files.constBegin();
+ for ( ; it != commitData->files.constEnd(); ++it) {
+ if (it->first == CommitData::UntrackedFile && !untrackedFiles.contains(it->second))
+ continue;
+ filteredFiles.append(*it);
+ }
+ commitData->files = filteredFiles;
+
+ if (commitData->files.isEmpty()) {
*errorMessage = msgNoChangedFiles();
return false;
}
@@ -1683,46 +1681,74 @@ static inline QString msgCommitted(const QString &amendSHA1, int fileCount)
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,
- const QStringList &origDeletedFiles)
+ VCSBase::SubmitFileModel *model)
{
- const QString renamedSeparator = QLatin1String(" -> ");
+ const QString renameSeparator = 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)
- // Split up renamed files ('foo.cpp -> foo2.cpp').
- QStringList resetFiles = origCommitFiles.toSet().subtract(checkedFiles.toSet()).toList();
- for (QStringList::iterator it = resetFiles.begin(); it != resetFiles.end(); ++it) {
- const int renamedPos = it->indexOf(renamedSeparator);
- if (renamedPos != -1) {
- const QString newFile = it->mid(renamedPos + renamedSeparator.size());
- it->truncate(renamedPos);
- it = resetFiles.insert(++it, newFile);
+ QStringList filesToAdd;
+ QStringList filesToRemove;
+ QStringList filesToReset;
+
+ int commitCount = 0;
+
+ for (int i = 0; i < model->rowCount(); ++i) {
+ const CommitData::FileState state = static_cast<CommitData::FileState>(model->data(i).toInt());
+ QString file = model->file(i);
+ const bool checked = model->checked(i);
+
+ if (checked)
+ ++commitCount;
+
+ if (state == CommitData::UntrackedFile && checked)
+ filesToAdd.append(file);
+
+ if (state == CommitData::ModifiedStagedFile && !checked) {
+ filesToReset.append(file);
+ } else if (state == CommitData::AddedStagedFile && !checked) {
+ filesToReset.append(file);
+ } else if (state == CommitData::DeletedStagedFile && !checked) {
+ filesToReset.append(file);
+ } else if (state == CommitData::RenamedStagedFile && !checked) {
+ const int pos = file.indexOf(QLatin1String(" -> "));
+ const QString newFile = file.mid(pos + 4);
+ filesToReset.append(newFile);
+ } else if (state == CommitData::CopiedStagedFile && !checked) {
+ const QString newFile = file.mid(file.indexOf(renameSeparator) + renameSeparator.count());
+ filesToReset.append(newFile);
+ } else if (state == CommitData::UpdatedStagedFile && !checked) {
+ QTC_ASSERT(false, continue); // There should not be updated files when commiting!
+ }
+
+ if (state == CommitData::ModifiedFile && checked) {
+ filesToReset.removeAll(file);
+ filesToAdd.append(file);
+ } else if (state == CommitData::AddedFile && checked) {
+ QTC_ASSERT(false, continue); // these should be untracked!
+ } else if (state == CommitData::DeletedFile && checked) {
+ filesToReset.removeAll(file);
+ filesToRemove.append(file);
+ } else if (state == CommitData::RenamedFile && checked) {
+ QTC_ASSERT(false, continue); // git mv directly stages.
+ } else if (state == CommitData::CopiedFile && checked) {
+ QTC_ASSERT(false, continue); // only is noticed after adding a new file to the index
+ } else if (state == CommitData::UpdatedFile && checked) {
+ QTC_ASSERT(false, continue); // There should not be updated files when commiting!
}
}
- if (!resetFiles.isEmpty())
- if (!synchronousReset(repositoryDirectory, resetFiles))
- return false;
+ if (!filesToReset.isEmpty() && !synchronousReset(repositoryDirectory, filesToReset))
+ return false;
- // Re-add all to make sure we have the latest changes, but only add those that aren't marked
- // for deletion. Purge out renamed files ('foo.cpp -> foo2.cpp').
- QStringList addFiles = checkedFiles.toSet().subtract(origDeletedFiles.toSet()).toList();
- for (QStringList::iterator it = addFiles.begin(); it != addFiles.end(); ) {
- if (it->contains(renamedSeparator))
- it = addFiles.erase(it);
- else
- ++it;
- }
- if (!addFiles.isEmpty() && !synchronousAdd(repositoryDirectory, false, addFiles))
- return false;
+ if (!filesToRemove.isEmpty() && !synchronousDelete(repositoryDirectory, true, filesToRemove))
+ return false;
+
+ if (!filesToAdd.isEmpty() && !synchronousAdd(repositoryDirectory, false, filesToAdd))
+ return false;
// Do the final commit
QStringList args;
@@ -1736,11 +1762,13 @@ bool GitClient::addAndCommit(const QString &repositoryDirectory,
QByteArray outputText;
QByteArray errorText;
+
const bool rc = fullySynchronousGit(repositoryDirectory, args, &outputText, &errorText);
if (rc)
- outputWindow()->append(msgCommitted(amendSHA1, checkedFiles.size()));
+ outputWindow()->append(msgCommitted(amendSHA1, commitCount));
else
- outputWindow()->appendError(tr("Cannot commit %n file(s): %1\n", 0, checkedFiles.size()).arg(commandOutputFromLocal8Bit(errorText)));
+ outputWindow()->appendError(tr("Cannot commit %n file(s): %1\n", 0, commitCount).arg(commandOutputFromLocal8Bit(errorText)));
+
return rc;
}
@@ -1796,9 +1824,8 @@ GitClient::RevertResult GitClient::revertI(QStringList files,
}
// From the status output, determine all modified [un]staged files.
- const QString modifiedState = QLatin1String("modified");
- const QStringList allStagedFiles = data.stagedFileNames(modifiedState);
- const QStringList allUnstagedFiles = data.unstagedFileNames(modifiedState);
+ const QStringList allStagedFiles = data.filterFiles(CommitData::ModifiedStagedFile);
+ const QStringList allUnstagedFiles = data.filterFiles(CommitData::ModifiedFile);
// Unless a directory was passed, filter all modified files for the
// argument file list.
QStringList stagedFiles = allStagedFiles;
diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h
index f4520e215a..fff6aa6b0b 100644
--- a/src/plugins/git/gitclient.h
+++ b/src/plugins/git/gitclient.h
@@ -57,6 +57,7 @@ namespace Core {
namespace VCSBase {
class VCSBaseEditorWidget;
+ class SubmitFileModel;
}
namespace Utils {
@@ -204,16 +205,13 @@ public:
const GitSubmitEditorPanelData &data,
const QString &amendSHA1,
const QString &messageFile,
- const QStringList &checkedFiles,
- const QStringList &origCommitFiles,
- const QStringList &origDeletedFiles);
+ VCSBase::SubmitFileModel *model);
enum StatusResult { StatusChanged, StatusUnchanged, StatusFailed };
StatusResult gitStatus(const QString &workingDirectory,
bool untracked = false,
QString *output = 0,
- QString *errorMessage = 0,
- bool *onBranch = 0);
+ QString *errorMessage = 0, bool *onBranch = 0);
void launchGitK(const QString &workingDirectory);
QStringList synchronousRepositoryBranches(const QString &repositoryURL);
diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp
index b98dfe6ea8..7ff41b4b98 100644
--- a/src/plugins/git/gitplugin.cpp
+++ b/src/plugins/git/gitplugin.cpp
@@ -63,6 +63,7 @@
#include <utils/fileutils.h>
#include <vcsbase/basevcseditorfactory.h>
+#include <vcsbase/submitfilemodel.h>
#include <vcsbase/vcsbaseeditor.h>
#include <vcsbase/basevcssubmiteditorfactory.h>
#include <vcsbase/vcsbaseoutputwindow.h>
@@ -695,8 +696,6 @@ void GitPlugin::startCommit(bool amend)
// 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");
// Start new temp file with message template
Utils::TempFileSaver saver;
@@ -772,21 +771,18 @@ bool GitPlugin::submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEdi
default:
break;
}
+
+
// Go ahead!
- const QStringList fileList = editor->checkedFiles();
+ VCSBase::SubmitFileModel *model = qobject_cast<VCSBase::SubmitFileModel *>(editor->fileModel());
bool closeEditor = true;
- if (!fileList.empty() || !m_commitAmendSHA1.isEmpty()) {
+ if (model->hasCheckedFiles() || !m_commitAmendSHA1.isEmpty()) {
// get message & commit
if (!m_core->fileManager()->saveFile(fileIFace))
return false;
- closeEditor = m_gitClient->addAndCommit(m_submitRepository,
- editor->panelData(),
- m_commitAmendSHA1,
- m_commitMessageFileName,
- fileList,
- m_submitOrigCommitFiles,
- m_submitOrigDeleteFiles);
+ closeEditor = m_gitClient->addAndCommit(m_submitRepository, editor->panelData(),
+ m_commitAmendSHA1, m_commitMessageFileName, model);
}
if (closeEditor)
cleanCommitMessageFile();
diff --git a/src/plugins/git/gitplugin.h b/src/plugins/git/gitplugin.h
index 5e45dd14c5..658c299c5b 100644
--- a/src/plugins/git/gitplugin.h
+++ b/src/plugins/git/gitplugin.h
@@ -206,8 +206,6 @@ private:
QPointer<BranchDialog> m_branchDialog;
QPointer<RemoteDialog> m_remoteDialog;
QString m_submitRepository;
- 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 34a96db285..9bb879b7ae 100644
--- a/src/plugins/git/gitsubmiteditor.cpp
+++ b/src/plugins/git/gitsubmiteditor.cpp
@@ -44,9 +44,6 @@
namespace Git {
namespace Internal {
-enum { FileTypeRole = Qt::UserRole + 1 };
-enum FileType { StagedFile , UnstagedFile, UntrackedFile };
-
/* The problem with git is that no diff can be obtained to for a random
* multiselection of staged/unstaged files; it requires the --cached
* option for staged files. So, we sort apart the diff file lists
@@ -64,21 +61,6 @@ GitSubmitEditorWidget *GitSubmitEditor::submitEditorWidget()
return static_cast<GitSubmitEditorWidget *>(widget());
}
-// Utility to add a list of state/file pairs to the model
-// setting a file type.
-static void addStateFileListToModel(const QList<CommitData::StateFilePair> &l,
- bool checked, FileType ft,
- VCSBase::SubmitFileModel *model)
-{
- typedef QList<CommitData::StateFilePair>::const_iterator ConstIterator;
- if (!l.empty()) {
- const ConstIterator cend = l.constEnd();
- const QVariant fileTypeData(ft);
- for (ConstIterator it = l.constBegin(); it != cend; ++it)
- model->addFile(it->second, it->first, checked).front()->setData(fileTypeData, FileTypeRole);
- }
-}
-
void GitSubmitEditor::setCommitData(const CommitData &d)
{
submitEditorWidget()->setPanelData(d.panelData);
@@ -87,14 +69,14 @@ void GitSubmitEditor::setCommitData(const CommitData &d)
m_commitEncoding = d.commitEncoding;
m_model = new VCSBase::SubmitFileModel(this);
- addStateFileListToModel(d.stagedFiles, true, StagedFile, m_model);
- addStateFileListToModel(d.unstagedFiles, false, UnstagedFile, m_model);
- if (!d.untrackedFiles.empty()) {
- const QString untrackedSpec = QLatin1String("untracked");
- const QVariant fileTypeData(UntrackedFile);
- const QStringList::const_iterator cend = d.untrackedFiles.constEnd();
- for (QStringList::const_iterator it = d.untrackedFiles.constBegin(); it != cend; ++it)
- m_model->addFile(*it, untrackedSpec, false).front()->setData(fileTypeData, FileTypeRole);
+ if (!d.files.isEmpty()) {
+ for (QList<CommitData::StateFilePair>::const_iterator it = d.files.constBegin();
+ it != d.files.constEnd(); ++it) {
+ const CommitData::FileState state = it->first;
+ const QString file = it->second;
+ m_model->addFile(file, CommitData::stateDisplayName(state), state & CommitData::StagedFile,
+ QVariant(static_cast<int>(state)));
+ }
}
setFileModel(m_model);
}
@@ -109,17 +91,11 @@ void GitSubmitEditor::slotDiffSelected(const QStringList &files)
for (int r = 0; r < rowCount; r++) {
const QString fileName = m_model->item(r, fileColumn)->text();
if (files.contains(fileName)) {
- const FileType ft = static_cast<FileType>(m_model->item(r, 0)->data(FileTypeRole).toInt());
- switch (ft) {
- case StagedFile:
+ const CommitData::FileState state = static_cast<CommitData::FileState>(m_model->data(r).toInt());
+ if (state & CommitData::StagedFile)
stagedFiles.push_back(fileName);
- break;
- case UnstagedFile:
+ else if (state != CommitData::UntrackedFile)
unstagedFiles.push_back(fileName);
- break;
- case UntrackedFile:
- break;
- }
}
}
if (!unstagedFiles.empty() || !stagedFiles.empty())
diff --git a/src/plugins/vcsbase/submitfilemodel.cpp b/src/plugins/vcsbase/submitfilemodel.cpp
index a35b23e2d0..45195dba89 100644
--- a/src/plugins/vcsbase/submitfilemodel.cpp
+++ b/src/plugins/vcsbase/submitfilemodel.cpp
@@ -38,6 +38,29 @@
namespace VCSBase {
+// --------------------------------------------------------------------------
+// Helpers:
+// --------------------------------------------------------------------------
+
+static QList<QStandardItem *> createFileRow(const QString &fileName, const QString &status,
+ bool checked, const QVariant &v)
+{
+ QStandardItem *statusItem = new QStandardItem(status);
+ statusItem->setCheckable(true);
+ statusItem->setCheckState(checked ? Qt::Checked : Qt::Unchecked);
+ statusItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsUserCheckable|Qt::ItemIsEnabled);
+ statusItem->setData(v);
+ QStandardItem *fileItem = new QStandardItem(fileName);
+ fileItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
+ QList<QStandardItem *> row;
+ row << statusItem << fileItem;
+ return row;
+}
+
+// --------------------------------------------------------------------------
+// SubmitFileModel:
+// --------------------------------------------------------------------------
+
/*!
\class VCSBase::SubmitFileModel
@@ -54,24 +77,10 @@ SubmitFileModel::SubmitFileModel(QObject *parent) :
setHorizontalHeaderLabels(headerLabels);
}
-QList<QStandardItem *> SubmitFileModel::createFileRow(const QString &fileName, const QString &status, bool checked)
-{
- if (VCSBase::Constants::Internal::debug)
- qDebug() << Q_FUNC_INFO << fileName << status << checked;
- QStandardItem *statusItem = new QStandardItem(status);
- statusItem->setCheckable(true);
- statusItem->setCheckState(checked ? Qt::Checked : Qt::Unchecked);
- statusItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsUserCheckable|Qt::ItemIsEnabled);
- QStandardItem *fileItem = new QStandardItem(fileName);
- fileItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
- QList<QStandardItem *> row;
- row << statusItem << fileItem;
- return row;
-}
-
-QList<QStandardItem *> SubmitFileModel::addFile(const QString &fileName, const QString &status, bool checked)
+QList<QStandardItem *> SubmitFileModel::addFile(const QString &fileName, const QString &status, bool checked,
+ const QVariant &v)
{
- const QList<QStandardItem *> row = createFileRow(fileName, status, checked);
+ const QList<QStandardItem *> row = createFileRow(fileName, status, checked, v);
appendRow(row);
return row;
}
@@ -106,6 +115,13 @@ bool SubmitFileModel::checked(int row) const
return (item(row)->checkState() == Qt::Checked);
}
+QVariant SubmitFileModel::data(int row) const
+{
+ if (row < 0 || row >= rowCount())
+ return false;
+ return item(row)->data();
+}
+
bool SubmitFileModel::hasCheckedFiles() const
{
for (int i = 0; i < rowCount(); ++i) {
diff --git a/src/plugins/vcsbase/submitfilemodel.h b/src/plugins/vcsbase/submitfilemodel.h
index e5049b2009..7b5f5a01e1 100644
--- a/src/plugins/vcsbase/submitfilemodel.h
+++ b/src/plugins/vcsbase/submitfilemodel.h
@@ -46,8 +46,8 @@ public:
explicit SubmitFileModel(QObject *parent = 0);
// Convenience to create and add rows containing a file plus status text.
- static QList<QStandardItem *> createFileRow(const QString &fileName, const QString &status = QString(), bool checked = true);
- QList<QStandardItem *> addFile(const QString &fileName, const QString &status = QString(), bool checked = true);
+ QList<QStandardItem *> addFile(const QString &fileName, const QString &status = QString(),
+ bool checked = true, const QVariant &data = QVariant());
// Find convenience that returns the whole row (as opposed to QStandardItemModel::find).
QList<QStandardItem *> findRow(const QString &text, int column = 0) const;
@@ -58,6 +58,7 @@ public:
QString state(int row) const;
QString file(int row) const;
bool checked(int row) const;
+ QVariant data(int row) const;
bool hasCheckedFiles() const;