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 | |
11 | using namespace QLogger; |
12 | |
13 | GitHistory::GitHistory(const QSharedPointer<GitBase> &gitBase) |
14 | : mGitBase(gitBase) |
15 | { |
16 | } |
17 | |
18 | GitExecResult 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 | |
31 | GitExecResult 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 | |
47 | GitExecResult 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 | |
72 | GitExecResult 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 | |
102 | GitExecResult GitHistory::getFileDiff(const QString ¤tSha, 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 | |
119 | GitExecResult 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 | |
135 | GitExecResult 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 | |