Fixed issue #2495: "Show Reflog" dialog shows empty action for "push" entries
[TortoiseGit.git] / src / Git / gitindex.h
blob718717647647b6a75cae853773acf8ca35dc41c5
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.
20 #include "GitHash.h"
21 #include "gitdll.h"
22 #include "GitStatus.h"
23 #include "UnicodeUtils.h"
24 #include "ReaderWriterLock.h"
25 #include "GitAdminDir.h"
27 class CGitIndex
29 public:
30 CString m_FileName;
31 __time64_t m_ModifyTime;
32 unsigned short m_Flags;
33 CGitHash m_IndexHash;
34 __int64 m_Size;
36 int Print();
39 class CGitIndexList:public std::vector<CGitIndex>
41 protected:
43 public:
44 __time64_t m_LastModifyTime;
46 CGitIndexList();
47 ~CGitIndexList();
49 int ReadIndex(CString file);
50 int GetStatus(const CString &gitdir, const CString &path, git_wc_status_kind * status, BOOL IsFull = false, BOOL IsRecursive = false, FILL_STATUS_CALLBACK callback = nullptr, void *pData = nullptr, CGitHash *pHash = nullptr, bool * assumeValid = nullptr, bool * skipWorktree = nullptr);
51 protected:
52 bool m_bCheckContent;
53 __int64 m_iMaxCheckSize;
54 CComCriticalSection m_critRepoSec;
55 CAutoRepository repository;
56 int GetFileStatus(const CString &gitdir, const CString &path, git_wc_status_kind * status, __int64 time, __int64 filesize, FILL_STATUS_CALLBACK callback = nullptr, void *pData = nullptr, CGitHash *pHash = nullptr, bool * assumeValid = nullptr, bool * skipWorktree = nullptr);
57 int GetDirStatus(const CString &gitdir, const CString &path, git_wc_status_kind * status,__int64 time, FILL_STATUS_CALLBACK callback = nullptr, void *pData = nullptr,CGitHash *pHash = nullptr);
60 typedef std::tr1::shared_ptr<CGitIndexList> SHARED_INDEX_PTR;
61 typedef CComCritSecLock<CComCriticalSection> CAutoLocker;
63 class CGitIndexFileMap:public std::map<CString, SHARED_INDEX_PTR>
65 public:
66 CComCriticalSection m_critIndexSec;
68 CGitIndexFileMap() { m_critIndexSec.Init(); }
69 ~CGitIndexFileMap() { m_critIndexSec.Term(); }
71 SHARED_INDEX_PTR SafeGet(const CString &path)
73 CString thePath = path;
74 thePath.MakeLower();
75 CAutoLocker lock(m_critIndexSec);
76 if(this->find(thePath) == end())
77 return SHARED_INDEX_PTR();
78 else
79 return (*this)[thePath];
82 void SafeSet(const CString &path, SHARED_INDEX_PTR ptr)
84 CString thePath = path;
85 thePath.MakeLower();
86 CAutoLocker lock(m_critIndexSec);
87 (*this)[thePath] = ptr;
90 bool SafeClear(const CString &path)
92 CString thePath = path;
93 thePath.MakeLower();
94 CAutoLocker lock(m_critIndexSec);
95 if (this->find(thePath) == end())
96 return false;
97 (*this)[thePath] = nullptr;
98 return true;
101 bool SafeClearRecursively(const CString &rootpath)
103 CString thePath = rootpath;
104 thePath.MakeLower();
105 CAutoLocker lock(m_critIndexSec);
106 for (auto it = this->begin(); it != this->end(); ++it)
108 if ((*it).first.Find(thePath) == 0)
109 (*this)[(*it).first] = nullptr;
111 return true;
114 int Check(const CString &gitdir, bool *isChanged);
115 int LoadIndex(const CString &gitdir);
117 bool CheckAndUpdate(const CString &gitdir,bool isLoadUpdatedIndex)
119 bool isChanged=false;
120 if(isLoadUpdatedIndex && Check(gitdir,&isChanged))
121 return false;
123 if(isChanged && isLoadUpdatedIndex)
125 LoadIndex(gitdir);
126 return true;
129 return false;
131 int GetFileStatus(const CString &gitdir,const CString &path,git_wc_status_kind * status,
132 BOOL IsFull=false, BOOL IsRecursive=false,
133 FILL_STATUS_CALLBACK callback = nullptr,
134 void *pData=NULL,CGitHash *pHash=NULL,
135 bool isLoadUpdatedIndex = true, bool * assumeValid = NULL, bool * skipWorktree = NULL);
137 int IsUnderVersionControl(const CString &gitdir,
138 const CString &path,
139 bool isDir,
140 bool *isVersion,
141 bool isLoadUpdateIndex=true);
145 class CGitTreeItem
147 public:
148 CString m_FileName;
149 CGitHash m_Hash;
150 int m_Flags;
153 /* After object create, never change field agains
154 * that needn't lock to get field
156 class CGitHeadFileList:public std::vector<CGitTreeItem>
158 private:
159 int GetPackRef(const CString &gitdir);
160 CReaderWriterLock m_SharedMutex;
162 __time64_t m_LastModifyTimeHead;
163 __time64_t m_LastModifyTimeRef;
164 __time64_t m_LastModifyTimePackRef;
166 CString m_HeadRefFile;
167 CGitHash m_Head;
168 CString m_HeadFile;
169 CString m_Gitdir;
170 CString m_PackRefFile;
172 CGitHash m_TreeHash; /* buffered tree hash value */
174 std::map<CString,CGitHash> m_PackRefMap;
176 public:
177 CGitHeadFileList()
179 m_LastModifyTimeHead=0;
180 m_LastModifyTimeRef=0;
181 m_LastModifyTimePackRef = 0;
184 int ReadTree();
185 int ReadHeadHash(CString gitdir);
186 bool CheckHeadUpdate();
187 bool HeadHashEqualsTreeHash();
188 bool HeadFileIsEmpty();
189 bool HeadIsEmpty();
190 static int CallBack(const unsigned char *, const char *, int, const char *, unsigned int, int, void *);
193 typedef std::tr1::shared_ptr<CGitHeadFileList> SHARED_TREE_PTR;
194 class CGitHeadFileMap:public std::map<CString,SHARED_TREE_PTR>
196 public:
198 CComCriticalSection m_critTreeSec;
200 CGitHeadFileMap() { m_critTreeSec.Init(); }
201 ~CGitHeadFileMap() { m_critTreeSec.Term(); }
203 SHARED_TREE_PTR SafeGet(const CString &path)
205 CString thePath = path;
206 thePath.MakeLower();
207 CAutoLocker lock(m_critTreeSec);
208 if(this->find(thePath) == end())
209 return SHARED_TREE_PTR();
210 else
211 return (*this)[thePath];
214 void SafeSet(const CString &path, SHARED_TREE_PTR ptr)
216 CString thePath = path;
217 thePath.MakeLower();
218 CAutoLocker lock(m_critTreeSec);
219 (*this)[thePath] = ptr;
222 int GetFileStatus(const CString &gitdir,const CString &path,git_wc_status_kind * status,BOOL IsFull=false, BOOL IsRecursive=false,
223 FILL_STATUS_CALLBACK callback = nullptr, void *pData = nullptr,
224 bool isLoaded=false);
225 bool CheckHeadAndUpdate(const CString &gitdir, bool readTree = true);
226 int IsUnderVersionControl(const CString &gitdir, const CString &path, bool isDir, bool *isVersion);
229 class CGitFileName
231 public:
232 CString m_FileName;
233 CString m_CaseFileName;
236 class CGitIgnoreItem
238 public:
239 CGitIgnoreItem()
241 m_LastModifyTime =0;
242 m_pExcludeList =NULL;
243 m_buffer = NULL;
245 ~CGitIgnoreItem()
247 if(m_pExcludeList)
248 git_free_exclude_list(m_pExcludeList);
249 free(m_buffer);
250 m_pExcludeList=NULL;
251 m_buffer = NULL;
253 __time64_t m_LastModifyTime;
254 CStringA m_BaseDir;
255 BYTE *m_buffer;
256 EXCLUDE_LIST m_pExcludeList;
258 int FetchIgnoreList(const CString &projectroot, const CString &file, bool isGlobal);
261 class CGitIgnoreList
263 private:
264 bool CheckFileChanged(const CString &path);
265 int FetchIgnoreFile(const CString &gitdir, const CString &gitignore, bool isGlobal);
267 int CheckIgnore(const CString &path, const CString &root, bool isDir);
268 int CheckFileAgainstIgnoreList(const CString &ignorefile, const CStringA &patha, const char * base, int &type);
270 // core.excludesfile stuff
271 std::map<CString, CString> m_CoreExcludesfiles;
272 CString m_sMsysGitBinPath;
273 DWORD m_dMsysGitBinPathLastChecked;
274 CReaderWriterLock m_coreExcludefilesSharedMutex;
275 // checks if the msysgit path has changed and return true/false
276 // if the path changed, the cache is update
277 // force is only ised in constructor
278 bool CheckAndUpdateMsysGitBinpath(bool force = true);
279 bool CheckAndUpdateCoreExcludefile(const CString &adminDir);
280 const CString GetWindowsHome();
282 public:
283 CReaderWriterLock m_SharedMutex;
285 CGitIgnoreList(){ CheckAndUpdateMsysGitBinpath(true); }
287 std::map<CString, CGitIgnoreItem> m_Map;
289 bool CheckIgnoreChanged(const CString &gitdir,const CString &path, bool isDir);
290 int LoadAllIgnoreFile(const CString &gitdir, const CString &path, bool isDir);
291 bool IsIgnore(const CString &path, const CString &root, bool isDir);
294 template<class T>
295 int GetRangeInSortVector(const T &vector, LPCTSTR pstr, int len, int *start, int *end, int pos)
297 if( pos < 0)
299 return -1;
301 if(start == 0 || end == NULL)
302 return -1;
304 *start=*end=-1;
306 if (vector.empty())
307 return -1;
309 if (pos >= (int)vector.size())
310 return -1;
312 if( _tcsnccmp(vector[pos].m_FileName, pstr,len) != 0)
314 for (int i = 0; i < (int)vector.size(); ++i)
316 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
318 if(*start<0)
319 *start =i;
320 *end =i;
323 return -1;
325 else
327 *start =0;
328 *end = (int)vector.size();
330 for (int i = pos; i < (int)vector.size(); ++i)
332 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
334 *end=i;
336 else
338 break;
341 for(int i=pos;i>=0;i--)
343 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
345 *start=i;
347 else
349 break;
353 return 0;
356 template<class T>
357 int SearchInSortVector(const T &vector, LPCTSTR pstr, int len)
359 int end = (int)vector.size() - 1;
360 int start = 0;
361 int mid = (start+end)/2;
363 if (vector.empty())
364 return -1;
366 while(!( start == end && start==mid))
368 int cmp;
369 if(len < 0)
370 cmp = _tcscmp(vector[mid].m_FileName,pstr);
371 else
372 cmp = _tcsnccmp( vector[mid].m_FileName,pstr,len );
374 if (cmp == 0)
375 return mid;
376 else if (cmp < 0)
377 start = mid + 1;
378 else // (cmp > 0)
379 end = mid;
381 mid=(start +end ) /2;
384 if(len <0)
386 if(_tcscmp(vector[mid].m_FileName,pstr) == 0)
387 return mid;
389 else
391 if(_tcsnccmp( vector[mid].m_FileName,pstr,len ) == 0)
392 return mid;
394 return -1;
397 class CGitAdminDirMap:public std::map<CString, CString>
399 public:
400 CComCriticalSection m_critIndexSec;
401 std::map<CString, CString> m_reverseLookup;
403 CGitAdminDirMap() { m_critIndexSec.Init(); }
404 ~CGitAdminDirMap() { m_critIndexSec.Term(); }
406 CString GetAdminDir(const CString &path)
408 CString thePath = path;
409 thePath.MakeLower();
410 CAutoLocker lock(m_critIndexSec);
411 if(this->find(thePath) == end())
413 if (PathIsDirectory(path + _T("\\.git")))
415 (*this)[thePath] = path + _T("\\.git\\");
416 m_reverseLookup[thePath + _T("\\.git")] = path;
417 return (*this)[thePath];
419 else
421 CString result = GitAdminDir::ReadGitLink(path, path + _T("\\.git"));
422 if (!result.IsEmpty())
424 (*this)[thePath] = result + _T("\\");
425 m_reverseLookup[result.MakeLower()] = path;
426 return (*this)[thePath];
429 return path + _T("\\.git\\"); // in case of an error stick to old behavior
432 else
433 return (*this)[thePath];
436 CString GetWorkingCopy(const CString &gitDir)
438 CString path = gitDir;
439 path.MakeLower();
440 CAutoLocker lock(m_critIndexSec);
441 if (m_reverseLookup.find(path) == m_reverseLookup.end())
442 return gitDir;
443 else
444 return m_reverseLookup[path];