gitbranch.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. #include "gitbranch.h"
  2. #include <QDebug>
  3. #include <gitrepository.h>
  4. #include <git2.h>
  5. namespace {
  6. const char remoteAddtion = '/';
  7. }
  8. GitBranch::GitBranch() : GitReference(nullptr, nullptr)
  9. ,m_commit(nullptr)
  10. ,m_type(GitBranch::Invalid)
  11. {
  12. }
  13. GitBranch::GitBranch(git_reference *ref, git_branch_t type, GitRepository *parent) : GitReference(ref, parent)
  14. ,m_commit(nullptr)
  15. ,m_type(static_cast<BranchType>(type))
  16. {
  17. const char* tmpName;
  18. git_branch_name(&tmpName, m_raw);
  19. m_fullName = tmpName;
  20. m_name = m_fullName;
  21. git_annotated_commit_from_ref(&m_commit, repository()->raw(), m_raw);
  22. m_oid = GitOid(git_annotated_commit_id(m_commit), m_repository);
  23. git_buf buf = GIT_BUF_INIT_CONST("",0);
  24. if(git_branch_remote_name(&buf, repository()->raw(), refName().toUtf8().data()) == 0) {
  25. m_remote = QString::fromUtf8(buf.ptr);
  26. m_name.remove(m_remote + remoteAddtion);
  27. }
  28. }
  29. GitBranch::GitBranch(GitBranch&& other) : GitReference(std::move(other))
  30. {
  31. //TODO: looks like free() functionality might be more common for GitBase childred.
  32. //Need to think about it
  33. if(m_commit != nullptr) {
  34. git_annotated_commit_free(m_commit);
  35. m_commit = nullptr;
  36. }
  37. m_commit = other.m_commit;
  38. other.m_commit = nullptr;
  39. other.m_type = GitBranch::Invalid;
  40. }
  41. GitBranch &GitBranch::operator=(GitBranch&& other)
  42. {
  43. if(&other != this) {
  44. if(m_commit != nullptr) {
  45. git_annotated_commit_free(m_commit);
  46. m_commit = nullptr;
  47. }
  48. m_commit = other.m_commit;
  49. other.m_commit = nullptr;
  50. other.m_type = GitBranch::Invalid;
  51. }
  52. return static_cast<GitBranch&>(GitReference::operator=(std::move(other)));
  53. }
  54. GitBranch::~GitBranch()
  55. {
  56. if(m_commit != nullptr) {
  57. git_annotated_commit_free(m_commit);
  58. m_commit = nullptr;
  59. }
  60. }
  61. GitBranch::BranchType GitBranch::type() const
  62. {
  63. return m_type;
  64. }
  65. void GitBranch::setUpstream(const GitBranch& branch)
  66. {
  67. if(type() == GitBranch::Remote
  68. || branch.type() == GitBranch::Local) {
  69. qWarning() << "Try to setup invalid pair of upstream/local branches";
  70. return;
  71. }
  72. git_branch_set_upstream(branch.raw(), branch.fullName().toUtf8().data());
  73. }
  74. GitBranch GitBranch::upstream() const
  75. {
  76. git_reference* ref = nullptr;
  77. if(type() == GitBranch::Remote) {
  78. qDebug() << "Skipping upstream read for remote branch";
  79. return GitBranch();
  80. }
  81. if(git_branch_upstream(&ref, raw()) != 0) {
  82. qWarning() << "Invalid reference or branch type" << GitBase::lastError();
  83. return GitBranch();
  84. }
  85. return GitBranch(ref, GIT_BRANCH_REMOTE, repository());
  86. }
  87. void GitBranch::pull(PullStrategy strategy)
  88. {
  89. if(type() == GitBranch::Remote) {
  90. qWarning() << "It's not possible to update remote branch, seems issue in branch handling logic";
  91. return;
  92. }
  93. GitBranch upstreamBranch = upstream();
  94. qDebug() << "Upstream branch for " << fullName() << " is " << upstreamBranch.fullName();
  95. git_annotated_commit* upstreamCommit = upstreamBranch.annotatedCommit();
  96. git_merge_analysis_t analResult;
  97. git_merge_preference_t preferences;
  98. git_merge_analysis(&analResult, &preferences, m_repository->raw(), (const git_annotated_commit**)&upstreamCommit, 1);
  99. if (analResult & GIT_MERGE_ANALYSIS_UP_TO_DATE) {
  100. qDebug() << "Up-to-date";
  101. return;
  102. }
  103. if (analResult & GIT_MERGE_ANALYSIS_FASTFORWARD) {
  104. qDebug() << "Fast-forward possible";
  105. fastForward();
  106. return;
  107. }
  108. if(analResult & GIT_MERGE_ANALYSIS_UNBORN) {
  109. qWarning() << "Merge is impossible";
  110. return;
  111. }
  112. switch (strategy) {
  113. case Merge:
  114. //TDB: Apply merge strategy
  115. break;
  116. default:
  117. rebase(upstreamCommit);
  118. break;
  119. }
  120. qWarning() << "Other merge methods are not supported yet";
  121. }
  122. void GitBranch::fastForward()
  123. {
  124. git_reference *newRaw = nullptr;
  125. if(0 == git_reference_set_target(&newRaw, m_raw, upstream().oid().raw(), "Update branch HEAD using fast-forward")) {
  126. git_reference_free(m_raw);
  127. m_raw = newRaw;
  128. } else {
  129. qWarning() << "Could not apply fast-forward " << lastError();
  130. }
  131. }
  132. void GitBranch::rebase(git_annotated_commit *upstreamCommit)
  133. {
  134. if(!isValid() || upstreamCommit == nullptr) {
  135. qWarning() << "Trying to reabase with invalid inputs";
  136. return;
  137. }
  138. git_rebase *rebase;
  139. git_rebase_options options = GIT_REBASE_OPTIONS_INIT;
  140. git_rebase_init(&rebase, m_repository->raw(), m_commit, upstreamCommit, NULL, &options);
  141. while(true) {
  142. git_rebase_operation *operation = nullptr;
  143. if(git_rebase_next(&operation, rebase) != 0) {
  144. break;
  145. }
  146. if(operation->type != GIT_REBASE_OPERATION_PICK) {
  147. qDebug() << "Rebase failed";
  148. git_rebase_free(rebase);
  149. return;
  150. }
  151. }
  152. git_index *index;
  153. git_repository_index(&index, m_repository->raw());
  154. if(git_index_has_conflicts(index) == 1) {
  155. qDebug() << "Conflicts found";
  156. git_index_free(index);
  157. git_rebase_free(rebase);
  158. return;
  159. }
  160. git_signature *signature;
  161. git_signature_default(&signature, m_repository->raw());
  162. git_oid commit_id;
  163. git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL);
  164. git_rebase_free(rebase);
  165. git_signature_free(signature);
  166. }