Fixed issue #4126: Capitalize the first letter in the Push dialog
[TortoiseGit.git] / src / Git / GitRev.cpp
blobbc1e6239925cd4fdd052e3495d44ef23e6215876
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2016, 2018-2021, 2023 - TortoiseGit
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "stdafx.h"
21 #include <ATLComTime.h>
22 #include "GitRev.h"
23 #include "Git.h"
24 #include "gitdll.h"
25 #include "UnicodeUtils.h"
27 GitRev::GitRev()
31 GitRev::~GitRev()
35 void GitRev::Clear()
37 this->m_ParentHash.clear();
38 m_AuthorName.Empty();
39 m_AuthorEmail.Empty();
40 m_CommitterName.Empty();
41 m_CommitterEmail.Empty();
42 m_Body.Empty();
43 m_Subject.Empty();
44 m_CommitHash.Empty();
45 m_sErr.Empty();
48 int GitRev::ParserParentFromCommit(const GIT_COMMIT* commit)
50 ATLASSERT(commit);
51 this->m_ParentHash.clear();
52 GIT_COMMIT_LIST list;
53 GIT_HASH parent;
55 git_get_commit_first_parent(commit,&list);
56 while(git_get_commit_next_parent(&list,parent)==0)
57 m_ParentHash.emplace_back(CGitHash::FromRaw(parent));
58 return 0;
61 int GitRev::ParserFromCommit(const GIT_COMMIT *commit)
63 ATLASSERT(commit);
64 int encode =CP_UTF8;
65 if(commit->m_Encode != 0 && commit->m_EncodeSize != 0)
66 encode = CUnicodeUtils::GetCPCode(CUnicodeUtils::GetUnicodeLength(commit->m_Encode, commit->m_EncodeSize));
68 this->m_CommitHash = CGitHash::FromRaw(commit->m_hash);
70 this->m_AuthorDate = commit->m_Author.Date;
71 this->m_AuthorEmail = CUnicodeUtils::GetUnicodeLength(commit->m_Author.Email, commit->m_Author.EmailSize, encode);
72 this->m_AuthorName = CUnicodeUtils::GetUnicodeLength(commit->m_Author.Name, commit->m_Author.NameSize, encode);
74 this->m_Body = CUnicodeUtils::GetUnicodeLength(commit->m_Body, commit->m_BodySize, encode);
76 this->m_CommitterDate = commit->m_Committer.Date;
77 this->m_CommitterEmail = CUnicodeUtils::GetUnicodeLength(commit->m_Committer.Email, commit->m_Committer.EmailSize, encode);
78 this->m_CommitterName = CUnicodeUtils::GetUnicodeLength(commit->m_Committer.Name, commit->m_Committer.NameSize, encode);
80 this->m_Subject = CUnicodeUtils::GetUnicodeLength(commit->m_Subject, commit->m_SubjectSize, encode);
82 return 0;
85 int GitRev::ParserParentFromCommit(const git_commit* commit)
87 ATLASSERT(commit);
88 m_ParentHash.clear();
89 const unsigned int parentCount = git_commit_parentcount(commit);
90 for (unsigned int i = 0; i < parentCount; ++i)
91 m_ParentHash.emplace_back(git_commit_parent_id(commit, i));
93 return 0;
96 int GitRev::ParserFromCommit(const git_commit* commit)
98 ATLASSERT(commit);
99 Clear();
101 int encode = CP_UTF8;
103 const char* encodingstr = git_commit_message_encoding(commit);
104 if (encodingstr)
105 encode = CUnicodeUtils::GetCPCode(CUnicodeUtils::GetUnicode(encodingstr));
107 m_CommitHash = git_commit_id(commit);
109 const git_signature* author = git_commit_author(commit);
110 m_AuthorDate = author->when.time;
111 m_AuthorEmail = CUnicodeUtils::GetUnicode(author->email, encode);
112 m_AuthorName = CUnicodeUtils::GetUnicode(author->name, encode);
114 const git_signature* committer = git_commit_committer(commit);
115 m_CommitterDate = committer->when.time;
116 m_CommitterEmail = CUnicodeUtils::GetUnicode(committer->email, encode);
117 m_CommitterName = CUnicodeUtils::GetUnicode(committer->name, encode);
119 const char* msg = git_commit_message_raw(commit);
120 const char* body = strchr(msg, '\n');
121 if (!body)
122 m_Subject = CUnicodeUtils::GetUnicode(msg, encode);
123 else
125 m_Subject = CUnicodeUtils::GetUnicodeLengthSizeT(msg, body - msg, encode);
126 m_Body = CUnicodeUtils::GetUnicode(body + 1, encode);
129 return 0;
132 int GitRev::GetCommitFromHash(git_repository* repo, const CGitHash& hash)
134 ATLASSERT(repo);
135 CAutoCommit commit;
136 if (git_commit_lookup(commit.GetPointer(), repo, hash) < 0)
138 m_sErr = CGit::GetLibGit2LastErr();
139 return -1;
142 return ParserFromCommit(commit);
145 int GitRev::GetCommit(git_repository* repo, const CString& refname)
147 ATLASSERT(repo);
148 if (refname.GetLength() >= 8 && wcsncmp(refname, GitRev::GetWorkingCopy(), refname.GetLength()) == 0)
150 Clear();
151 m_Subject = L"Working Tree";
152 return 0;
155 CGitHash hash;
156 if (CGit::GetHash(repo, hash, refname + L"^{}")) // add ^{} in order to dereference signed tags
158 m_sErr = CGit::GetLibGit2LastErr();
159 return -1;
162 return GetCommitFromHash(repo, hash);
165 #if DEBUG
166 void GitRev::DbgPrint()
168 ATLTRACE(L"Commit %s\r\n", static_cast<LPCWSTR>(this->m_CommitHash.ToString()));
169 for (unsigned int i = 0; i < this->m_ParentHash.size(); ++i)
171 ATLTRACE(L"Parent %i %s\r\n", i, static_cast<LPCWSTR>(m_ParentHash[i].ToString()));
173 ATLTRACE(L"\r\n\r\n");
175 #endif
177 int GitRev::GetParentFromHash(const CGitHash& hash)
179 CAutoLocker lock(g_Git.m_critGitDllSec);
181 GIT_COMMIT commit;
184 g_Git.CheckAndInitDll();
186 if (git_get_commit_from_hash(&commit, hash.ToRaw()))
188 m_sErr = L"git_get_commit_from_hash failed for " + hash.ToString();
189 return -1;
192 catch (const char* msg)
194 m_sErr = L"Could not get parents of commit \"" + hash.ToString() + L"\".\nlibgit reports:\n" + CUnicodeUtils::GetUnicode(msg);
195 return -1;
198 this->ParserParentFromCommit(&commit);
199 git_free_commit(&commit);
201 this->m_CommitHash=hash;
203 return 0;
206 int GitRev::GetCommitFromHash(const CGitHash& hash)
208 CAutoLocker lock(g_Git.m_critGitDllSec);
210 g_Git.CheckAndInitDll();
212 return GetCommitFromHash_withoutLock(hash);
215 int GitRev::GetCommitFromHash_withoutLock(const CGitHash& hash)
217 GIT_COMMIT commit;
220 if (git_get_commit_from_hash(&commit, hash.ToRaw()))
222 m_sErr = L"git_get_commit_from_hash failed for " + hash.ToString();
223 return -1;
226 catch (const char * msg)
228 m_sErr = L"Could not get commit \"" + hash.ToString() + L"\".\nlibgit reports:\n" + CString(msg);
229 return -1;
232 this->ParserFromCommit(&commit);
233 git_free_commit(&commit);
235 m_sErr.Empty();
237 return 0;
240 int GitRev::GetCommit(const CString& refname)
242 if (g_Git.UsingLibGit2(CGit::GIT_CMD_GET_COMMIT))
244 CAutoRepository repo(g_Git.GetGitRepository());
245 if (!repo)
247 m_sErr = g_Git.GetLibGit2LastErr();
248 return -1;
250 return GetCommit(repo, refname);
253 CAutoLocker lock(g_Git.m_critGitDllSec);
257 g_Git.CheckAndInitDll();
259 catch (const char* msg)
261 m_sErr = L"Could not initiate libgit.\nlibgit reports:\n" + CUnicodeUtils::GetUnicode(msg);
262 return -1;
265 if(refname.GetLength() >= 8)
266 if (refname.GetLength() >= 8 && wcsncmp(refname, GitRev::GetWorkingCopy(), refname.GetLength()) == 0)
268 this->m_CommitHash.Empty();
269 this->m_Subject = L"Working Tree";
270 m_sErr.Empty();
271 return 0;
273 CStringA rev = CUnicodeUtils::GetUTF8(g_Git.FixBranchName(refname + L"^{}")); // add ^{} in order to dereference signed tags
274 GIT_HASH sha;
278 if (git_get_sha1(rev.GetBuffer(), sha))
280 m_sErr = L"Could not get SHA-1 of ref \"" + g_Git.FixBranchName(refname);
281 return -1;
284 catch (const char* msg)
286 m_sErr = L"Could not get SHA-1 of ref \"" + g_Git.FixBranchName(refname) + L"\".\nlibgit reports:\n" + CUnicodeUtils::GetUnicode(msg);
287 return -1;
290 CGitHash hash = CGitHash::FromRaw(sha);
291 return GetCommitFromHash_withoutLock(hash);
294 void GitRev::ApplyMailmap(const CGitMailmap& mailmap)
296 if (!mailmap)
297 return;
298 mailmap.Translate(m_AuthorName, m_AuthorEmail);
299 mailmap.Translate(m_CommitterName, m_CommitterEmail);