1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2015 - 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"
27 class CException
; //Just in case afx.h is not included (cannot be included in every project which uses this file)
29 // provide an ASSERT macro for when compiled without MFC
31 // Don't use _asm here, it isn't supported by x64 version of compiler. In fact, MFC's ASSERT() is the same with _ASSERTE().
32 #define ASSERT(x) _ASSERTE(x)
35 typedef CComCritSecLock
<CComCriticalSection
> CAutoLocker
;
45 m_CallDiffAsync
= NULL
;
46 m_IsSimpleListReady
=0;
49 memset(&this->m_GitCommit
,0,sizeof(GIT_COMMIT
));
57 GitRev::GitRev(GitRev
& rev
)
60 GitRev
& GitRev::operator=(GitRev
&rev
)
68 this->m_Files
.Clear();
70 this->m_ParentHash
.clear();
71 m_CommitterName
.Empty();
72 m_CommitterEmail
.Empty();
81 int GitRev::CopyFrom(GitRev
&rev
,bool OmitParentAndMark
)
83 m_AuthorName
=rev
.m_AuthorName
;
84 m_AuthorEmail
=rev
.m_AuthorEmail
;
85 m_AuthorDate
=rev
.m_AuthorDate
;
86 m_CommitterName
=rev
.m_CommitterName
;
87 m_CommitterEmail
=rev
.m_CommitterEmail
;
88 m_CommitterDate
=rev
.m_CommitterDate
;
89 m_Subject
=rev
.m_Subject
;
91 m_CommitHash
=rev
.m_CommitHash
;
93 m_Action
=rev
.m_Action
;
94 m_IsFull
=rev
.m_IsFull
;
96 if(!OmitParentAndMark
)
98 m_ParentHash
=rev
.m_ParentHash
;
104 int GitRev::SafeGetSimpleList(CGit
*git
)
106 if(InterlockedExchange(&m_IsUpdateing
,TRUE
) == FALSE
)
108 m_SimpleFileList
.clear();
109 git
->CheckAndInitDll();
111 GIT_COMMIT_LIST list
;
113 memset(&commit
,0,sizeof(GIT_COMMIT
));
115 CAutoLocker
lock(g_Git
.m_critGitDllSec
);
119 if(git_get_commit_from_hash(&commit
, this->m_CommitHash
.m_hash
))
128 bool isRoot
= this->m_ParentHash
.empty();
129 git_get_commit_first_parent(&commit
,&list
);
130 while(git_get_commit_next_parent(&list
,parent
) == 0 || isRoot
)
137 git_root_diff(git
->GetGitSimpleListDiff(), commit
.m_hash
, &file
, &count
, 0);
139 git_do_diff(git
->GetGitSimpleListDiff(), parent
, commit
.m_hash
, &file
, &count
, 0);
152 for (int j
= 0; j
< count
; ++j
)
161 int mode
,IsBin
,inc
,dec
;
164 git_get_diff_file(git
->GetGitSimpleListDiff(), file
, j
, &newname
, &oldname
, &mode
, &IsBin
, &inc
, &dec
);
171 git
->StringAppend(&strnewname
, (BYTE
*)newname
, CP_UTF8
);
173 m_SimpleFileList
.push_back(strnewname
);
176 git_diff_flush(git
->GetGitSimpleListDiff());
180 InterlockedExchange(&m_IsUpdateing
,FALSE
);
181 InterlockedExchange(&m_IsSimpleListReady
, TRUE
);
182 git_free_commit(&commit
);
187 int GitRev::SafeFetchFullInfo(CGit
*git
)
189 if(InterlockedExchange(&m_IsUpdateing
,TRUE
) == FALSE
)
191 this->m_Files
.Clear();
192 git
->CheckAndInitDll();
194 GIT_COMMIT_LIST list
;
196 memset(&commit
,0,sizeof(GIT_COMMIT
));
198 CAutoLocker
lock(g_Git
.m_critGitDllSec
);
202 if (git_get_commit_from_hash(&commit
, this->m_CommitHash
.m_hash
))
212 git_get_commit_first_parent(&commit
,&list
);
213 bool isRoot
= (list
==NULL
);
215 while(git_get_commit_next_parent(&list
,parent
) == 0 || isRoot
)
223 git_root_diff(git
->GetGitDiff(), this->m_CommitHash
.m_hash
, &file
, &count
, 1);
225 git_do_diff(git
->GetGitDiff(), parent
, commit
.m_hash
, &file
, &count
, 1);
229 git_free_commit(&commit
);
238 for (int j
= 0; j
< count
; ++j
)
247 int mode
,IsBin
,inc
,dec
;
248 git_get_diff_file(git
->GetGitDiff(),file
,j
,&newname
,&oldname
,
249 &mode
,&IsBin
,&inc
,&dec
);
251 git
->StringAppend(&strnewname
, (BYTE
*)newname
, CP_UTF8
);
252 git
->StringAppend(&stroldname
, (BYTE
*)oldname
, CP_UTF8
);
254 path
.SetFromGit(strnewname
,&stroldname
);
255 path
.ParserAction((BYTE
)mode
);
258 this->m_Action
|=path
.m_Action
;
262 path
.m_StatAdd
=_T("-");
263 path
.m_StatDel
=_T("-");
267 path
.m_StatAdd
.Format(_T("%d"),inc
);
268 path
.m_StatDel
.Format(_T("%d"),dec
);
270 m_Files
.AddPath(path
);
272 git_diff_flush(git
->GetGitDiff());
277 InterlockedExchange(&m_IsUpdateing
,FALSE
);
278 InterlockedExchange(&m_IsFull
,TRUE
);
279 git_free_commit(&commit
);
285 int GitRev::ParserParentFromCommit(GIT_COMMIT
*commit
)
287 this->m_ParentHash
.clear();
288 GIT_COMMIT_LIST list
;
291 git_get_commit_first_parent(commit
,&list
);
292 while(git_get_commit_next_parent(&list
,parent
)==0)
294 m_ParentHash
.push_back(CGitHash((char *)parent
));
299 int GitRev::ParserFromCommit(GIT_COMMIT
*commit
)
303 if(commit
->m_Encode
!= 0 && commit
->m_EncodeSize
!= 0)
306 CGit::StringAppend(&str
, (BYTE
*)commit
->m_Encode
, CP_UTF8
, commit
->m_EncodeSize
);
307 encode
= CUnicodeUtils::GetCPCode(str
);
310 this->m_CommitHash
= commit
->m_hash
;
312 this->m_AuthorDate
= commit
->m_Author
.Date
;
314 this->m_AuthorEmail
.Empty();
315 CGit::StringAppend(&m_AuthorEmail
, (BYTE
*)commit
->m_Author
.Email
, encode
, commit
->m_Author
.EmailSize
);
317 this->m_AuthorName
.Empty();
318 CGit::StringAppend(&m_AuthorName
, (BYTE
*)commit
->m_Author
.Name
, encode
, commit
->m_Author
.NameSize
);
320 this->m_Body
.Empty();
321 CGit::StringAppend(&m_Body
, (BYTE
*)commit
->m_Body
, encode
, commit
->m_BodySize
);
323 this->m_CommitterDate
= commit
->m_Committer
.Date
;
325 this->m_CommitterEmail
.Empty();
326 CGit::StringAppend(&m_CommitterEmail
, (BYTE
*)commit
->m_Committer
.Email
, encode
, commit
->m_Committer
.EmailSize
);
328 this->m_CommitterName
.Empty();
329 CGit::StringAppend(&m_CommitterName
, (BYTE
*)commit
->m_Committer
.Name
, encode
, commit
->m_Committer
.NameSize
);
331 this->m_Subject
.Empty();
332 CGit::StringAppend(&m_Subject
, (BYTE
*)commit
->m_Subject
,encode
,commit
->m_SubjectSize
);
336 void GitRev::DbgPrint()
338 ATLTRACE(_T("Commit %s\r\n"), this->m_CommitHash
.ToString());
339 for (unsigned int i
= 0; i
< this->m_ParentHash
.size(); ++i
)
341 ATLTRACE(_T("Parent %i %s"), i
, m_ParentHash
[i
].ToString());
346 int GitRev::GetParentFromHash(CGitHash
&hash
)
348 CAutoLocker
lock(g_Git
.m_critGitDllSec
);
350 g_Git
.CheckAndInitDll();
353 if(git_get_commit_from_hash( &commit
, hash
.m_hash
))
356 this->ParserParentFromCommit(&commit
);
357 git_free_commit(&commit
);
359 this->m_CommitHash
=hash
;
363 int GitRev::GetCommitFromHash(CGitHash
&hash
)
365 CAutoLocker
lock(g_Git
.m_critGitDllSec
);
367 g_Git
.CheckAndInitDll();
369 return GetCommitFromHash_withoutLock(hash
);
372 int GitRev::GetCommitFromHash_withoutLock(CGitHash
&hash
)
377 if (git_get_commit_from_hash(&commit
, hash
.m_hash
))
382 MessageBox(NULL
, _T("Could not get commit \"") + hash
.ToString() + _T("\".\nlibgit reports:\n") + CString(msg
), _T("TortoiseGit"), MB_ICONERROR
);
386 this->ParserFromCommit(&commit
);
387 git_free_commit(&commit
);
393 int GitRev::GetCommit(CString refname
)
395 CAutoLocker
lock(g_Git
.m_critGitDllSec
);
397 g_Git
.CheckAndInitDll();
399 if(refname
.GetLength() >= 8)
400 if(refname
.Find(_T("00000000")) == 0)
402 this->m_CommitHash
.Empty();
403 this->m_Subject
=_T("Working Copy");
407 rev
= CUnicodeUtils::GetUTF8(g_Git
.FixBranchName(refname
));
412 if (git_get_sha1(rev
.GetBuffer(), sha
))
417 MessageBox(NULL
, _T("Could not get SHA-1 of ref \"") + g_Git
.FixBranchName(refname
) + _T("\".\nlibgit reports:\n") + CString(msg
), _T("TortoiseGit"), MB_ICONERROR
);
421 CGitHash
hash((char*)sha
);
422 GetCommitFromHash_withoutLock(hash
);
426 int GitRev::AddMergeFiles()
428 std::map
<CString
, int> map
;
429 std::map
<CString
, int>::iterator it
;
431 for (int i
= 0; i
< m_Files
.GetCount(); ++i
)
433 if(map
.find(m_Files
[i
].GetGitPathString()) == map
.end())
435 map
[m_Files
[i
].GetGitPathString()]=0;
439 ++map
[m_Files
[i
].GetGitPathString()];
443 for (it
= map
.begin(); it
!= map
.end(); ++it
)
448 path
.SetFromGit(it
->first
);
449 path
.m_ParentNo
= MERGE_MASK
;
450 path
.m_StatAdd
=_T("-");
451 path
.m_StatDel
=_T("-");
452 path
.m_Action
= CTGitPath::LOGACTIONS_MERGED
;
453 m_Files
.AddPath(path
);