aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/git/gitversioncontrol.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/git/gitversioncontrol.cpp')
-rw-r--r--src/plugins/git/gitversioncontrol.cpp101
1 files changed, 100 insertions, 1 deletions
diff --git a/src/plugins/git/gitversioncontrol.cpp b/src/plugins/git/gitversioncontrol.cpp
index 76541548ccb..c98f0688921 100644
--- a/src/plugins/git/gitversioncontrol.cpp
+++ b/src/plugins/git/gitversioncontrol.cpp
@@ -30,10 +30,19 @@
#include "gitversioncontrol.h"
#include "gitclient.h"
#include "gitplugin.h"
+#include "gitutils.h"
+
+static const char stashMessageKeywordC[] = "IVersionControl@";
+static const char stashRevisionIdC[] = "revision";
namespace Git {
namespace Internal {
+static inline GitClient *gitClient()
+{
+ return GitPlugin::instance()->gitClient();
+}
+
GitVersionControl::GitVersionControl(GitClient *client) :
m_enabled(true),
m_client(client)
@@ -54,6 +63,7 @@ bool GitVersionControl::supportsOperation(Operation operation) const
case OpenOperation:
break;
case CreateRepositoryOperation:
+ case SnapshotOperations:
rc = true;
break;
}
@@ -78,7 +88,91 @@ bool GitVersionControl::vcsDelete(const QString & /*fileName*/)
bool GitVersionControl::vcsCreateRepository(const QString &directory)
{
- return GitPlugin::instance()->gitClient()->synchronousInit(directory);
+ return gitClient()->synchronousInit(directory);
+}
+/* Snapshots are implement using stashes, relying on stash messages for
+ * naming as the actual stash names (stash{n}) are rotated as one adds stashes.
+ * Note that the snapshot interface does not care whether we have an unmodified
+ * repository state, in which case git refuses to stash.
+ * In that case, return a special identifier as "specialprefix:<branch>:<head revision>",
+ * which will trigger a checkout in restore(). */
+
+QString GitVersionControl::vcsCreateSnapshot(const QString &topLevel)
+{
+ bool repositoryUnchanged;
+ // Create unique keyword
+ static int n = 1;
+ QString keyword = QLatin1String(stashMessageKeywordC) + QString::number(n++);
+ const QString stashMessage =
+ gitClient()->synchronousStash(topLevel, keyword,
+ GitClient::StashImmediateRestore|GitClient::StashIgnoreUnchanged,
+ &repositoryUnchanged);
+ if (!stashMessage.isEmpty())
+ return stashMessage;
+ if (repositoryUnchanged) {
+ // For unchanged repository state: return identifier + top revision
+ QString topRevision;
+ QString branch;
+ if (!gitClient()->synchronousTopRevision(topLevel, &topRevision, &branch))
+ return QString();
+ const QChar colon = QLatin1Char(':');
+ QString id = QLatin1String(stashRevisionIdC);
+ id += colon;
+ id += branch;
+ id += colon;
+ id += topRevision;
+ return id;
+ }
+ return QString(); // Failure
+}
+
+QStringList GitVersionControl::vcsSnapshots(const QString &topLevel)
+{
+ QList<Stash> stashes;
+ if (!gitClient()->synchronousStashList(topLevel, &stashes))
+ return QStringList();
+ // Return the git stash 'message' as identifier, ignoring empty ones
+ QStringList rc;
+ foreach(const Stash &s, stashes)
+ if (!s.message.isEmpty())
+ rc.push_back(s.message);
+ return rc;
+}
+
+bool GitVersionControl::vcsRestoreSnapshot(const QString &topLevel, const QString &name)
+{
+ bool success = false;
+ do {
+ // Is this a revision or a stash
+ if (name.startsWith(QLatin1String(stashRevisionIdC))) {
+ // Restore "id:branch:revision"
+ const QStringList tokens = name.split(QLatin1Char(':'));
+ if (tokens.size() != 3)
+ break;
+ const QString branch = tokens.at(1);
+ const QString revision = tokens.at(2);
+ success = gitClient()->synchronousReset(topLevel)
+ && gitClient()->synchronousCheckoutBranch(topLevel, branch)
+ && gitClient()->synchronousCheckoutFiles(topLevel, QStringList(), revision);
+ } else {
+ // Restore stash if it can be resolved.
+ QString stashName;
+ success = gitClient()->stashNameFromMessage(topLevel, name, &stashName)
+ && gitClient()->synchronousReset(topLevel)
+ && gitClient()->synchronousStashRestore(topLevel, stashName);
+ }
+ } while (false);
+ return success;
+}
+
+bool GitVersionControl::vcsRemoveSnapshot(const QString &topLevel, const QString &name)
+{
+ // Is this a revision -> happy
+ if (name.startsWith(QLatin1String(stashRevisionIdC)))
+ return true;
+ QString stashName;
+ return gitClient()->stashNameFromMessage(topLevel, name, &stashName)
+ && gitClient()->synchronousStashRemove(topLevel, stashName);
}
bool GitVersionControl::managesDirectory(const QString &directory) const
@@ -96,5 +190,10 @@ void GitVersionControl::emitFilesChanged(const QStringList &l)
emit filesChanged(l);
}
+void GitVersionControl::emitRepositoryChanged(const QString &r)
+{
+ emit repositoryChanged(r);
+}
+
} // Internal
} // Git