1#include "GitHistory.h"
2
3#include <CommitInfo.h>
4#include <GitBase.h>
5#include <GitConfig.h>
6
7#include <QLogger.h>
8
9#include <QStringLiteral>
10
11using namespace QLogger;
12
13GitHistory::GitHistory(const QSharedPointer<GitBase> &gitBase)
14 : mGitBase(gitBase)
15{
16}
17
18GitExecResult GitHistory::blame(const QString &file, const QString &commitFrom)
19{
20 QLog_Debug("Git", QString("Executing blame: {%1} from {%2}").arg(file, commitFrom));
21
22 const auto cmd = QString("git annotate %1 %2").arg(file, commitFrom);
23
24 QLog_Trace("Git", QString("Executing blame: {%1}").arg(cmd));
25
26 const auto ret = mGitBase->run(cmd);
27
28 return ret;
29}
30
31GitExecResult GitHistory::history(const QString &file)
32{
33 QLog_Debug("Git", QString("Executing history: {%1}").arg(file));
34
35 const auto cmd = QString("git log --follow --pretty=%H %1").arg(file);
36
37 QLog_Trace("Git", QString("Executing history: {%1}").arg(cmd));
38
39 auto ret = mGitBase->run(cmd);
40
41 if (ret.success && ret.output.isEmpty())
42 ret.success = false;
43
44 return ret;
45}
46
47GitExecResult GitHistory::getBranchesDiff(const QString &base, const QString &head)
48{
49 QLog_Debug("Git", QString("Getting diff between branches: {%1} and {%2}").arg(base, head));
50
51 QScopedPointer<GitConfig> git(new GitConfig(mGitBase));
52
53 QString fullBase = base;
54 auto retBase = git->getRemoteForBranch(base);
55
56 if (retBase.success)
57 fullBase.prepend(retBase.output + QStringLiteral("/"));
58
59 QString fullHead = head;
60 auto retHead = git->getRemoteForBranch(head);
61
62 if (retHead.success)
63 fullHead.prepend(retHead.output + QStringLiteral("/"));
64
65 const auto cmd = QString("git diff %1...%2").arg(fullBase, fullHead);
66
67 QLog_Trace("Git", QString("Getting diff between branches: {%1}").arg(cmd));
68
69 return mGitBase->run(cmd);
70}
71
72GitExecResult GitHistory::getCommitDiff(const QString &sha, const QString &diffToSha)
73{
74 if (!sha.isEmpty())
75 {
76 QLog_Debug("Git", QString("Executing diff for commit: {%1} to {%2}").arg(sha, diffToSha));
77
78 QString runCmd = QString("git diff-tree --no-color -r --patch-with-stat -m");
79
80 if (sha != CommitInfo::ZERO_SHA)
81 {
82 runCmd += " -C ";
83
84 if (diffToSha.isEmpty())
85 runCmd += " --root ";
86
87 runCmd.append(QString("%1 %2").arg(diffToSha, sha)); // diffToSha could be empty
88 }
89 else
90 runCmd = "git diff HEAD ";
91
92 QLog_Trace("Git", QString("Executing diff for commit: {%1}").arg(runCmd));
93
94 return mGitBase->run(runCmd);
95 }
96 else
97 QLog_Warning("Git", QString("Executing getCommitDiff with empty SHA"));
98
99 return qMakePair(false, QString());
100}
101
102GitExecResult GitHistory::getFileDiff(const QString &currentSha, const QString &previousSha, const QString &file,
103 bool isCached)
104{
105 QLog_Debug("Git", QString("Getting diff for a file: {%1} between {%2} and {%3}").arg(file, currentSha, previousSha));
106
107 auto cmd = QString("git diff %1 -w -U15000 ").arg(QString::fromUtf8(isCached ? "--cached" : ""));
108
109 if (currentSha.isEmpty() || currentSha == CommitInfo::ZERO_SHA)
110 cmd.append(file);
111 else
112 cmd.append(QString("%1 %2 %3").arg(previousSha, currentSha, file));
113
114 QLog_Trace("Git", QString("Getting diff for a file: {%1}").arg(cmd));
115
116 return mGitBase->run(cmd);
117}
118
119GitExecResult GitHistory::getDiffFiles(const QString &sha, const QString &diffToSha)
120{
121 QLog_Debug("Git", QString("Getting modified files between SHAs: {%1} to {%2}").arg(sha, diffToSha));
122
123 auto runCmd = QString("git diff-tree -C --no-color -r -m ");
124
125 if (!diffToSha.isEmpty() && sha != CommitInfo::ZERO_SHA)
126 runCmd.append(diffToSha + " " + sha);
127 else
128 runCmd.append("4b825dc642cb6eb9a060e54bf8d69288fbee4904 " + sha);
129
130 QLog_Trace("Git", QString("Getting modified files between SHAs: {%1}").arg(runCmd));
131
132 return mGitBase->run(runCmd);
133}
134
135GitExecResult GitHistory::getUntrackedFileDiff(const QString &file) const
136{
137 QLog_Debug("Git", QString("Getting diff for untracked file {%1}").arg(file));
138
139 auto cmd = QString("git add --intent-to-add %1").arg(file);
140
141 QLog_Trace("Git", QString("Simulating we stage the file: {%1}").arg(cmd));
142
143 if (auto ret = mGitBase->run(cmd); ret.success)
144 {
145 cmd = QString("git diff %1").arg(file);
146
147 QLog_Trace("Git", QString("Getting diff for untracked file: {%1}").arg(cmd));
148
149 const auto retDiff = mGitBase->run(cmd);
150
151 QLog_Trace("Git", QString("Resetting the file to its previous state: {%1}").arg(cmd));
152
153 cmd = QString("git reset %1").arg(file);
154
155 mGitBase->run(cmd);
156
157 return { true, retDiff.output };
158 }
159 else
160 return { false, "" };
161}
162