Commit 8695fe6d authored by Orgad Shaneh's avatar Orgad Shaneh Committed by Orgad Shaneh

Git: Implement "Fixup previous commit"

Change-Id: Ia2584ff975ed0db614dc878a70ce4adbd5c3ba67
Reviewed-by: default avatarTobias Hunger <tobias.hunger@digia.com>
parent 5d325f6b
...@@ -437,7 +437,8 @@ GitClient::GitClient(GitSettings *settings) : ...@@ -437,7 +437,8 @@ GitClient::GitClient(GitSettings *settings) :
m_cachedGitVersion(0), m_cachedGitVersion(0),
m_msgWait(tr("Waiting for data...")), m_msgWait(tr("Waiting for data...")),
m_repositoryChangedSignalMapper(0), m_repositoryChangedSignalMapper(0),
m_settings(settings) m_settings(settings),
m_disableEditor(false)
{ {
QTC_CHECK(settings); QTC_CHECK(settings);
connect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()), this, SLOT(saveSettings())); connect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()), this, SLOT(saveSettings()));
...@@ -1701,7 +1702,7 @@ QProcessEnvironment GitClient::processEnvironment() const ...@@ -1701,7 +1702,7 @@ QProcessEnvironment GitClient::processEnvironment() const
&& settings()->boolValue(GitSettings::winSetHomeEnvironmentKey)) { && settings()->boolValue(GitSettings::winSetHomeEnvironmentKey)) {
environment.insert(QLatin1String("HOME"), QDir::toNativeSeparators(QDir::homePath())); environment.insert(QLatin1String("HOME"), QDir::toNativeSeparators(QDir::homePath()));
} }
environment.insert(QLatin1String("GIT_EDITOR"), m_gitQtcEditor); environment.insert(QLatin1String("GIT_EDITOR"), m_disableEditor ? QLatin1String("true") : m_gitQtcEditor);
// Set up SSH and C locale (required by git using perl). // Set up SSH and C locale (required by git using perl).
VcsBase::VcsBasePlugin::setProcessEnvironment(&environment, false); VcsBase::VcsBasePlugin::setProcessEnvironment(&environment, false);
return environment; return environment;
...@@ -2139,6 +2140,8 @@ bool GitClient::getCommitData(const QString &workingDirectory, ...@@ -2139,6 +2140,8 @@ bool GitClient::getCommitData(const QString &workingDirectory,
} }
break; break;
} }
case FixupCommit:
break;
} }
return true; return true;
} }
...@@ -2155,12 +2158,12 @@ static inline QString msgCommitted(const QString &amendSHA1, int fileCount) ...@@ -2155,12 +2158,12 @@ static inline QString msgCommitted(const QString &amendSHA1, int fileCount)
bool GitClient::addAndCommit(const QString &repositoryDirectory, bool GitClient::addAndCommit(const QString &repositoryDirectory,
const GitSubmitEditorPanelData &data, const GitSubmitEditorPanelData &data,
CommitType commitType,
const QString &amendSHA1, const QString &amendSHA1,
const QString &messageFile, const QString &messageFile,
VcsBase::SubmitFileModel *model) VcsBase::SubmitFileModel *model)
{ {
const QString renameSeparator = QLatin1String(" -> "); const QString renameSeparator = QLatin1String(" -> ");
const bool amend = !amendSHA1.isEmpty();
QStringList filesToAdd; QStringList filesToAdd;
QStringList filesToRemove; QStringList filesToRemove;
...@@ -2218,15 +2221,19 @@ bool GitClient::addAndCommit(const QString &repositoryDirectory, ...@@ -2218,15 +2221,19 @@ bool GitClient::addAndCommit(const QString &repositoryDirectory,
// Do the final commit // Do the final commit
QStringList args; QStringList args;
args << QLatin1String("commit") args << QLatin1String("commit");
<< QLatin1String("-F") << QDir::toNativeSeparators(messageFile); if (commitType == FixupCommit) {
if (amend) args << QLatin1String("--fixup") << amendSHA1;
args << QLatin1String("--amend"); } else {
const QString &authorString = data.authorString(); args << QLatin1String("-F") << QDir::toNativeSeparators(messageFile);
if (!authorString.isEmpty()) if (commitType == AmendCommit)
args << QLatin1String("--author") << authorString; args << QLatin1String("--amend");
if (data.bypassHooks) const QString &authorString = data.authorString();
args << QLatin1String("--no-verify"); if (!authorString.isEmpty())
args << QLatin1String("--author") << authorString;
if (data.bypassHooks)
args << QLatin1String("--no-verify");
}
QByteArray outputText; QByteArray outputText;
QByteArray errorText; QByteArray errorText;
...@@ -2544,11 +2551,16 @@ bool GitClient::synchronousCherryPick(const QString &workingDirectory, const QSt ...@@ -2544,11 +2551,16 @@ bool GitClient::synchronousCherryPick(const QString &workingDirectory, const QSt
} }
void GitClient::interactiveRebase(const QString &workingDirectory, const QString &commit, void GitClient::interactiveRebase(const QString &workingDirectory, const QString &commit,
StashGuard &stashGuard) StashGuard &stashGuard, bool fixup)
{ {
QStringList arguments; QStringList arguments;
arguments << QLatin1String("rebase") << QLatin1String("-i") << commit + QLatin1Char('^'); arguments << QLatin1String("rebase") << QLatin1String("-i");
if (fixup)
arguments << QLatin1String("--autosquash");
arguments << commit + QLatin1Char('^');
outputWindow()->appendCommand(workingDirectory, settings()->stringValue(GitSettings::binaryPathKey), arguments); outputWindow()->appendCommand(workingDirectory, settings()->stringValue(GitSettings::binaryPathKey), arguments);
if (fixup)
m_disableEditor = true;
VcsBase::Command *command = createCommand(workingDirectory, 0, true); VcsBase::Command *command = createCommand(workingDirectory, 0, true);
command->addJob(arguments, -1); command->addJob(arguments, -1);
command->execute(); command->execute();
...@@ -2557,6 +2569,8 @@ void GitClient::interactiveRebase(const QString &workingDirectory, const QString ...@@ -2557,6 +2569,8 @@ void GitClient::interactiveRebase(const QString &workingDirectory, const QString
connect(command, SIGNAL(errorText(QString)), rebaseManager, SLOT(readStdErr(QString))); connect(command, SIGNAL(errorText(QString)), rebaseManager, SLOT(readStdErr(QString)));
connect(command, SIGNAL(finished(bool,int,QVariant)), connect(command, SIGNAL(finished(bool,int,QVariant)),
rebaseManager, SLOT(finished(bool,int,QVariant))); rebaseManager, SLOT(finished(bool,int,QVariant)));
if (fixup)
m_disableEditor = false;
} }
QString GitClient::msgNoChangedFiles() QString GitClient::msgNoChangedFiles()
......
...@@ -238,7 +238,7 @@ public: ...@@ -238,7 +238,7 @@ public:
bool synchronousRevert(const QString &workingDirectory, const QString &commit); bool synchronousRevert(const QString &workingDirectory, const QString &commit);
bool synchronousCherryPick(const QString &workingDirectory, const QString &commit); bool synchronousCherryPick(const QString &workingDirectory, const QString &commit);
void interactiveRebase(const QString &workingDirectory, const QString &commit, void interactiveRebase(const QString &workingDirectory, const QString &commit,
StashGuard &stashGuard); StashGuard &stashGuard, bool fixup);
void synchronousAbortCommand(const QString &workingDir, const QString &abortCommand); void synchronousAbortCommand(const QString &workingDir, const QString &abortCommand);
// git svn support (asynchronous). // git svn support (asynchronous).
...@@ -267,6 +267,7 @@ public: ...@@ -267,6 +267,7 @@ public:
bool addAndCommit(const QString &workingDirectory, bool addAndCommit(const QString &workingDirectory,
const GitSubmitEditorPanelData &data, const GitSubmitEditorPanelData &data,
CommitType commitType,
const QString &amendSHA1, const QString &amendSHA1,
const QString &messageFile, const QString &messageFile,
VcsBase::SubmitFileModel *model); VcsBase::SubmitFileModel *model);
...@@ -376,6 +377,7 @@ private: ...@@ -376,6 +377,7 @@ private:
QSignalMapper *m_repositoryChangedSignalMapper; QSignalMapper *m_repositoryChangedSignalMapper;
GitSettings *m_settings; GitSettings *m_settings;
QString m_gitQtcEditor; QString m_gitQtcEditor;
bool m_disableEditor;
}; };
} // namespace Internal } // namespace Internal
......
...@@ -424,6 +424,10 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage) ...@@ -424,6 +424,10 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage)
createRepositoryAction(localRepositoryMenu, createRepositoryAction(localRepositoryMenu,
tr("Amend Last Commit..."), Core::Id("Git.AmendCommit"), tr("Amend Last Commit..."), Core::Id("Git.AmendCommit"),
globalcontext, true, SLOT(startAmendCommit())); globalcontext, true, SLOT(startAmendCommit()));
createRepositoryAction(localRepositoryMenu,
tr("Fixup Previous Commit..."), Core::Id("Git.FixupCommit"),
globalcontext, true, SLOT(startFixupCommit()));
// -------------- // --------------
localRepositoryMenu->addSeparator(globalcontext); localRepositoryMenu->addSeparator(globalcontext);
...@@ -769,7 +773,7 @@ void GitPlugin::startRebase() ...@@ -769,7 +773,7 @@ void GitPlugin::startRebase()
return; return;
const QString change = dialog.commit(); const QString change = dialog.commit();
if (!change.isEmpty()) if (!change.isEmpty())
m_gitClient->interactiveRebase(workingDirectory, change, *stashGuard.take()); m_gitClient->interactiveRebase(workingDirectory, change, *stashGuard.take(), false);
} }
void GitPlugin::startChangeRelatedAction() void GitPlugin::startChangeRelatedAction()
...@@ -879,6 +883,11 @@ void GitPlugin::startAmendCommit() ...@@ -879,6 +883,11 @@ void GitPlugin::startAmendCommit()
startCommit(AmendCommit); startCommit(AmendCommit);
} }
void GitPlugin::startFixupCommit()
{
startCommit(FixupCommit);
}
void GitPlugin::startCommit() void GitPlugin::startCommit()
{ {
startCommit(SimpleCommit); startCommit(SimpleCommit);
...@@ -906,7 +915,6 @@ void GitPlugin::startCommit(CommitType commitType) ...@@ -906,7 +915,6 @@ void GitPlugin::startCommit(CommitType commitType)
// Store repository for diff and the original list of // Store repository for diff and the original list of
// files to be able to unstage files the user unchecks // files to be able to unstage files the user unchecks
m_submitRepository = data.panelInfo.repository; m_submitRepository = data.panelInfo.repository;
m_commitAmendSHA1 = data.amendSHA1;
// Start new temp file with message template // Start new temp file with message template
Utils::TempFileSaver saver; Utils::TempFileSaver saver;
...@@ -1009,17 +1017,29 @@ bool GitPlugin::submitEditorAboutToClose() ...@@ -1009,17 +1017,29 @@ bool GitPlugin::submitEditorAboutToClose()
// Go ahead! // Go ahead!
VcsBase::SubmitFileModel *model = qobject_cast<VcsBase::SubmitFileModel *>(editor->fileModel()); VcsBase::SubmitFileModel *model = qobject_cast<VcsBase::SubmitFileModel *>(editor->fileModel());
bool closeEditor = true; bool closeEditor = true;
if (model->hasCheckedFiles() || !m_commitAmendSHA1.isEmpty()) { CommitType commitType = editor->commitType();
QString amendSHA1 = editor->amendSHA1();
if (model->hasCheckedFiles() || !amendSHA1.isEmpty()) {
// get message & commit // get message & commit
if (!Core::DocumentManager::saveDocument(editorDocument)) if (!Core::DocumentManager::saveDocument(editorDocument))
return false; return false;
closeEditor = m_gitClient->addAndCommit(m_submitRepository, editor->panelData(), closeEditor = m_gitClient->addAndCommit(m_submitRepository, editor->panelData(),
m_commitAmendSHA1, m_commitMessageFileName, model); commitType, amendSHA1,
m_commitMessageFileName, model);
} }
if (closeEditor) { if (closeEditor) {
cleanCommitMessageFile(); cleanCommitMessageFile();
m_gitClient->continueCommandIfNeeded(m_submitRepository); if (commitType == FixupCommit) {
QScopedPointer<GitClient::StashGuard> stashGuard(
new GitClient::StashGuard(m_submitRepository, QLatin1String("Rebase-fixup"),
NoPrompt));
if (stashGuard->stashingFailed())
return false;
m_gitClient->interactiveRebase(m_submitRepository, amendSHA1, *stashGuard.take(), true);
} else {
m_gitClient->continueCommandIfNeeded(m_submitRepository);
}
} }
return closeEditor; return closeEditor;
} }
......
...@@ -131,6 +131,7 @@ private slots: ...@@ -131,6 +131,7 @@ private slots:
void gitClientMemberFuncRepositoryAction(); void gitClientMemberFuncRepositoryAction();
void startAmendCommit(); void startAmendCommit();
void startFixupCommit();
void stash(); void stash();
void stashSnapshot(); void stashSnapshot();
void branchList(); void branchList();
...@@ -231,7 +232,6 @@ private: ...@@ -231,7 +232,6 @@ private:
QPointer<RemoteDialog> m_remoteDialog; QPointer<RemoteDialog> m_remoteDialog;
QString m_submitRepository; QString m_submitRepository;
QString m_commitMessageFileName; QString m_commitMessageFileName;
QString m_commitAmendSHA1;
bool m_submitActionTriggered; bool m_submitActionTriggered;
GitSettings m_settings; GitSettings m_settings;
......
...@@ -38,7 +38,8 @@ namespace Internal { ...@@ -38,7 +38,8 @@ namespace Internal {
enum CommitType enum CommitType
{ {
SimpleCommit, SimpleCommit,
AmendCommit AmendCommit,
FixupCommit
}; };
// Todo: Add user name and password? // Todo: Add user name and password?
......
...@@ -103,14 +103,17 @@ const GitSubmitEditorWidget *GitSubmitEditor::submitEditorWidget() const ...@@ -103,14 +103,17 @@ const GitSubmitEditorWidget *GitSubmitEditor::submitEditorWidget() const
void GitSubmitEditor::setCommitData(const CommitData &d) void GitSubmitEditor::setCommitData(const CommitData &d)
{ {
m_commitEncoding = d.commitEncoding;
m_workingDirectory = d.panelInfo.repository;
m_commitType = d.commitType;
m_amendSHA1 = d.amendSHA1;
GitSubmitEditorWidget *w = submitEditorWidget(); GitSubmitEditorWidget *w = submitEditorWidget();
w->initialize(m_commitType, m_workingDirectory);
w->setPanelData(d.panelData); w->setPanelData(d.panelData);
w->setPanelInfo(d.panelInfo); w->setPanelInfo(d.panelInfo);
w->setHasUnmerged(false); w->setHasUnmerged(false);
m_commitEncoding = d.commitEncoding;
m_workingDirectory = d.panelInfo.repository;
m_commitType = d.commitType;
setEmptyFileListEnabled(m_commitType == AmendCommit); // Allow for just correcting the message setEmptyFileListEnabled(m_commitType == AmendCommit); // Allow for just correcting the message
m_model = new GitSubmitFileModel(this); m_model = new GitSubmitFileModel(this);
...@@ -178,6 +181,12 @@ GitSubmitEditorPanelData GitSubmitEditor::panelData() const ...@@ -178,6 +181,12 @@ GitSubmitEditorPanelData GitSubmitEditor::panelData() const
return submitEditorWidget()->panelData(); return submitEditorWidget()->panelData();
} }
QString GitSubmitEditor::amendSHA1() const
{
QString commit = submitEditorWidget()->amendSHA1();
return commit.isEmpty() ? m_amendSHA1 : commit;
}
QByteArray GitSubmitEditor::fileContents() const QByteArray GitSubmitEditor::fileContents() const
{ {
const QString &text = submitEditorWidget()->descriptionText(); const QString &text = submitEditorWidget()->descriptionText();
......
...@@ -56,6 +56,8 @@ public: ...@@ -56,6 +56,8 @@ public:
void setCommitData(const CommitData &); void setCommitData(const CommitData &);
GitSubmitEditorPanelData panelData() const; GitSubmitEditorPanelData panelData() const;
bool forceClose() const { return m_forceClose; } bool forceClose() const { return m_forceClose; }
CommitType commitType() const { return m_commitType; }
QString amendSHA1() const;
signals: signals:
void diff(const QStringList &unstagedFiles, const QStringList &stagedFiles); void diff(const QStringList &unstagedFiles, const QStringList &stagedFiles);
...@@ -75,6 +77,7 @@ private: ...@@ -75,6 +77,7 @@ private:
VcsBase::SubmitFileModel *m_model; VcsBase::SubmitFileModel *m_model;
QString m_commitEncoding; QString m_commitEncoding;
CommitType m_commitType; CommitType m_commitType;
QString m_amendSHA1;
bool m_forceClose; bool m_forceClose;
QString m_workingDirectory; QString m_workingDirectory;
}; };
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "gitsubmiteditorwidget.h" #include "gitsubmiteditorwidget.h"
#include "commitdata.h" #include "commitdata.h"
#include "logchangedialog.h"
#include <texteditor/texteditorsettings.h> #include <texteditor/texteditorsettings.h>
#include <texteditor/fontsettings.h> #include <texteditor/fontsettings.h>
...@@ -40,7 +41,9 @@ ...@@ -40,7 +41,9 @@
#include <QDebug> #include <QDebug>
#include <QDir> #include <QDir>
#include <QGroupBox>
#include <QRegExp> #include <QRegExp>
#include <QVBoxLayout>
namespace Git { namespace Git {
namespace Internal { namespace Internal {
...@@ -120,10 +123,11 @@ void GitSubmitHighlighter::highlightBlock(const QString &text) ...@@ -120,10 +123,11 @@ void GitSubmitHighlighter::highlightBlock(const QString &text)
GitSubmitEditorWidget::GitSubmitEditorWidget(QWidget *parent) : GitSubmitEditorWidget::GitSubmitEditorWidget(QWidget *parent) :
VcsBase::SubmitEditorWidget(parent), VcsBase::SubmitEditorWidget(parent),
m_gitSubmitPanel(new QWidget), m_gitSubmitPanel(new QWidget),
m_hasUnmerged(false) m_logChangeWidget(0),
m_hasUnmerged(false),
m_isInitialized(false)
{ {
m_gitSubmitPanelUi.setupUi(m_gitSubmitPanel); m_gitSubmitPanelUi.setupUi(m_gitSubmitPanel);
insertTopWidget(m_gitSubmitPanel);
new GitSubmitHighlighter(descriptionEdit()); new GitSubmitHighlighter(descriptionEdit());
m_emailValidator = new QRegExpValidator(QRegExp(QLatin1String("[^@ ]+@[^@ ]+\\.[a-zA-Z]+")), this); m_emailValidator = new QRegExpValidator(QRegExp(QLatin1String("[^@ ]+@[^@ ]+\\.[a-zA-Z]+")), this);
...@@ -144,11 +148,35 @@ void GitSubmitEditorWidget::setPanelInfo(const GitSubmitEditorPanelInfo &info) ...@@ -144,11 +148,35 @@ void GitSubmitEditorWidget::setPanelInfo(const GitSubmitEditorPanelInfo &info)
m_gitSubmitPanelUi.branchLabel->setText(info.branch); m_gitSubmitPanelUi.branchLabel->setText(info.branch);
} }
QString GitSubmitEditorWidget::amendSHA1() const
{
return m_logChangeWidget ? m_logChangeWidget->commit() : QString();
}
void GitSubmitEditorWidget::setHasUnmerged(bool e) void GitSubmitEditorWidget::setHasUnmerged(bool e)
{ {
m_hasUnmerged = e; m_hasUnmerged = e;
} }
void GitSubmitEditorWidget::initialize(CommitType commitType, const QString &repository)
{
if (m_isInitialized)
return;
m_isInitialized = true;
if (commitType == FixupCommit) {
QGroupBox *logChangeGroupBox = new QGroupBox(tr("Select Change"));
QVBoxLayout *logChangeLayout = new QVBoxLayout;
logChangeGroupBox->setLayout(logChangeLayout);
m_logChangeWidget = new LogChangeWidget;
m_logChangeWidget->init(repository);
logChangeLayout->addWidget(m_logChangeWidget);
insertTopWidget(logChangeGroupBox);
m_gitSubmitPanelUi.editGroup->hide();
hideDescription();
}
insertTopWidget(m_gitSubmitPanel);
}
GitSubmitEditorPanelData GitSubmitEditorWidget::panelData() const GitSubmitEditorPanelData GitSubmitEditorWidget::panelData() const
{ {
GitSubmitEditorPanelData rc; GitSubmitEditorPanelData rc;
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#define GITSUBMITEDITORWIDGET_H #define GITSUBMITEDITORWIDGET_H
#include "ui_gitsubmitpanel.h" #include "ui_gitsubmitpanel.h"
#include "gitsettings.h"
#include <vcsbase/submiteditorwidget.h> #include <vcsbase/submiteditorwidget.h>
...@@ -43,6 +44,7 @@ namespace Internal { ...@@ -43,6 +44,7 @@ namespace Internal {
struct GitSubmitEditorPanelInfo; struct GitSubmitEditorPanelInfo;
struct GitSubmitEditorPanelData; struct GitSubmitEditorPanelData;
class LogChangeWidget;
/* Submit editor widget with 2 additional panes: /* Submit editor widget with 2 additional panes:
* 1) Info with branch, description, etc * 1) Info with branch, description, etc
...@@ -62,7 +64,9 @@ public: ...@@ -62,7 +64,9 @@ public:
GitSubmitEditorPanelData panelData() const; GitSubmitEditorPanelData panelData() const;
void setPanelData(const GitSubmitEditorPanelData &data); void setPanelData(const GitSubmitEditorPanelData &data);
void setPanelInfo(const GitSubmitEditorPanelInfo &info); void setPanelInfo(const GitSubmitEditorPanelInfo &info);
QString amendSHA1() const;
void setHasUnmerged(bool e); void setHasUnmerged(bool e);
void initialize(CommitType commitType, const QString &repository);
protected: protected:
bool canSubmit() const; bool canSubmit() const;
...@@ -75,9 +79,11 @@ private: ...@@ -75,9 +79,11 @@ private:
bool emailIsValid() const; bool emailIsValid() const;
QWidget *m_gitSubmitPanel; QWidget *m_gitSubmitPanel;
LogChangeWidget *m_logChangeWidget;
Ui::GitSubmitPanel m_gitSubmitPanelUi; Ui::GitSubmitPanel m_gitSubmitPanelUi;
QValidator *m_emailValidator; QValidator *m_emailValidator;
bool m_hasUnmerged; bool m_hasUnmerged;
bool m_isInitialized;
}; };
} // namespace Internal } // namespace Internal
......
...@@ -534,6 +534,12 @@ void SubmitEditorWidget::insertTopWidget(QWidget *w) ...@@ -534,6 +534,12 @@ void SubmitEditorWidget::insertTopWidget(QWidget *w)
d->m_ui.vboxLayout->insertWidget(0, w); d->m_ui.vboxLayout->insertWidget(0, w);
} }
void SubmitEditorWidget::hideDescription()
{
d->m_ui.descriptionBox->hide();
setDescriptionMandatory(false);
}
void SubmitEditorWidget::descriptionTextChanged() void SubmitEditorWidget::descriptionTextChanged()
{ {
#if QT_VERSION < 0x050000 // Fix Qt-Bug, see QTCREATORBUG-5633 && QTCREATORBUG-6082 #if QT_VERSION < 0x050000 // Fix Qt-Bug, see QTCREATORBUG-5633 && QTCREATORBUG-6082
......
...@@ -122,6 +122,7 @@ protected: ...@@ -122,6 +122,7 @@ protected:
virtual void changeEvent(QEvent *e); virtual void changeEvent(QEvent *e);
virtual QString commitName() const; virtual QString commitName() const;
void insertTopWidget(QWidget *w); void insertTopWidget(QWidget *w);
void hideDescription();
protected slots: protected slots:
void descriptionTextChanged(); void descriptionTextChanged();
......
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