gitrepository.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. #include "gitrepository.h"
  2. #include <QDebug>
  3. #include <QFileInfo>
  4. #include <QDir>
  5. #include <gitbranch.h>
  6. #include <gitcommit.h>
  7. #include <gittag.h>
  8. #include <gitremote.h>
  9. #include <gitdiff.h>
  10. #include <git2.h>
  11. GitRepository::GitRepository(const QString& root) : QObject(nullptr)
  12. {
  13. if(git_repository_open(&m_raw, root.toUtf8().data()) != 0) {
  14. qDebug() << "Cannot open repository";
  15. close();
  16. return;
  17. }
  18. m_root = root;
  19. m_path = git_repository_workdir(m_raw);
  20. m_name = m_path;//TODO: replace with Human readable name
  21. qDebug() << "New repo:" << m_name << m_root << m_path;
  22. readBranches();
  23. readTags();
  24. readRemotes();
  25. updateHead();
  26. }
  27. GitRepository::~GitRepository()
  28. {
  29. close();
  30. }
  31. void GitRepository::close()
  32. {
  33. if(m_raw) {
  34. git_repository_free(m_raw);
  35. }
  36. m_raw = nullptr;
  37. }
  38. void GitRepository::readBranches()
  39. {
  40. git_reference *branchRef;
  41. git_branch_t branchType;
  42. git_branch_iterator* iter;
  43. git_branch_iterator_new(&iter, m_raw, GIT_BRANCH_ALL);
  44. while(git_branch_next(&branchRef, &branchType, iter) == 0)
  45. {
  46. GitBranch* branch = new GitBranch(branchRef, branchType, this);
  47. m_branches.insert(branch->fullName(), QPointer<GitBranch>(branch));
  48. qDebug() << branch->fullName();
  49. qDebug() << branch->type();
  50. }
  51. emit branchesChanged();
  52. }
  53. void GitRepository::readTags()
  54. {
  55. git_tag_foreach(raw(),
  56. [](const char *name, git_oid *oid, void *payload) -> int
  57. {
  58. Q_UNUSED(payload)
  59. Q_UNUSED(name)
  60. GitRepository* repo = static_cast<GitRepository*>(payload);
  61. git_tag* tagraw = 0;
  62. if(git_tag_lookup(&tagraw, repo->raw(), oid) != 0) {
  63. qCritical() << "Invalid tag found. Broken repository";
  64. return 1;
  65. }
  66. GitTag* tag = new GitTag(tagraw, repo);
  67. if(tag->isValid()) {
  68. repo->m_tags.insert(tag->targetId(), tag);
  69. }
  70. qDebug() << "Tag found: " << tag->name() << tag->sha1();
  71. return 0;
  72. },
  73. this);
  74. }
  75. void GitRepository::readRemotes()
  76. {
  77. git_strarray str_array;
  78. git_remote_list(&str_array, raw());
  79. for(int i = 0; i < str_array.count; i++) {
  80. GitRemote* remote = GitRemote::fromName(QString::fromLatin1(str_array.strings[i]), this);
  81. if(remote) {
  82. m_remotes.insert(remote->name(), QPointer<GitRemote>(remote));
  83. }
  84. }
  85. // git_reference_foreach_glob(raw(),"refs/remotes/*", [](const char *name, void *payload) -> int
  86. // {
  87. // qDebug() << "Remotes: " << name;
  88. // return 0;
  89. //// if(git_reference_is_remote(reference)) {
  90. //// }
  91. // }, this);
  92. // git_remote* remoteRaw;
  93. // git_reference_is_remote()
  94. }
  95. void GitRepository::checkout(QObject* object)
  96. {
  97. git_checkout_options opts;
  98. git_checkout_init_options(&opts,GIT_CHECKOUT_OPTIONS_VERSION);
  99. opts.checkout_strategy = GIT_CHECKOUT_FORCE;//TODO: modify to merge policy
  100. opts.notify_flags = GIT_CHECKOUT_NOTIFY_ALL;
  101. opts.notify_cb = [](
  102. git_checkout_notify_t why,
  103. const char *path,
  104. const git_diff_file *baseline,
  105. const git_diff_file *target,
  106. const git_diff_file *workdir,
  107. void *payload) -> int
  108. {
  109. //TODO: make popup with progressbar
  110. // qDebug() << "path:" << path;
  111. // switch (why) {
  112. // case GIT_CHECKOUT_NOTIFY_CONFLICT:
  113. // qDebug() << "conflict";
  114. // break;
  115. // case GIT_CHECKOUT_NOTIFY_DIRTY:
  116. // qDebug() << "dirty";
  117. // break;
  118. // case GIT_CHECKOUT_NOTIFY_UPDATED:
  119. // qDebug() << "updated";
  120. // break;
  121. // case GIT_CHECKOUT_NOTIFY_UNTRACKED:
  122. // qDebug() << "untracked";
  123. // break;
  124. // case GIT_CHECKOUT_NOTIFY_IGNORED:
  125. // qDebug() << "ignored";
  126. // break;
  127. // default:
  128. // break;
  129. // }
  130. return 0;
  131. };
  132. GitOid oid;
  133. GitBranch* branch = dynamic_cast<GitBranch*>(object);
  134. GitCommit* commit = dynamic_cast<GitCommit*>(object);
  135. if(branch != nullptr) {
  136. commit = GitCommit::fromOid(branch->oid());
  137. qDebug() << "Checkout branch: " << git_checkout_tree(raw(), (git_object*)(commit->raw()), &opts);
  138. switch(branch->type()) {
  139. case GitBranch::Local:
  140. break;
  141. case GitBranch::Remote:
  142. git_reference* ref;
  143. //TODO: better to create API for local branch creation
  144. if(0 == git_branch_create_from_annotated(&ref, raw(), branch->name().toUtf8().data(), branch->annontatedCommit(), 0)) {
  145. branch = new GitBranch(ref, GIT_BRANCH_LOCAL, this);
  146. git_branch_set_upstream(ref, branch->fullName().toUtf8().data());
  147. m_branches.insert(branch->fullName(), QPointer<GitBranch>(branch));
  148. emit branchesChanged();
  149. } else if(m_branches.contains(branch->name())) { /*
  150. TODO: need to think how valid is this.
  151. In case if local branch already exists
  152. it will be checked out.
  153. But from commit tree perspective it doesn't
  154. look as valid behavior.
  155. */
  156. branch = m_branches.value(branch->name());
  157. }
  158. break;
  159. }
  160. git_repository_set_head(raw(), branch->refName().toLatin1().data());
  161. oid = branch->oid();
  162. delete commit;
  163. } else if(commit != nullptr) {
  164. qDebug() << "Checkout commit: " << git_checkout_tree(raw(), (git_object*)(commit->raw()), &opts);
  165. git_repository_set_head_detached(raw(), commit->oid().raw());
  166. oid = commit->oid();
  167. } else {
  168. qDebug() << "Invalid object for checkout";
  169. return;
  170. }
  171. setHead(oid);
  172. }
  173. void GitRepository::updateHead()
  174. {
  175. //Read head
  176. git_reference* ref = nullptr;
  177. git_repository_head(&ref, raw());
  178. git_annotated_commit* commit = nullptr;
  179. git_annotated_commit_from_ref(&commit, raw(), ref);
  180. setHead(GitOid(git_annotated_commit_id(commit), this));
  181. qDebug() << "Repo head" << m_head.toString();
  182. }