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.
21 #include <ATLComTime.h>
25 #include "UnicodeUtils.h"
37 this->m_ParentHash
.clear();
39 m_AuthorEmail
.Empty();
40 m_CommitterName
.Empty();
41 m_CommitterEmail
.Empty();
48 int GitRev::ParserParentFromCommit(const GIT_COMMIT
* commit
)
51 this->m_ParentHash
.clear();
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
));
61 int GitRev::ParserFromCommit(const GIT_COMMIT
*commit
)
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
);
85 int GitRev::ParserParentFromCommit(const git_commit
* commit
)
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
));
96 int GitRev::ParserFromCommit(const git_commit
* commit
)
101 int encode
= CP_UTF8
;
103 const char* encodingstr
= git_commit_message_encoding(commit
);
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');
122 m_Subject
= CUnicodeUtils::GetUnicode(msg
, encode
);
125 m_Subject
= CUnicodeUtils::GetUnicodeLengthSizeT(msg
, body
- msg
, encode
);
126 m_Body
= CUnicodeUtils::GetUnicode(body
+ 1, encode
);
132 int GitRev::GetCommitFromHash(git_repository
* repo
, const CGitHash
& hash
)
136 if (git_commit_lookup(commit
.GetPointer(), repo
, hash
) < 0)
138 m_sErr
= CGit::GetLibGit2LastErr();
142 return ParserFromCommit(commit
);
145 int GitRev::GetCommit(git_repository
* repo
, const CString
& refname
)
148 if (refname
.GetLength() >= 8 && wcsncmp(refname
, GitRev::GetWorkingCopy(), refname
.GetLength()) == 0)
151 m_Subject
= L
"Working Tree";
156 if (CGit::GetHash(repo
, hash
, refname
+ L
"^{}")) // add ^{} in order to dereference signed tags
158 m_sErr
= CGit::GetLibGit2LastErr();
162 return GetCommitFromHash(repo
, hash
);
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");
177 int GitRev::GetParentFromHash(const CGitHash
& hash
)
179 CAutoLocker
lock(g_Git
.m_critGitDllSec
);
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();
192 catch (const char* msg
)
194 m_sErr
= L
"Could not get parents of commit \"" + hash
.ToString() + L
"\".\nlibgit reports:\n" + CUnicodeUtils::GetUnicode(msg
);
198 this->ParserParentFromCommit(&commit
);
199 git_free_commit(&commit
);
201 this->m_CommitHash
=hash
;
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
)
220 if (git_get_commit_from_hash(&commit
, hash
.ToRaw()))
222 m_sErr
= L
"git_get_commit_from_hash failed for " + hash
.ToString();
226 catch (const char * msg
)
228 m_sErr
= L
"Could not get commit \"" + hash
.ToString() + L
"\".\nlibgit reports:\n" + CString(msg
);
232 this->ParserFromCommit(&commit
);
233 git_free_commit(&commit
);
240 int GitRev::GetCommit(const CString
& refname
)
242 if (g_Git
.UsingLibGit2(CGit::GIT_CMD_GET_COMMIT
))
244 CAutoRepository
repo(g_Git
.GetGitRepository());
247 m_sErr
= g_Git
.GetLibGit2LastErr();
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
);
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";
273 CStringA rev
= CUnicodeUtils::GetUTF8(g_Git
.FixBranchName(refname
+ L
"^{}")); // add ^{} in order to dereference signed tags
278 if (git_get_sha1(rev
.GetBuffer(), sha
))
280 m_sErr
= L
"Could not get SHA-1 of ref \"" + g_Git
.FixBranchName(refname
);
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
);
290 CGitHash hash
= CGitHash::FromRaw(sha
);
291 return GetCommitFromHash_withoutLock(hash
);
294 void GitRev::ApplyMailmap(const CGitMailmap
& mailmap
)
298 mailmap
.Translate(m_AuthorName
, m_AuthorEmail
);
299 mailmap
.Translate(m_CommitterName
, m_CommitterEmail
);