Git: Support staging a single chunk.

Add context menu in diff editor to stage/unstage a single chunk from the diff.

Task-number: QTCREATORBUG-5875
Change-Id: Ic244a0d84b5ed5f66b90d7fe8784fc1b8041d183
Reviewed-by: Orgad Shaneh <orgads@gmail.com>
Reviewed-by: Tobias Hunger <tobias.hunger@digia.com>
This commit is contained in:
Francois Ferrand
2013-09-24 14:44:22 +02:00
committed by Orgad Shaneh
parent c372f7b601
commit 367cfc8419
6 changed files with 99 additions and 9 deletions

View File

@@ -1115,6 +1115,8 @@ void GitClient::diff(const QString &workingDirectory,
workingDirectory,
argWidget);
newEditor = vcsEditor->editor();
connect(vcsEditor, SIGNAL(diffChunkApplied(VcsBase::DiffChunk)),
argWidget, SLOT(executeCommand()));
connect(vcsEditor, SIGNAL(diffChunkReverted(VcsBase::DiffChunk)),
argWidget, SLOT(executeCommand()));
}
@@ -1222,6 +1224,8 @@ void GitClient::diff(const QString &workingDirectory,
sourceFile,
argWidget);
newEditor = vcsEditor->editor();
connect(vcsEditor, SIGNAL(diffChunkApplied(VcsBase::DiffChunk)),
argWidget, SLOT(executeCommand()));
connect(vcsEditor, SIGNAL(diffChunkReverted(VcsBase::DiffChunk)),
argWidget, SLOT(executeCommand()));
}
@@ -2433,10 +2437,11 @@ bool GitClient::synchronousCleanList(const QString &workingDirectory, QStringLis
}
bool GitClient::synchronousApplyPatch(const QString &workingDirectory,
const QString &file, QString *errorMessage)
const QString &file, QString *errorMessage,
const QStringList &arguments)
{
QStringList args;
args << QLatin1String("apply") << QLatin1String("--whitespace=fix") << file;
args << QLatin1String("apply") << QLatin1String("--whitespace=fix") << arguments << file;
QByteArray outputText;
QByteArray errorText;
const bool rc = fullySynchronousGit(workingDirectory, args, &outputText, &errorText);

View File

@@ -182,7 +182,7 @@ public:
const QStringList &files = QStringList(),
QString *errorMessage = 0);
bool synchronousCleanList(const QString &workingDirectory, QStringList *files, QStringList *ignoredFiles, QString *errorMessage);
bool synchronousApplyPatch(const QString &workingDirectory, const QString &file, QString *errorMessage);
bool synchronousApplyPatch(const QString &workingDirectory, const QString &file, QString *errorMessage, const QStringList &arguments = QStringList());
bool synchronousInit(const QString &workingDirectory);
bool synchronousCheckoutFiles(const QString &workingDirectory,
QStringList files = QStringList(),

View File

@@ -44,9 +44,12 @@
#include <QFileInfo>
#include <QRegExp>
#include <QSet>
#include <QTemporaryFile>
#include <QDir>
#include <QTextCursor>
#include <QTextBlock>
#include <QMessageBox>
#define CHANGE_PATTERN "[a-f0-9]{7,40}"
@@ -223,6 +226,53 @@ void GitEditor::revertChange()
GitPlugin::instance()->gitClient()->synchronousRevert(workingDirectory, m_currentChange);
}
void GitEditor::stageDiffChunk()
{
const QAction *a = qobject_cast<QAction *>(sender());
QTC_ASSERT(a, return);
const VcsBase::DiffChunk chunk = qvariant_cast<VcsBase::DiffChunk>(a->data());
return applyDiffChunk(chunk, false);
}
void GitEditor::unstageDiffChunk()
{
const QAction *a = qobject_cast<QAction *>(sender());
QTC_ASSERT(a, return);
const VcsBase::DiffChunk chunk = qvariant_cast<VcsBase::DiffChunk>(a->data());
return applyDiffChunk(chunk, true);
}
void GitEditor::applyDiffChunk(const VcsBase::DiffChunk& chunk, bool revert)
{
VcsBase::VcsBaseOutputWindow *outwin = VcsBase::VcsBaseOutputWindow::instance();
QTemporaryFile patchFile;
if (!patchFile.open())
return;
const QString baseDir = diffBaseDirectory();
patchFile.write(chunk.header);
patchFile.write(chunk.chunk);
patchFile.close();
GitClient *client = GitPlugin::instance()->gitClient();
QStringList args = QStringList() << QLatin1String("--cached");
if (revert)
args << QLatin1String("--reverse");
QString errorMessage;
if (client->synchronousApplyPatch(baseDir, patchFile.fileName(), &errorMessage, args)) {
if (errorMessage.isEmpty())
outwin->append(tr("Chunk successfully staged"));
else
outwin->append(errorMessage);
if (revert)
emit diffChunkReverted(chunk);
else
emit diffChunkApplied(chunk);
} else {
outwin->appendError(errorMessage);
}
}
void GitEditor::init()
{
VcsBase::VcsBaseEditorWidget::init();
@@ -233,6 +283,19 @@ void GitEditor::init()
new GitRebaseHighlighter(baseTextDocument().data());
}
void GitEditor::addDiffActions(QMenu *menu, const VcsBase::DiffChunk &chunk)
{
menu->addSeparator();
QAction *stageAction = menu->addAction(tr("Stage Chunk..."));
stageAction->setData(qVariantFromValue(chunk));
connect(stageAction, SIGNAL(triggered()), this, SLOT(stageDiffChunk()));
QAction *unstageAction = menu->addAction(tr("Unstage Chunk..."));
unstageAction->setData(qVariantFromValue(chunk));
connect(unstageAction, SIGNAL(triggered()), this, SLOT(unstageDiffChunk()));
}
bool GitEditor::open(QString *errorString, const QString &fileName, const QString &realFileName)
{
bool res = VcsBaseEditorWidget::open(errorString, fileName, realFileName);

View File

@@ -57,9 +57,13 @@ public slots:
private slots:
void cherryPickChange();
void revertChange();
void stageDiffChunk();
void unstageDiffChunk();
void applyDiffChunk(const VcsBase::DiffChunk& chunk, bool revert);
private:
void init();
void addDiffActions(QMenu *menu, const VcsBase::DiffChunk &chunk);
bool open(QString *errorString, const QString &fileName, const QString &realFileName);
QSet<QString> annotationChanges() const;
QString changeUnderCursor(const QTextCursor &) const;