1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
|
/*
SPDX-FileCopyrightText: 2008 Evgeniy Ivanov <powerfox@kde.ru>
SPDX-FileCopyrightText: 2009 Hugo Parente Lima <hugo.pl@gmail.com>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#ifndef KDEVPLATFORM_PLUGIN_GIT_PLUGIN_H
#define KDEVPLATFORM_PLUGIN_GIT_PLUGIN_H
#include <vcs/interfaces/idistributedversioncontrol.h>
#include <vcs/interfaces/icontentawareversioncontrol.h>
#include <vcs/dvcs/dvcsplugin.h>
#include <vcs/vcsstatusinfo.h>
#include <outputview/outputjob.h>
#include <vcs/vcsjob.h>
#include <QDateTime>
class KDirWatch;
class QDir;
class RepoStatusModel;
class CommitToolViewFactory;
namespace KDevelop
{
class VcsJob;
class VcsRevision;
}
class StandardJob : public KDevelop::VcsJob
{
Q_OBJECT
public:
StandardJob(KDevelop::IPlugin* parent, KJob* job, OutputJobVerbosity verbosity);
QVariant fetchResults() override { return QVariant(); }
void start() override;
JobStatus status() const override { return m_status; }
KDevelop::IPlugin* vcsPlugin() const override { return m_plugin; }
public Q_SLOTS:
void result(KJob*);
private:
KJob* m_job;
KDevelop::IPlugin* m_plugin;
JobStatus m_status;
};
/**
* This is the main class of KDevelop's Git plugin.
*
* It implements the DVCS dependent things not implemented in KDevelop::DistributedVersionControlPlugin
* @author Evgeniy Ivanov <powerfox@kde.ru>
*/
class GitPlugin: public KDevelop::DistributedVersionControlPlugin, public KDevelop::IContentAwareVersionControl
{
Q_OBJECT
Q_INTERFACES(KDevelop::IBasicVersionControl KDevelop::IDistributedVersionControl KDevelop::IContentAwareVersionControl)
friend class GitInitTest;
public:
enum ExtendedState {
/* Unchanged in index (no staged changes) */
GitXX = KDevelop::VcsStatusInfo::ItemUserState, // No changes in worktree
// Changed in worktree, not staged for commit
GitXM, // Modified in worktree
GitXD, // Deleted in worktree
GitXR, // Renamed in worktree
GitXC, // Copied in worktree
/* Changes in index (staged changes) */
GitMX, // No changes in worktree
// Changed in worktree, not staged for commit
GitMM, // Modified in worktree
GitMD, // Deleted in worktree
/* Added to index (new item) */
GitAX, // No changes in worktree
// Changes in worktree, not staged for commit
GitAM, // Modified in worktree
GitAD, // Deleted in worktree
/* Deleted from index */
GitDX, // No changes in worktree (deleted in wt)
GitDR, // Renamed in worktree
GitDC, // Copied in worktree
/* Renamed in index */
GitRX, // No changes in worktree
GitRM, // Modified in worktree
GitRD, // Deleted in worktree
/* Copied in index */
GitCX, // No changes in worktree
GitCM, // Modified in worktree
GitCD, // Deleted in worktree
/* Special states */
GitUntracked, // ? ? --- untracked files
GitConflicts, // U, AA, DD --- conflicts
GitInvalid = -1, // not really a state
};
/**
* Enums with values which are used as function arguments
* instead of bools for better readability.
*
* The enums are named ${function_name}Params.
*/
enum ApplyParams {
Index = 0,
WorkTree = 2,
};
explicit GitPlugin(QObject* parent, const KPluginMetaData& metaData, const QVariantList& args = QVariantList());
~GitPlugin() override;
void unload() override;
QString name() const override;
bool isValidRemoteRepositoryUrl(const QUrl& remoteLocation) override;
bool isVersionControlled(const QUrl &path) override;
KDevelop::VcsJob* copy(const QUrl& localLocationSrc, const QUrl& localLocationDstn) override;
KDevelop::VcsJob* move(const QUrl& localLocationSrc, const QUrl& localLocationDst) override;
//TODO
KDevelop::VcsJob* pull(const KDevelop::VcsLocation& localOrRepoLocationSrc, const QUrl& localRepositoryLocation) override;
KDevelop::VcsJob* push(const QUrl& localRepositoryLocation, const KDevelop::VcsLocation& localOrRepoLocationDst) override;
KDevelop::VcsJob* repositoryLocation(const QUrl& localLocation) override;
KDevelop::VcsJob* resolve(const QList<QUrl>& localLocations, RecursionMode recursion) override;
KDevelop::VcsJob* update(const QList<QUrl>& localLocations, const KDevelop::VcsRevision& rev, RecursionMode recursion) override;
KDevelop::VcsLocationWidget* vcsLocation(QWidget* parent) const override;
void setupCommitMessageEditor(const QUrl& localLocation, KTextEdit* editor) const override;
//End of
KDevelop::VcsJob* add(const QList<QUrl>& localLocations,
KDevelop::IBasicVersionControl::RecursionMode recursion = KDevelop::IBasicVersionControl::Recursive) override;
KDevelop::VcsJob* createWorkingCopy(const KDevelop::VcsLocation & localOrRepoLocationSrc,
const QUrl& localRepositoryRoot, KDevelop::IBasicVersionControl::RecursionMode) override;
KDevelop::VcsJob* remove(const QList<QUrl>& files) override;
KDevelop::VcsJob* status(const QList<QUrl>& localLocations,
KDevelop::IBasicVersionControl::RecursionMode recursion = KDevelop::IBasicVersionControl::Recursive) override;
KDevelop::VcsJob* commit(const QString& message,
const QList<QUrl>& localLocations,
KDevelop::IBasicVersionControl::RecursionMode recursion = KDevelop::IBasicVersionControl::Recursive) override;
/**
* Commits staged changes to the repo located at repoUrl.
*
* @param message the commit message
* @param repoUrl the url pointing to the repo directory (or a file in the repo)
*/
KDevelop::VcsJob* commitStaged(const QString& message, const QUrl& repoUrl);
KDevelop::VcsJob* diff(const QUrl& fileOrDirectory, const KDevelop::VcsRevision& srcRevision, const KDevelop::VcsRevision& dstRevision,
RecursionMode recursion) override;
/**
* Shows a diff of changes between srcRevision and dstRevision.
*
* @param repoPath a path pointing somewhere inside the repo
* @param srcRevision the source revision
* @param dstRevision the destination revision
*
* @note: This differs from the @ref:diff method in @ref:IBasicVersionControl in that it does not require
* a list of files but automatically shows all changed files
*/
KDevelop::VcsJob* diff(const QUrl& repoPath, const KDevelop::VcsRevision& srcRevision, const KDevelop::VcsRevision& dstRevision);
KDevelop::VcsJob* log( const QUrl& localLocation, const KDevelop::VcsRevision& rev, unsigned long limit) override;
KDevelop::VcsJob* log(const QUrl& localLocation, const KDevelop::VcsRevision& rev, const KDevelop::VcsRevision& limit) override;
KDevelop::VcsJob* annotate(const QUrl &localLocation, const KDevelop::VcsRevision &rev) override;
KDevelop::VcsJob* revert(const QList<QUrl>& localLocations, RecursionMode recursion) override;
/**
* Resets all changes in the specified files which were "staged for commit".
*
* @param localLocations the local files/dirs changes to which should be reset
* @param recursion defines whether changes should be reset recursively in all files
* in a directory, if localLocations contain a directory
*/
KDevelop::VcsJob* reset(const QList<QUrl>& localLocations, RecursionMode recursion);
/**
* Applies the patch given by a diff to the repo
*
* @param diff the patch
* @param applyTo where to apply the patch (index or worktree)
*/
KDevelop::VcsJob* apply(const KDevelop::VcsDiff& diff, ApplyParams applyTo = WorkTree);
// Begin: KDevelop::IDistributedVersionControl
KDevelop::VcsJob* init(const QUrl & directory) override;
// Branch management
KDevelop::VcsJob* tag(const QUrl& repository, const QString& commitMessage, const KDevelop::VcsRevision& rev, const QString& tagName) override;
KDevelop::VcsJob* branch(const QUrl& repository, const KDevelop::VcsRevision& rev, const QString& branchName) override;
KDevelop::VcsJob* branches(const QUrl& repository) override;
KDevelop::VcsJob* currentBranch(const QUrl& repository) override;
KDevelop::VcsJob* deleteBranch(const QUrl& repository, const QString& branchName) override;
KDevelop::VcsJob* switchBranch(const QUrl& repository, const QString& branchName) override;
KDevelop::VcsJob* renameBranch(const QUrl& repository, const QString& oldBranchName, const QString& newBranchName) override;
KDevelop::VcsJob* mergeBranch(const QUrl& repository, const QString& branchName) override;
KDevelop::VcsJob* rebase(const QUrl& repository, const QString& branchName);
//graph helpers
QVector<KDevelop::DVcsEvent> allCommits(const QString& repo) override;
//used in log
void parseLogOutput(const KDevelop::DVcsJob* job,
QVector<KDevelop::DVcsEvent>& commits) const override;
void additionalMenuEntries(QMenu* menu, const QList<QUrl>& urls) override;
// Stash Management
/**
* Structure to hold information about an item on the stash stack
*/
struct StashItem {
int stackDepth = -1; /* Position on the stack */
QString shortRef; /* The reflog selector (e.g. stash@{0}) */
QString parentSHA; /* The short SHA of the commit on which the stash was made */
QString parentDescription; /* A short description of the commit on which the stash was made */
QString branch; /* The branch on which the stash was made */
QString message; /* The message with which the stash was made */
QDateTime creationTime; /* The date-time the stash item was committed */
};
/**
* Returns a job to run `git stash` in the repository @p repository with
* additional arguments @p args.
*
* The @p verbosity parameter will determine whether the job output will
* be shown in the VCS Output ToolView.
*
* For example, a job to silently apply the top-most stashed item to the current
* tree would be created as follows:
*
* gitStash(repoDir, {QStringLiteral("apply")}, KDevelop::OutputJob::Silent)
*
*/
KDevelop::VcsJob* gitStash(const QDir& repository, const QStringList& args, KDevelop::OutputJob::OutputJobVerbosity verbosity);
/**
* The result (job->fetchResults()) will be a @ref QList of @ref StashItem s
*
* @p repository is the repository to work on
* @p verbosity determines whether the job output will be shown in the VCS Output ToolView
*/
KDevelop::VcsJob* stashList(const QDir& repository, KDevelop::OutputJob::OutputJobVerbosity verbosity = KDevelop::OutputJob::Silent);
bool hasStashes(const QDir& repository);
bool hasModifications(const QDir& repository);
bool hasModifications(const QDir& repo, const QUrl& file);
void registerRepositoryForCurrentBranchChanges(const QUrl& repository) override;
KDevelop::CheckInRepositoryJob* isInRepository(KTextEditor::Document* document) override;
KDevelop::DVcsJob* setConfigOption(const QUrl& repository, const QString& key, const QString& value, bool global = false);
QString readConfigOption(const QUrl& repository, const QString& key);
// this indicates whether the diff() function will generate a diff (patch) which
// includes the working copy directory name or not (in which case git diff is called
// with --no-prefix).
bool usePrefix() const
{
return m_usePrefix;
}
void setUsePrefix(bool p)
{
m_usePrefix = p;
}
protected:
QUrl repositoryRoot(const QUrl& path);
bool isValidDirectory(const QUrl &dirPath) override;
KDevelop::DVcsJob* lsFiles(const QDir &repository,
const QStringList &args,
KDevelop::OutputJob::OutputJobVerbosity verbosity = KDevelop::OutputJob::Verbose);
KDevelop::DVcsJob* gitRevList(const QString &directory,
const QStringList &args);
KDevelop::DVcsJob* gitRevParse(const QString &repository,
const QStringList &args,
KDevelop::OutputJob::OutputJobVerbosity verbosity = KDevelop::OutputJob::Silent);
private Q_SLOTS:
void parseGitBlameOutput(KDevelop::DVcsJob *job);
void parseGitLogOutput(KDevelop::DVcsJob *job);
void parseGitDiffOutput(KDevelop::DVcsJob* job);
void parseGitRepoLocationOutput(KDevelop::DVcsJob* job);
void parseGitStatusOutput(KDevelop::DVcsJob* job);
void parseGitStatusOutput_old(KDevelop::DVcsJob* job);
void parseGitVersionOutput(KDevelop::DVcsJob* job);
void parseGitBranchOutput(KDevelop::DVcsJob* job);
void parseGitCurrentBranch(KDevelop::DVcsJob* job);
void parseGitStashList(KDevelop::VcsJob* job);
void ctxRebase();
void ctxPushStash();
void ctxPopStash();
void ctxStashManager();
void fileChanged(const QString& file);
void delayedBranchChanged();
Q_SIGNALS:
void repositoryBranchChanged(const QUrl& repository);
private:
bool ensureValidGitIdentity(const QDir& dir);
void addNotVersionedFiles(const QDir& dir, const QList<QUrl>& files);
//commit dialog "main" helper
QStringList getLsFiles(const QDir &directory, const QStringList &args,
KDevelop::OutputJob::OutputJobVerbosity verbosity);
KDevelop::DVcsJob* errorsFound(const QString& error, KDevelop::OutputJob::OutputJobVerbosity verbosity);
void initBranchHash(const QString &repo);
/**
* Parses a git status --porcelain line
*
* @param statusLine a line as returned by `git status --porcelain`
* @returns the appropriate extended status
*/
static ExtendedState parseGitState(QStringView statusLine);
/**
* Maps an extended state to a basic state
*
* @param state the extended state as provided by git (i.e. describing the combined status in the index & worktree)
*/
static KDevelop::VcsStatusInfo::State extendedStateToBasic(const ExtendedState state);
QList<QStringList> branchesShas;
QList<QUrl> m_urls;
/** Tells if it's older than 1.7.0 or not */
bool m_oldVersion = false;
KDirWatch* m_watcher;
QList<QUrl> m_branchesChange;
bool m_usePrefix = true;
/** A tree model tracking and classifying changes into staged, unstaged and untracked */
RepoStatusModel* m_repoStatusModel;
/** A factory for constructing the tool view for preparing commits */
CommitToolViewFactory* m_commitToolViewFactory;
};
Q_DECLARE_METATYPE(GitPlugin::StashItem)
QVariant runSynchronously(KDevelop::VcsJob* job);
#endif
|