File indexing completed on 2025-01-19 04:22:45
0001 // Copyright (C) 2020 Hamed Masafi <hamed.masafi@gmail.com> 0002 // SPDX-License-Identifier: GPL-3.0-or-later 0003 0004 #include "gitmanager.h" 0005 0006 #include "models/authorsmodel.h" 0007 #include "models/branchesmodel.h" 0008 #include "models/logsmodel.h" 0009 #include "models/remotesmodel.h" 0010 #include "models/stashesmodel.h" 0011 #include "models/submodulesmodel.h" 0012 #include "models/tagsmodel.h" 0013 0014 #include "libkommit_debug.h" 0015 #include <QFile> 0016 #include <QProcess> 0017 #include <QSortFilterProxyModel> 0018 #include <QtConcurrent> 0019 #include <QFuture> 0020 #include <QFutureWatcher> 0021 0022 namespace Git 0023 { 0024 0025 const QString &Manager::path() const 0026 { 0027 return mPath; 0028 } 0029 0030 void Manager::setPath(const QString &newPath) 0031 { 0032 if (mPath == newPath) 0033 return; 0034 0035 QProcess p; 0036 p.setProgram(QStringLiteral("git")); 0037 p.setArguments({QStringLiteral("rev-parse"), QStringLiteral("--show-toplevel")}); 0038 p.setWorkingDirectory(newPath); 0039 p.start(); 0040 p.waitForFinished(); 0041 auto ret = p.readAllStandardOutput() + p.readAllStandardError(); 0042 0043 if (ret.contains("fatal")) { 0044 mPath = QString(); 0045 mIsValid = false; 0046 } else { 0047 mPath = ret.replace("\n", ""); 0048 mIsValid = true; 0049 loadAsync(); 0050 0051 setIsMerging(QFile::exists(mPath + QStringLiteral("/.git/MERGE_HEAD"))); 0052 setIsRebasing(QFile::exists(mPath + QStringLiteral("/.git/REBASE_HEAD"))); 0053 } 0054 0055 Q_EMIT pathChanged(); 0056 } 0057 0058 QMap<QString, ChangeStatus> Manager::changedFiles(const QString &hash) const 0059 { 0060 QMap<QString, ChangeStatus> statuses; 0061 auto buffer = QString(runGit({QStringLiteral("show"), QStringLiteral("--name-status"), hash})).split(QLatin1Char('\n')); 0062 0063 for (auto &line : buffer) { 0064 if (!line.trimmed().size()) 0065 continue; 0066 0067 const auto parts = line.split(QLatin1Char('\t')); 0068 if (parts.size() != 2) 0069 continue; 0070 0071 const auto partFirst{parts.first()}; 0072 if (partFirst == QLatin1Char('A')) 0073 statuses.insert(parts.at(1), ChangeStatus::Added); 0074 else if (partFirst == QLatin1Char('M')) 0075 statuses.insert(parts.at(1), ChangeStatus::Modified); 0076 else if (partFirst == QLatin1Char('D')) 0077 statuses.insert(parts.at(1), ChangeStatus::Removed); 0078 else 0079 qCDebug(KOMMITLIB_LOG) << "Unknown file status" << partFirst; 0080 } 0081 return statuses; 0082 } 0083 0084 QStringList Manager::ignoredFiles() const 0085 { 0086 return readAllNonEmptyOutput({QStringLiteral("check-ignore"), QStringLiteral("*")}); 0087 } 0088 0089 QList<FileStatus> Manager::repoFilesStatus() const 0090 { 0091 const auto buffer = QString(runGit({QStringLiteral("status"), 0092 QStringLiteral("--untracked-files=all"), 0093 QStringLiteral("--ignored"), 0094 QStringLiteral("--short"), 0095 QStringLiteral("--ignore-submodules"), 0096 QStringLiteral("--porcelain")})) 0097 .split(QLatin1Char('\n')); 0098 QList<FileStatus> files; 0099 for (const auto &item : buffer) { 0100 if (!item.trimmed().size()) 0101 continue; 0102 FileStatus fs; 0103 fs.parseStatusLine(item); 0104 qCDebug(KOMMITLIB_LOG) << "[STATUS]" << fs.name() << fs.status(); 0105 fs.setFullPath(mPath + QLatin1Char('/') + fs.name()); 0106 files.append(fs); 0107 } 0108 return files; 0109 } 0110 0111 bool Manager::isValid() const 0112 { 0113 return mIsValid; 0114 } 0115 0116 bool Manager::addRemote(const QString &name, const QString &url) const 0117 { 0118 runGit({QStringLiteral("remote"), QStringLiteral("add"), name, url}); 0119 return true; 0120 } 0121 0122 bool Manager::removeRemote(const QString &name) const 0123 { 0124 runGit({QStringLiteral("remote"), QStringLiteral("remove"), name}); 0125 return true; 0126 } 0127 0128 bool Manager::renameRemote(const QString &name, const QString &newName) const 0129 { 0130 runGit({QStringLiteral("remote"), QStringLiteral("rename"), name, newName}); 0131 return true; 0132 } 0133 0134 bool Manager::isIgnored(const QString &path) 0135 { 0136 auto tmp = readAllNonEmptyOutput({QStringLiteral("check-ignore"), path}); 0137 qCDebug(KOMMITLIB_LOG) << Q_FUNC_INFO << tmp; 0138 return !tmp.empty(); 0139 } 0140 0141 QPair<int, int> Manager::uniqueCommitsOnBranches(const QString &branch1, const QString &branch2) const 0142 { 0143 if (branch1 == branch2) 0144 return qMakePair(0, 0); 0145 0146 auto ret = readAllNonEmptyOutput( 0147 {QStringLiteral("rev-list"), QStringLiteral("--left-right"), QStringLiteral("--count"), branch1 + QStringLiteral("...") + branch2}); 0148 0149 if (ret.size() != 1) 0150 return qMakePair(-1, -1); 0151 0152 const auto parts = ret.first().split(QLatin1Char('\t')); 0153 if (parts.size() != 2) 0154 return qMakePair(-1, -1); 0155 0156 return qMakePair(parts.at(0).toInt(), parts.at(1).toInt()); 0157 } 0158 0159 QStringList Manager::fileLog(const QString &fileName) const 0160 { 0161 return readAllNonEmptyOutput({QStringLiteral("log"), QStringLiteral("--format=format:%H"), QStringLiteral("--"), fileName}); 0162 } 0163 0164 QString Manager::diff(const QString &from, const QString &to) const 0165 { 0166 return runGit({QStringLiteral("diff"), from, to}); 0167 } 0168 0169 QList<FileStatus> Manager::diffBranch(const QString &from) const 0170 { 0171 auto buffer = QString(runGit({QStringLiteral("diff"), from, QStringLiteral("--name-status")})).split(QLatin1Char('\n')); 0172 QList<FileStatus> files; 0173 for (auto &item : buffer) { 0174 if (!item.trimmed().size()) 0175 continue; 0176 auto parts = item.split(QStringLiteral("\t")); 0177 if (parts.size() != 2) 0178 continue; 0179 0180 FileStatus fs; 0181 fs.setStatus(parts.at(0)); 0182 fs.setName(parts.at(1)); 0183 files.append(fs); 0184 } 0185 return files; 0186 } 0187 0188 QList<FileStatus> Manager::diffBranches(const QString &from, const QString &to) const 0189 { 0190 const auto buffer = QString(runGit({QStringLiteral("diff"), from + QStringLiteral("..") + to, QStringLiteral("--name-status")})).split(QLatin1Char('\n')); 0191 QList<FileStatus> files; 0192 for (const auto &item : buffer) { 0193 if (!item.trimmed().size()) 0194 continue; 0195 const auto parts = item.split(QLatin1Char('\t')); 0196 if (parts.size() != 2) 0197 continue; 0198 0199 FileStatus fs; 0200 fs.setStatus(parts.at(0)); 0201 fs.setName(parts.at(1)); 0202 files.append(fs); 0203 } 0204 return files; 0205 } 0206 0207 QString Manager::config(const QString &name, ConfigType type) const 0208 { 0209 QStringList cmd; 0210 switch (type) { 0211 case ConfigLocal: 0212 cmd = QStringList{QStringLiteral("config"), name}; 0213 break; 0214 case ConfigGlobal: 0215 cmd = QStringList{QStringLiteral("config"), QStringLiteral("--global"), name}; 0216 break; 0217 } 0218 const auto list = readAllNonEmptyOutput(cmd); 0219 if (!list.empty()) 0220 return list.first(); 0221 0222 return {}; 0223 } 0224 0225 bool Manager::configBool(const QString &name, ConfigType type) const 0226 { 0227 const auto buffer = config(name, type); 0228 return buffer == QStringLiteral("true") || buffer == QStringLiteral("yes") || buffer == QStringLiteral("on"); 0229 } 0230 0231 void Manager::setConfig(const QString &name, const QString &value, ConfigType type) const 0232 { 0233 QStringList cmd; 0234 switch (type) { 0235 case ConfigLocal: 0236 cmd = QStringList{QStringLiteral("config"), name, value}; 0237 break; 0238 case ConfigGlobal: 0239 cmd = QStringList{QStringLiteral("config"), QStringLiteral("--global"), name, value}; 0240 break; 0241 } 0242 0243 runGit(cmd); 0244 } 0245 0246 void Manager::unsetConfig(const QString &name, ConfigType type) const 0247 { 0248 QStringList cmd{QStringLiteral("config"), QStringLiteral("--unset")}; 0249 0250 if (type == ConfigGlobal) 0251 cmd.append(QStringLiteral("--global")); 0252 0253 cmd.append(name); 0254 0255 runGit(cmd); 0256 } 0257 0258 QStringList Manager::readAllNonEmptyOutput(const QStringList &cmd) const 0259 { 0260 QStringList list; 0261 const auto out = QString(runGit(cmd)).split(QLatin1Char('\n')); 0262 0263 for (const auto &line : out) { 0264 const auto b = line.trimmed(); 0265 if (b.isEmpty()) 0266 continue; 0267 0268 list.append(b.trimmed()); 0269 } 0270 return list; 0271 } 0272 0273 QString Manager::escapeFileName(const QString &filePath) const 0274 { 0275 if (filePath.contains(QLatin1Char(' '))) 0276 return QLatin1Char('\'') + filePath + QLatin1Char('\''); 0277 return filePath; 0278 } 0279 0280 AbstractGitItemsModel * load(AbstractGitItemsModel *cache) 0281 { 0282 cache->load(); 0283 return cache; 0284 } 0285 0286 void Manager::loadAsync() 0287 { 0288 QList<AbstractGitItemsModel *> models; 0289 if (mAuthorsModel) { 0290 mAuthorsModel->clear(); 0291 } 0292 if (mLoadFlags & LoadStashes) 0293 models << mStashesCache; 0294 if (mLoadFlags & LoadRemotes) 0295 models << mRemotesModel; 0296 if (mLoadFlags & LoadSubmodules) 0297 models << mSubmodulesModel; 0298 if (mLoadFlags & LoadBranches) 0299 models << mBranchesModel; 0300 if (mLoadFlags & LoadLogs) 0301 models << mLogsCache; 0302 if (mLoadFlags & LoadTags) 0303 models << mTagsModel; 0304 0305 if (!models.empty()) { 0306 #ifdef QT_CONCURRENT_LIB 0307 qDebug() << "LOADING MODELS ASYNC"; 0308 auto future = QtConcurrent::mapped(models, load); 0309 0310 auto watcher = new QFutureWatcher<AbstractGitItemsModel *>; 0311 0312 watcher->setFuture(future); 0313 0314 connect(watcher, &QFutureWatcher<bool>::finished, [this]() 0315 { 0316 Q_EMIT modelsReady(); 0317 }); 0318 0319 connect(watcher, &QFutureWatcher<AbstractGitItemsModel *>::resultReadyAt, [this, watcher](int index) 0320 { 0321 auto model = watcher->resultAt(index); 0322 model->reset(); 0323 }); 0324 #else 0325 for (auto &m : models) 0326 m->load(); 0327 #endif 0328 } 0329 } 0330 0331 TagsModel *Manager::tagsModel() const 0332 { 0333 return mTagsModel; 0334 } 0335 0336 StashesModel *Manager::stashesModel() const 0337 { 0338 return mStashesCache; 0339 } 0340 0341 LogsModel *Manager::logsModel() const 0342 { 0343 return mLogsCache; 0344 } 0345 0346 BranchesModel *Manager::branchesModel() const 0347 { 0348 return mBranchesModel; 0349 } 0350 0351 AuthorsModel *Manager::authorsModel() const 0352 { 0353 return mAuthorsModel; 0354 } 0355 0356 SubmodulesModel *Manager::submodulesModel() const 0357 { 0358 return mSubmodulesModel; 0359 } 0360 0361 RemotesModel *Manager::remotesModel() const 0362 { 0363 return mRemotesModel; 0364 } 0365 0366 const LoadFlags &Manager::loadFlags() const 0367 { 0368 return mLoadFlags; 0369 } 0370 0371 void Manager::setLoadFlags(Git::LoadFlags newLoadFlags) 0372 { 0373 mLoadFlags = newLoadFlags; 0374 } 0375 0376 QString Manager::readNote(const QString &branchName) const 0377 { 0378 return runGit({QStringLiteral("notes"), QStringLiteral("show"), branchName}); 0379 } 0380 0381 void Manager::saveNote(const QString &branchName, const QString ¬e) const 0382 { 0383 runGit({QStringLiteral("notes"), QStringLiteral("add"), branchName, QStringLiteral("-f"), QStringLiteral("--message=") + note}); 0384 } 0385 0386 Manager::Manager() 0387 : QObject() 0388 , mRemotesModel{new RemotesModel(this)} 0389 , mAuthorsModel{new AuthorsModel(this)} 0390 , mSubmodulesModel{new SubmodulesModel(this)} 0391 , mBranchesModel{new BranchesModel(this)} 0392 , mLogsCache{new LogsModel(this, mAuthorsModel)} 0393 , mStashesCache{new StashesModel(this)} 0394 , mTagsModel{new TagsModel(this)} 0395 { 0396 } 0397 0398 Manager::Manager(const QString &path) 0399 : Manager() 0400 { 0401 setPath(path); 0402 } 0403 0404 Manager *Manager::instance() 0405 { 0406 static Manager instance; 0407 return &instance; 0408 } 0409 0410 QString Manager::currentBranch() const 0411 { 0412 const auto ret = QString(runGit({QStringLiteral("rev-parse"), QStringLiteral("--abbrev-ref"), QStringLiteral("HEAD")})) 0413 .remove(QLatin1Char('\n')) 0414 .remove(QLatin1Char('\r')); 0415 return ret; 0416 } 0417 0418 //git rev-parse --abbrev-ref --symbolic-full-name @{u} 0419 QString Manager::currentRemote() const 0420 { 0421 const auto ret = QString(runGit({QStringLiteral("rev-parse"), QStringLiteral("--abbrev-ref"), QStringLiteral("--symbolic-full-name"), QStringLiteral("@{u}")})+"/") 0422 .remove(QLatin1Char('\n')) 0423 .remove(QLatin1Char('\r')) 0424 .split("/").first(); 0425 return ret; 0426 } 0427 0428 QString Manager::run(const AbstractCommand &cmd) const 0429 { 0430 return QString(runGit(cmd.generateArgs())); 0431 } 0432 0433 void Manager::init(const QString &path) 0434 { 0435 mPath = path; 0436 runGit({QStringLiteral("init")}); 0437 } 0438 0439 QByteArray Manager::runGit(const QStringList &args) const 0440 { 0441 // qCDebug(KOMMITLIB_LOG).noquote() << "Running: git " << args.join(" "); 0442 0443 QProcess p; 0444 p.setProgram(QStringLiteral("git")); 0445 p.setArguments(args); 0446 p.setWorkingDirectory(mPath); 0447 p.start(); 0448 p.waitForFinished(); 0449 auto out = p.readAllStandardOutput(); 0450 auto err = p.readAllStandardError(); 0451 0452 if (p.exitStatus() == QProcess::CrashExit) { 0453 qWarning() << "=== Crash on git process ==="; 0454 qWarning() << "====\nERROR:\n====\n" << err; 0455 qWarning() << "====\nOUTPUR:\n====\n" << out; 0456 } 0457 return out; // + err; 0458 } 0459 0460 QStringList Manager::ls(const QString &place) const 0461 { 0462 auto buffer = readAllNonEmptyOutput({QStringLiteral("ls-tree"), QStringLiteral("--name-only"), QStringLiteral("-r"), place}); 0463 QMutableListIterator<QString> it(buffer); 0464 while (it.hasNext()) { 0465 auto s = it.next(); 0466 if (s.startsWith(QLatin1String("\"")) && s.endsWith(QLatin1String("\""))) 0467 it.setValue(s.mid(1, s.length() - 2)); 0468 } 0469 return buffer; 0470 } 0471 0472 QString Manager::fileContent(const QString &place, const QString &fileName) const 0473 { 0474 return runGit({QStringLiteral("show"), place + QLatin1Char(':') + fileName}); 0475 } 0476 0477 void Manager::saveFile(const QString &place, const QString &fileName, const QString &localFile) const 0478 { 0479 auto buffer = runGit({QStringLiteral("show"), place + QLatin1Char(':') + fileName}); 0480 QFile f{localFile}; 0481 if (!f.open(QIODevice::WriteOnly)) 0482 return; 0483 f.write(buffer); 0484 f.close(); 0485 } 0486 0487 QStringList Manager::branches() const 0488 { 0489 QStringList branchesList; 0490 auto out = QString(runGit({QStringLiteral("branch"), QStringLiteral("--list")})).split(QLatin1Char('\n')); 0491 0492 for (auto &line : out) { 0493 auto b = line.trimmed(); 0494 if (b.isEmpty()) 0495 continue; 0496 if (b.startsWith(QLatin1String("* "))) 0497 b = b.mid(2); 0498 0499 if (b.startsWith(QLatin1String("(HEAD detached at"))) 0500 continue; 0501 0502 branchesList.append(b.trimmed()); 0503 } 0504 return branchesList; 0505 } 0506 0507 QStringList Manager::remoteBranches() const 0508 { 0509 QStringList branchesList; 0510 const auto out = QString(runGit({QStringLiteral("branch"), QStringLiteral("--remote"), QStringLiteral("--list")})).split(QLatin1Char('\n')); 0511 0512 for (const auto &line : out) { 0513 auto b = line.trimmed(); 0514 if (b.isEmpty()) 0515 continue; 0516 if (b.startsWith(QStringLiteral("* "))) 0517 b = b.mid(2); 0518 0519 if (!b.contains(QStringLiteral("->"))) 0520 branchesList.append(b.trimmed()); 0521 } 0522 return branchesList; 0523 } 0524 0525 QStringList Manager::remotes() const 0526 { 0527 return readAllNonEmptyOutput({QStringLiteral("remote")}); 0528 } 0529 0530 QStringList Manager::tags() const 0531 { 0532 return readAllNonEmptyOutput({QStringLiteral("tag"), QStringLiteral("--list")}); 0533 } 0534 0535 void Manager::createTag(const QString &name, const QString &message) const 0536 { 0537 runGit({QStringLiteral("tag"), QStringLiteral("-a"), name, QStringLiteral("--message"), message}); 0538 } 0539 0540 QList<Stash> Manager::stashes() 0541 { 0542 QList<Stash> ret; 0543 const auto list = readAllNonEmptyOutput({QStringLiteral("stash"), QStringLiteral("list"), QStringLiteral("--format=format:%s%m%an%m%ae%m%aD")}); 0544 int id{0}; 0545 for (const auto &item : std::as_const(list)) { 0546 const auto parts = item.split(QStringLiteral(">")); 0547 if (parts.size() != 4) 0548 continue; 0549 0550 const auto subject = parts.first(); 0551 Stash stash(this, QStringLiteral("stash@{%1}").arg(id)); 0552 0553 stash.mSubject = subject; 0554 stash.mAuthorName = parts.at(1); 0555 stash.mAuthorEmail = parts.at(2); 0556 stash.mPushTime = QDateTime::fromString(parts.at(3), Qt::RFC2822Date); 0557 qCDebug(KOMMITLIB_LOG) << item << subject << stash.mPushTime; 0558 0559 ret.append(stash); 0560 id++; 0561 } 0562 return ret; 0563 } 0564 0565 void Manager::createStash(const QString &name) const 0566 { 0567 QStringList args{QStringLiteral("stash"), QStringLiteral("push")}; 0568 0569 if (!name.isEmpty()) 0570 args.append({QStringLiteral("--message"), name}); 0571 0572 const auto ret = runGit(args); 0573 qCDebug(KOMMITLIB_LOG) << ret; 0574 } 0575 0576 bool Manager::removeStash(const QString &name) const 0577 { 0578 runGit({QStringLiteral("stash"), QStringLiteral("drop"), name}); 0579 return true; 0580 } 0581 0582 bool Manager::applyStash(const QString &name) const 0583 { 0584 runGit({QStringLiteral("stash"), QStringLiteral("apply"), name}); 0585 return true; 0586 } 0587 0588 Remote Manager::remoteDetails(const QString &remoteName) 0589 { 0590 if (mRemotes.contains(remoteName)) 0591 return mRemotes.value(remoteName); 0592 Remote r; 0593 auto ret = QString(runGit({QStringLiteral("remote"), QStringLiteral("show"), remoteName})); 0594 r.parse(ret); 0595 mRemotes.insert(remoteName, r); 0596 return r; 0597 } 0598 0599 bool Manager::removeBranch(const QString &branchName) const 0600 { 0601 auto ret = readAllNonEmptyOutput({QStringLiteral("branch"), QStringLiteral("-D"), branchName}); 0602 return true; 0603 } 0604 0605 BlameData Manager::blame(const File &file) 0606 { 0607 BlameData b; 0608 auto lines = readAllNonEmptyOutput({QStringLiteral("--no-pager"), QStringLiteral("blame"), QStringLiteral("-l"), file.fileName()}); 0609 b.reserve(lines.size()); 0610 0611 for (auto &line : lines) { 0612 BlameDataRow row; 0613 row.commitHash = line.mid(0, 40); 0614 0615 auto metaIndex = line.indexOf(QLatin1Char(')')); 0616 row.code = line.mid(metaIndex + 1); 0617 0618 auto hash = row.commitHash; 0619 if (hash.startsWith(QLatin1Char('^'))) 0620 hash = hash.remove(0, 1); 0621 row.log = mLogsCache->findLogByHash(hash, LogsModel::LogMatchType::BeginMatch); 0622 0623 b.append(row); 0624 } 0625 0626 return b; 0627 } 0628 0629 void Manager::revertFile(const QString &filePath) const 0630 { 0631 runGit({QStringLiteral("checkout"), QStringLiteral("--"), filePath}); 0632 } 0633 0634 QMap<QString, ChangeStatus> Manager::changedFiles() const 0635 { 0636 // status --untracked-files=all --ignored --short --ignore-submodules --porcelain 0637 QMap<QString, ChangeStatus> statuses; 0638 const auto buffer = QString(runGit({QStringLiteral("status"), QStringLiteral("--short")})).split(QLatin1Char('\n')); 0639 0640 for (const auto &line : buffer) { 0641 if (!line.trimmed().size()) 0642 continue; 0643 0644 auto status0 = line.mid(0, 1).trimmed(); 0645 auto status1 = line.mid(1, 1).trimmed(); 0646 const auto fileName = line.mid(3); 0647 0648 if (status1 == QLatin1Char('M') || status0 == QLatin1Char('M')) 0649 statuses.insert(fileName, ChangeStatus::Modified); 0650 else if (status1 == QLatin1Char('A')) 0651 statuses.insert(fileName, ChangeStatus::Added); 0652 else if (status1 == QLatin1Char('D') || status0 == QLatin1Char('D')) 0653 statuses.insert(fileName, ChangeStatus::Removed); 0654 else if (status1 == QLatin1Char('R')) 0655 statuses.insert(fileName, ChangeStatus::Renamed); 0656 else if (status1 == QLatin1Char('C')) 0657 statuses.insert(fileName, ChangeStatus::Copied); 0658 else if (status1 == QLatin1Char('U')) 0659 statuses.insert(fileName, ChangeStatus::UpdatedButInmerged); 0660 else if (status1 == QLatin1Char('?')) 0661 statuses.insert(fileName, ChangeStatus::Untracked); 0662 else if (status1 == QLatin1Char('!')) 0663 statuses.insert(fileName, ChangeStatus::Ignored); 0664 else { 0665 qDebug() << __FUNCTION__ << "The status" << status1 << "is unknown"; 0666 statuses.insert(fileName, ChangeStatus::Unknown); 0667 } 0668 } 0669 return statuses; 0670 } 0671 0672 void Manager::commit(const QString &message) const 0673 { 0674 runGit({QStringLiteral("commit"), QStringLiteral("-m"), message}); 0675 } 0676 0677 void Manager::push() const 0678 { 0679 runGit({QStringLiteral("push"), QStringLiteral("origin"), QStringLiteral("master")}); 0680 } 0681 0682 void Manager::addFile(const QString &file) const 0683 { 0684 runGit({QStringLiteral("add"), file}); 0685 } 0686 0687 void Manager::removeFile(const QString &file, bool cached) const 0688 { 0689 QStringList args; 0690 args.append(QStringLiteral("rm")); 0691 if (cached) 0692 args.append(QStringLiteral("--cached")); 0693 args.append(file); 0694 runGit(args); 0695 } 0696 0697 bool Manager::isMerging() const 0698 { 0699 return m_isMerging; 0700 } 0701 0702 void Manager::setIsMerging(bool newIsMerging) 0703 { 0704 if (m_isMerging == newIsMerging) 0705 return; 0706 m_isMerging = newIsMerging; 0707 Q_EMIT isMergingChanged(); 0708 } 0709 0710 bool Manager::isRebasing() const 0711 { 0712 return m_isRebasing; 0713 } 0714 0715 void Manager::setIsRebasing(bool newIsRebasing) 0716 { 0717 if (m_isRebasing == newIsRebasing) 0718 return; 0719 m_isRebasing = newIsRebasing; 0720 emit isRebasingChanged(); 0721 } 0722 0723 } // namespace Git