From 4a5af14b7f1260f2a4d2bb7c4bd3883fc5baf524 Mon Sep 17 00:00:00 2001
From: Orgad Shaneh <orgad.shaneh@audiocodes.com>
Date: Mon, 2 Dec 2013 23:28:58 +0200
Subject: [PATCH] Git: Enable choosing non-fast-forward merge

Change-Id: I5972489d06637616953bd0d93a3b65c4d9918377
Reviewed-by: Leena Miettinen <riitta-leena.miettinen@digia.com>
Reviewed-by: Tobias Hunger <tobias.hunger@digia.com>
Reviewed-by: Petar Perisin <petar.perisin@gmail.com>
---
 src/plugins/git/branchdialog.cpp | 15 ++++++++++++++-
 src/plugins/git/gitclient.cpp    | 20 +++++++++++++++++---
 src/plugins/git/gitclient.h      |  4 +++-
 3 files changed, 34 insertions(+), 5 deletions(-)

diff --git a/src/plugins/git/branchdialog.cpp b/src/plugins/git/branchdialog.cpp
index 9fadf16934a..09e21ba2c8f 100644
--- a/src/plugins/git/branchdialog.cpp
+++ b/src/plugins/git/branchdialog.cpp
@@ -38,11 +38,14 @@
 #include "stashdialog.h" // Label helpers
 
 #include <utils/qtcassert.h>
+#include <utils/execmenu.h>
 #include <vcsbase/vcsbaseoutputwindow.h>
 
+#include <QAction>
 #include <QItemSelectionModel>
 #include <QMessageBox>
 #include <QList>
+#include <QMenu>
 
 #include <QDebug>
 
@@ -321,8 +324,18 @@ void BranchDialog::merge()
 
     const QString branch = m_model->fullName(idx, true);
     GitClient *client = GitPlugin::instance()->gitClient();
+    bool allowFastForward = true;
+    if (client->isFastForwardMerge(m_repository, branch)) {
+        QMenu popup;
+        QAction *fastForward = popup.addAction(tr("Fast-Forward"));
+        popup.addAction(tr("No Fast-Forward"));
+        QAction *chosen = Utils::execMenuAtWidget(&popup, m_ui->mergeButton);
+        if (!chosen)
+            return;
+        allowFastForward = (chosen == fastForward);
+    }
     if (client->beginStashScope(m_repository, QLatin1String("merge"), AllowUnstashed))
-        client->synchronousMerge(m_repository, branch);
+        client->synchronousMerge(m_repository, branch, allowFastForward);
 }
 
 void BranchDialog::rebase()
diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp
index ed5124c93ce..6842489a82c 100644
--- a/src/plugins/git/gitclient.cpp
+++ b/src/plugins/git/gitclient.cpp
@@ -2106,6 +2106,17 @@ bool GitClient::isRemoteCommit(const QString &workingDirectory, const QString &c
     return !outputText.isEmpty();
 }
 
+bool GitClient::isFastForwardMerge(const QString &workingDirectory, const QString &branch)
+{
+    QStringList arguments;
+    QByteArray outputText;
+    arguments << QLatin1String("merge-base") << QLatin1String(HEAD) << branch;
+    fullySynchronousGit(workingDirectory, arguments, &outputText, 0,
+                        VcsBasePlugin::SuppressCommandLogging);
+    return commandOutputFromLocal8Bit(outputText).trimmed()
+            == synchronousTopRevision(workingDirectory);
+}
+
 // Format an entry in a one-liner for selection list using git log.
 QString GitClient::synchronousShortDescription(const QString &workingDirectory, const QString &revision,
                                             const QString &format)
@@ -3485,12 +3496,15 @@ void GitClient::push(const QString &workingDirectory, const QStringList &pushArg
     executeGit(workingDirectory, arguments, 0, true);
 }
 
-bool GitClient::synchronousMerge(const QString &workingDirectory, const QString &branch)
+bool GitClient::synchronousMerge(const QString &workingDirectory, const QString &branch,
+                                 bool allowFastForward)
 {
     QString command = QLatin1String("merge");
-    QStringList arguments;
+    QStringList arguments(command);
 
-    arguments << command << branch;
+    if (!allowFastForward)
+        arguments << QLatin1String("--no-ff");
+    arguments << branch;
     return executeAndHandleConflicts(workingDirectory, arguments, command);
 }
 
diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h
index 039d3381b7d..69f11e95539 100644
--- a/src/plugins/git/gitclient.h
+++ b/src/plugins/git/gitclient.h
@@ -244,13 +244,15 @@ public:
     QStringList synchronousBranchesForCommit(const QString &workingDirectory,
                                              const QString &revision);
     bool isRemoteCommit(const QString &workingDirectory, const QString &commit);
+    bool isFastForwardMerge(const QString &workingDirectory, const QString &branch);
 
     bool cloneRepository(const QString &directory, const QByteArray &url);
     QString vcsGetRepositoryURL(const QString &directory);
     void fetch(const QString &workingDirectory, const QString &remote);
     bool synchronousPull(const QString &workingDirectory, bool rebase);
     void push(const QString &workingDirectory, const QStringList &pushArgs = QStringList());
-    bool synchronousMerge(const QString &workingDirectory, const QString &branch);
+    bool synchronousMerge(const QString &workingDirectory, const QString &branch,
+                          bool allowFastForward = true);
     bool canRebase(const QString &workingDirectory) const;
     void rebase(const QString &workingDirectory, const QString &baseBranch);
     bool synchronousRevert(const QString &workingDirectory, const QString &commit);
-- 
GitLab