Can also refresh Rebase dialog by double clicking to delete conflict file
[TortoiseGit.git] / src / Git / GitRev.cpp
bloba6ff75f39f772173c6c38df6e2b62d7daa95bd8c
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2012 - 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 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
30 #if !defined ASSERT
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)
33 #endif
35 typedef CComCritSecLock<CComCriticalSection> CAutoLocker;
37 GitRev::GitRev(void)
39 m_Action=0;
40 m_IsFull = 0;
41 m_IsUpdateing = 0;
42 m_IsCommitParsed = 0;
43 m_IsDiffFiles = 0;
44 m_CallDiffAsync = NULL;
45 m_IsSimpleListReady =0;
47 memset(&this->m_GitCommit,0,sizeof(GIT_COMMIT));
49 // fetch local machine timezone info
50 if ( GetTimeZoneInformation( &m_TimeZone ) == TIME_ZONE_ID_INVALID )
52 ASSERT(false);
56 GitRev::~GitRev(void)
60 #if 0
61 GitRev::GitRev(GitRev & rev)
64 GitRev& GitRev::operator=(GitRev &rev)
66 return *this;
68 #endif
69 void GitRev::Clear()
71 this->m_Action=0;
72 this->m_Files.Clear();
73 this->m_Action=0;
74 this->m_ParentHash.clear();
75 m_CommitterName.Empty();
76 m_CommitterEmail.Empty();
77 m_Body.Empty();
78 m_Subject.Empty();
79 m_CommitHash.Empty();
80 m_Ref.Empty();
81 m_RefAction.Empty();
82 m_Mark=0;
85 int GitRev::CopyFrom(GitRev &rev,bool OmitParentAndMark)
87 m_AuthorName =rev.m_AuthorName;
88 m_AuthorEmail =rev.m_AuthorEmail;
89 m_AuthorDate =rev.m_AuthorDate;
90 m_CommitterName =rev.m_CommitterName;
91 m_CommitterEmail=rev.m_CommitterEmail;
92 m_CommitterDate =rev.m_CommitterDate;
93 m_Subject =rev.m_Subject;
94 m_Body =rev.m_Body;
95 m_CommitHash =rev.m_CommitHash;
96 m_Files =rev.m_Files;
97 m_Action =rev.m_Action;
98 m_IsFull =rev.m_IsFull;
100 if(!OmitParentAndMark)
102 m_ParentHash =rev.m_ParentHash;
103 m_Mark =rev.m_Mark;
105 return 0;
108 CTime GitRev::ConverFromString(CString input)
110 // pick up date from string
113 COleDateTime tm(_wtoi(input.Mid(0,4)),
114 _wtoi(input.Mid(5,2)),
115 _wtoi(input.Mid(8,2)),
116 _wtoi(input.Mid(11,2)),
117 _wtoi(input.Mid(14,2)),
118 _wtoi(input.Mid(17,2)));
119 if( tm.GetStatus() != COleDateTime::valid )
120 return CTime();//Error parsing time-string
122 // pick up utc offset
123 CString sign = input.Mid(20,1); // + or -
124 int hoursOffset = _wtoi(input.Mid(21,2));
125 int minsOffset = _wtoi(input.Mid(23,2));
126 // convert to a fraction of a day
127 double offset = (hoursOffset*60 + minsOffset) / 1440.0; // 1440 mins = 1 day
128 if ( sign == "-" )
130 offset = -offset;
132 // we have to subtract this from the time given to get UTC
133 tm -= offset;
134 // get utc time as a SYSTEMTIME
135 SYSTEMTIME sysTime;
136 tm.GetAsSystemTime( sysTime );
137 // and convert to users local time
138 SYSTEMTIME local;
139 if ( SystemTimeToTzSpecificLocalTime( &m_TimeZone, &sysTime, &local ) )
141 sysTime = local;
143 else
145 ASSERT(false); // this should not happen but leave time in utc if it does
147 // convert to CTime and return
148 return CTime( sysTime, -1 );
150 catch(CException* e)
152 //Probably the date was something like 1970-01-01 00:00:00. _mktime64() doesnt like this.
153 //Dont let the application crash on this exception
155 #ifdef _AFX //CException classes are only defined when afx.h is included.
156 //When afx.h is not included, the exception is leaked.
157 //This will probably never happen because when CException is not defined, it cannot be thrown.
158 e->Delete();
159 #endif //ifdef _AFX
160 UNREFERENCED_PARAMETER(e);
162 return CTime(); //Return an invalid time
165 int GitRev::SafeGetSimpleList(CGit *git)
167 if(InterlockedExchange(&m_IsUpdateing,TRUE) == FALSE)
169 m_SimpleFileList.clear();
170 git->CheckAndInitDll();
171 GIT_COMMIT commit;
172 GIT_COMMIT_LIST list;
173 GIT_HASH parent;
174 memset(&commit,0,sizeof(GIT_COMMIT));
176 CAutoLocker lock(g_Git.m_critGitDllSec);
180 if(git_get_commit_from_hash(&commit, this->m_CommitHash.m_hash))
181 return -1;
183 catch (char *)
185 return -1;
188 int i=0;
189 bool isRoot = this->m_ParentHash.empty();
190 git_get_commit_first_parent(&commit,&list);
191 while(git_get_commit_next_parent(&list,parent) == 0 || isRoot)
193 GIT_FILE file=0;
194 int count=0;
197 if(isRoot)
198 git_root_diff(git->GetGitSimpleListDiff(), commit.m_hash, &file, &count, 0);
199 else
200 git_diff(git->GetGitSimpleListDiff(), parent, commit.m_hash, &file, &count, 0);
202 catch (char *)
204 return -1;
207 isRoot = false;
209 CTGitPath path;
210 CString strnewname;
211 CString stroldname;
213 for(int j=0;j<count;j++)
215 path.Reset();
216 char *newname;
217 char *oldname;
219 strnewname.Empty();
220 stroldname.Empty();
222 int mode,IsBin,inc,dec;
225 git_get_diff_file(git->GetGitSimpleListDiff(), file, j, &newname, &oldname, &mode, &IsBin, &inc, &dec);
227 catch (char *)
229 return -1;
232 git->StringAppend(&strnewname, (BYTE*)newname, CP_UTF8);
234 m_SimpleFileList.push_back(strnewname);
237 git_diff_flush(git->GetGitSimpleListDiff());
238 i++;
241 InterlockedExchange(&m_IsUpdateing,FALSE);
242 InterlockedExchange(&m_IsSimpleListReady, TRUE);
243 git_free_commit(&commit);
246 return 0;
248 int GitRev::SafeFetchFullInfo(CGit *git)
250 if(InterlockedExchange(&m_IsUpdateing,TRUE) == FALSE)
252 this->m_Files.Clear();
253 git->CheckAndInitDll();
254 GIT_COMMIT commit;
255 GIT_COMMIT_LIST list;
256 GIT_HASH parent;
257 memset(&commit,0,sizeof(GIT_COMMIT));
259 CAutoLocker lock(g_Git.m_critGitDllSec);
263 if (git_get_commit_from_hash(&commit, this->m_CommitHash.m_hash))
264 return -1;
266 catch (char *)
268 return -1;
271 int i=0;
273 git_get_commit_first_parent(&commit,&list);
274 bool isRoot = (list==NULL);
276 while(git_get_commit_next_parent(&list,parent) == 0 || isRoot)
278 GIT_FILE file=0;
279 int count=0;
283 if (isRoot)
284 git_root_diff(git->GetGitDiff(), this->m_CommitHash.m_hash, &file, &count, 1);
285 else
286 git_diff(git->GetGitDiff(), parent, commit.m_hash, &file, &count, 1);
288 catch (char *)
290 git_free_commit(&commit);
291 return -1;
293 isRoot = false;
295 CTGitPath path;
296 CString strnewname;
297 CString stroldname;
299 for(int j=0;j<count;j++)
301 path.Reset();
302 char *newname;
303 char *oldname;
305 strnewname.Empty();
306 stroldname.Empty();
308 int mode,IsBin,inc,dec;
309 git_get_diff_file(git->GetGitDiff(),file,j,&newname,&oldname,
310 &mode,&IsBin,&inc,&dec);
312 git->StringAppend(&strnewname, (BYTE*)newname, CP_UTF8);
313 git->StringAppend(&stroldname, (BYTE*)oldname, CP_UTF8);
315 path.SetFromGit(strnewname,&stroldname);
316 path.ParserAction((BYTE)mode);
317 path.m_ParentNo = i;
319 this->m_Action|=path.m_Action;
321 if(IsBin)
323 path.m_StatAdd=_T("-");
324 path.m_StatDel=_T("-");
326 else
328 path.m_StatAdd.Format(_T("%d"),inc);
329 path.m_StatDel.Format(_T("%d"),dec);
331 m_Files.AddPath(path);
333 git_diff_flush(git->GetGitDiff());
334 i++;
338 InterlockedExchange(&m_IsUpdateing,FALSE);
339 InterlockedExchange(&m_IsFull,TRUE);
340 git_free_commit(&commit);
343 return 0;
346 int GitRev::ParserParentFromCommit(GIT_COMMIT *commit)
348 this->m_ParentHash.clear();
349 GIT_COMMIT_LIST list;
350 GIT_HASH parent;
352 git_get_commit_first_parent(commit,&list);
353 while(git_get_commit_next_parent(&list,parent)==0)
355 m_ParentHash.push_back(CGitHash((char *)parent));
357 return 0;
360 int GitRev::ParserFromCommit(GIT_COMMIT *commit)
362 int encode =CP_UTF8;
364 if(commit->m_Encode != 0 && commit->m_EncodeSize != 0)
366 CString str;
367 g_Git.StringAppend(&str, (BYTE*)commit->m_Encode, CP_UTF8, commit->m_EncodeSize);
368 encode = CUnicodeUtils::GetCPCode(str);
371 this->m_CommitHash = (char*)commit->m_hash;
373 this->m_AuthorDate = commit->m_Author.Date;
375 this->m_AuthorEmail.Empty();
376 g_Git.StringAppend(&m_AuthorEmail,(BYTE*)commit->m_Author.Email,encode,commit->m_Author.EmailSize);
378 this->m_AuthorName.Empty();
379 g_Git.StringAppend(&m_AuthorName,(BYTE*)commit->m_Author.Name,encode,commit->m_Author.NameSize);
381 this->m_Body.Empty();
382 g_Git.StringAppend(&m_Body,(BYTE*)commit->m_Body,encode,commit->m_BodySize);
384 this->m_CommitterDate = commit->m_Committer.Date;
386 this->m_CommitterEmail.Empty();
387 g_Git.StringAppend(&m_CommitterEmail, (BYTE*)commit->m_Committer.Email,encode, commit->m_Committer.EmailSize);
389 this->m_CommitterName.Empty();
390 g_Git.StringAppend(&m_CommitterName, (BYTE*)commit->m_Committer.Name,encode, commit->m_Committer.NameSize);
392 this->m_Subject.Empty();
393 g_Git.StringAppend(&m_Subject, (BYTE*)commit->m_Subject,encode,commit->m_SubjectSize);
395 return 0;
397 void GitRev::DbgPrint()
399 ATLTRACE(_T("Commit %s\r\n"), this->m_CommitHash.ToString());
400 for(unsigned int i=0;i<this->m_ParentHash.size();i++)
402 ATLTRACE(_T("Parent %i %s"), i, m_ParentHash[i].ToString());
404 ATLTRACE(_T("\n"));
407 int GitRev::GetParentFromHash(CGitHash &hash)
409 CAutoLocker lock(g_Git.m_critGitDllSec);
411 g_Git.CheckAndInitDll();
413 GIT_COMMIT commit;
414 if(git_get_commit_from_hash( &commit, hash.m_hash))
415 return -1;
417 this->ParserParentFromCommit(&commit);
418 git_free_commit(&commit);
420 this->m_CommitHash=hash;
422 return 0;
424 int GitRev::GetCommitFromHash(CGitHash &hash)
426 CAutoLocker lock(g_Git.m_critGitDllSec);
428 g_Git.CheckAndInitDll();
430 return GetCommitFromHash_withoutLock(hash);
433 int GitRev::GetCommitFromHash_withoutLock(CGitHash &hash)
435 GIT_COMMIT commit;
436 if(git_get_commit_from_hash( &commit, hash.m_hash))
437 return -1;
439 this->ParserFromCommit(&commit);
440 git_free_commit(&commit);
442 return 0;
446 int GitRev::GetCommit(CString refname)
448 CAutoLocker lock(g_Git.m_critGitDllSec);
450 g_Git.CheckAndInitDll();
452 if(refname.GetLength() >= 8)
453 if(refname.Find(_T("00000000")) == 0)
455 this->m_CommitHash.Empty();
456 this->m_Subject=_T("Working Copy");
457 return 0;
459 CStringA rev;
460 rev= CUnicodeUtils::GetUTF8(g_Git.FixBranchName(refname));
461 GIT_HASH sha;
463 if(git_get_sha1(rev.GetBuffer(),sha))
464 return -1;
466 CGitHash hash((char*)sha);
467 GetCommitFromHash_withoutLock(hash);
468 return 0;
471 int GitRev::AddMergeFiles()
473 std::map<CString, int> map;
474 std::map<CString, int>::iterator it;
476 for(int i=0;i<m_Files.GetCount();i++)
478 if(map.find(m_Files[i].GetGitPathString()) == map.end())
480 map[m_Files[i].GetGitPathString()]=0;
482 else
484 map[m_Files[i].GetGitPathString()]++;
488 for(it=map.begin();it!=map.end();it++)
490 if(it->second)
492 CTGitPath path;
493 path.SetFromGit(it->first);
494 path.m_ParentNo = MERGE_MASK;
495 path.m_StatAdd=_T("-");
496 path.m_StatDel=_T("-");
497 path.m_Action = CTGitPath::LOGACTIONS_MERGED;
498 m_Files.AddPath(path);
501 return 0;