Add move-assign operator
[TortoiseGit.git] / src / Git / GitStatus.cpp
blob3a9b0d459d38fa9ab31d929ff60ee3af2d5a8c6d
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2016 - 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 "registry.h"
22 #include "..\TortoiseShell\resource.h"
23 #include "GitStatus.h"
24 #include "UnicodeUtils.h"
25 #include "Git.h"
26 #include "gitindex.h"
27 #include "ShellCache.h"
28 #include "SysInfo.h"
30 extern CGitAdminDirMap g_AdminDirMap;
31 extern CGitIndexFileMap g_IndexFileMap;
32 CGitHeadFileMap g_HeadFileMap;
33 CGitIgnoreList g_IgnoreList;
35 GitStatus::GitStatus()
36 : status(nullptr)
38 m_status.assumeValid = m_status.skipWorktree = false;
39 m_status.prop_status = m_status.text_status = git_wc_status_none;
42 GitStatus::~GitStatus(void)
46 // static method
47 #ifndef TGITCACHE
48 git_wc_status_kind GitStatus::GetAllStatus(const CTGitPath& path, git_depth_t depth, bool * assumeValid, bool * skipWorktree)
50 git_wc_status_kind statuskind;
51 BOOL err;
52 BOOL isDir;
53 CString sProjectRoot;
55 isDir = path.IsDirectory();
56 if (!path.HasAdminDir(&sProjectRoot))
57 return git_wc_status_none;
59 // rev.kind = git_opt_revision_unspecified;
60 statuskind = git_wc_status_none;
62 const BOOL bIsRecursive = (depth == git_depth_infinity || depth == git_depth_unknown); // taken from SVN source
64 CString sSubPath;
65 CString s = path.GetWinPathString();
66 if (s.GetLength() > sProjectRoot.GetLength())
68 if (sProjectRoot.GetLength() == 3 && sProjectRoot[1] == _T(':'))
69 sSubPath = s.Right(s.GetLength() - sProjectRoot.GetLength());
70 else
71 sSubPath = s.Right(s.GetLength() - sProjectRoot.GetLength() - 1/*otherwise it gets initial slash*/);
74 bool isfull = ((DWORD)CRegStdDWORD(_T("Software\\TortoiseGit\\CacheType"),
75 GetSystemMetrics(SM_REMOTESESSION) ? ShellCache::dll : ShellCache::exe) == ShellCache::dllFull);
77 if(isDir)
79 err = GetDirStatus(sProjectRoot, sSubPath, &statuskind, isfull, bIsRecursive, isfull);
80 // folders must not be displayed as added or deleted only as modified (this is for Shell Overlay-Modes)
81 if (statuskind == git_wc_status_unversioned && sSubPath.IsEmpty())
82 statuskind = git_wc_status_normal;
83 else if (statuskind == git_wc_status_deleted || statuskind == git_wc_status_added)
84 statuskind = git_wc_status_modified;
86 else
87 err = GetFileStatus(sProjectRoot, sSubPath, &statuskind, isfull, false, isfull, nullptr, nullptr, assumeValid, skipWorktree);
89 return statuskind;
91 #endif
93 // static method
94 git_wc_status_kind GitStatus::GetMoreImportant(git_wc_status_kind status1, git_wc_status_kind status2)
96 if (GetStatusRanking(status1) >= GetStatusRanking(status2))
97 return status1;
98 return status2;
100 // static private method
101 int GitStatus::GetStatusRanking(git_wc_status_kind status)
103 switch (status)
105 case git_wc_status_none:
106 return 0;
107 case git_wc_status_unversioned:
108 return 1;
109 case git_wc_status_ignored:
110 return 2;
111 case git_wc_status_incomplete:
112 return 4;
113 case git_wc_status_normal:
114 case git_wc_status_external:
115 return 5;
116 case git_wc_status_added:
117 return 6;
118 case git_wc_status_missing:
119 return 7;
120 case git_wc_status_deleted:
121 return 8;
122 case git_wc_status_replaced:
123 return 9;
124 case git_wc_status_modified:
125 return 10;
126 case git_wc_status_merged:
127 return 11;
128 case git_wc_status_conflicted:
129 return 12;
130 case git_wc_status_obstructed:
131 return 13;
133 return 0;
136 #ifndef TGITCACHE
137 void GitStatus::GetStatus(const CTGitPath& path, bool /*update*/ /* = false */, bool noignore /* = false */, bool /*noexternals*/ /* = false */)
139 // NOTE: unlike the SVN version this one does not cache the enumerated files, because in practice no code in all of
140 // Tortoise uses this, all places that call GetStatus create a temp GitStatus object which gets destroyed right
141 // after the call again
143 CString sProjectRoot;
144 if ( !path.HasAdminDir(&sProjectRoot) )
145 return;
147 bool isfull = ((DWORD)CRegStdDWORD(_T("Software\\TortoiseGit\\CacheType"),
148 GetSystemMetrics(SM_REMOTESESSION) ? ShellCache::dll : ShellCache::exe) == ShellCache::dllFull);
150 int err = 0;
152 LPCTSTR lpszSubPath = nullptr;
153 CString sSubPath;
154 CString s = path.GetWinPathString();
155 if (s.GetLength() > sProjectRoot.GetLength())
157 sSubPath = s.Right(s.GetLength() - sProjectRoot.GetLength());
158 lpszSubPath = sSubPath;
159 // skip initial slash if necessary
160 if (*lpszSubPath == _T('\\'))
161 ++lpszSubPath;
164 m_status.prop_status = m_status.text_status = git_wc_status_none;
165 m_status.assumeValid = false;
166 m_status.skipWorktree = false;
168 if (path.IsDirectory())
170 err = GetDirStatus(sProjectRoot, lpszSubPath, &m_status.text_status, isfull, false, !noignore);
171 if (m_status.text_status == git_wc_status_added || m_status.text_status == git_wc_status_deleted) // fix for issue #1769; a folder is either modified, conflicted or normal
172 m_status.text_status = git_wc_status_modified;
174 else
175 err = GetFileStatus(sProjectRoot, lpszSubPath, &m_status.text_status, isfull, false, !noignore, nullptr, nullptr, &m_status.assumeValid, &m_status.skipWorktree);
177 // Error present if function is not under version control
178 if (err)
180 status = nullptr;
181 return;
184 status = &m_status;
186 #endif
188 typedef CComCritSecLock<CComCriticalSection> CAutoLocker;
190 int GitStatus::GetFileStatus(const CString& gitdir, CString path, git_wc_status_kind* status, BOOL IsFull, BOOL /*IsRecursive*/, BOOL IsIgnore, FILL_STATUS_CALLBACK callback, void* pData, bool* assumeValid, bool* skipWorktree)
192 if (!status)
193 return 0;
195 path.Replace(_T('\\'), _T('/'));
197 CString lowcasepath = path;
198 lowcasepath.MakeLower();
200 git_wc_status_kind st = git_wc_status_none;
201 CGitHash hash;
203 g_IndexFileMap.GetFileStatus(gitdir, path, &st, IsFull, false, callback, pData, &hash, true, assumeValid, skipWorktree);
205 if (st == git_wc_status_conflicted)
207 *status = st;
208 if (callback && assumeValid && skipWorktree)
209 callback(CombinePath(gitdir, path), st, false, pData, *assumeValid, *skipWorktree);
210 return 0;
213 if (st == git_wc_status_unversioned)
215 if (!IsIgnore)
217 *status = git_wc_status_unversioned;
218 if (callback && assumeValid && skipWorktree)
219 callback(CombinePath(gitdir, path), *status, false, pData, *assumeValid, *skipWorktree);
220 return 0;
223 if (g_IgnoreList.CheckIgnoreChanged(gitdir, path, false))
224 g_IgnoreList.LoadAllIgnoreFile(gitdir, path, false);
225 if (g_IgnoreList.IsIgnore(path, gitdir, false))
226 st = git_wc_status_ignored;
228 *status = st;
229 if (callback && assumeValid && skipWorktree)
230 callback(CombinePath(gitdir, path), st, false, pData, *assumeValid, *skipWorktree);
232 return 0;
235 if ((st == git_wc_status_normal || st == git_wc_status_modified) && IsFull)
237 g_HeadFileMap.CheckHeadAndUpdate(gitdir);
239 // Check Head Tree Hash
240 SHARED_TREE_PTR treeptr = g_HeadFileMap.SafeGet(gitdir);
242 //add item
243 int start = SearchInSortVector(*treeptr, lowcasepath, -1);
244 if (start < 0)
246 *status = st = git_wc_status_added;
247 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": File miss in head tree %s"), (LPCTSTR)path);
248 if (callback && assumeValid && skipWorktree)
249 callback(CombinePath(gitdir, path), st, false, pData, *assumeValid, *skipWorktree);
250 return 0;
253 // staged and not commit
254 if (treeptr->at(start).m_Hash != hash)
256 *status = st = git_wc_status_modified;
257 if (callback && assumeValid && skipWorktree)
258 callback(CombinePath(gitdir, path), st, false, pData, *assumeValid, *skipWorktree);
259 return 0;
262 *status = st;
263 if (callback && assumeValid && skipWorktree)
264 callback(CombinePath(gitdir, path), st, false, pData, *assumeValid, *skipWorktree);
265 return 0;
268 #ifdef TGITCACHE
269 bool GitStatus::HasIgnoreFilesChanged(const CString &gitdir, const CString &subpaths, bool isDir)
271 return g_IgnoreList.CheckIgnoreChanged(gitdir, subpaths, isDir);
274 int GitStatus::LoadIgnoreFile(const CString &gitdir, const CString &subpaths, bool isDir)
276 return g_IgnoreList.LoadAllIgnoreFile(gitdir, subpaths, isDir);
278 int GitStatus::IsUnderVersionControl(const CString &gitdir, const CString &path, bool isDir,bool *isVersion)
280 if (g_IndexFileMap.IsUnderVersionControl(gitdir, path, isDir, isVersion))
281 return 1;
282 if (!*isVersion)
283 return g_HeadFileMap.IsUnderVersionControl(gitdir, path, isDir, isVersion);
284 return 0;
287 int GitStatus::IsIgnore(const CString &gitdir, const CString &path, bool *isIgnore, bool isDir)
289 if (g_IgnoreList.CheckIgnoreChanged(gitdir, path, isDir))
290 g_IgnoreList.LoadAllIgnoreFile(gitdir, path, isDir);
292 *isIgnore = g_IgnoreList.IsIgnore(path, gitdir, isDir);
294 return 0;
297 int GitStatus::GetFileList(CString path, std::vector<CGitFileName> &list)
299 path += _T("\\*.*");
300 WIN32_FIND_DATA data;
301 HANDLE handle = ::FindFirstFileEx(path, SysInfo::Instance().IsWin7OrLater() ? FindExInfoBasic : FindExInfoStandard, &data, FindExSearchNameMatch, nullptr, SysInfo::Instance().IsWin7OrLater() ? FIND_FIRST_EX_LARGE_FETCH : 0);
304 if(_tcscmp(data.cFileName, _T(".git")) == 0)
305 continue;
307 if(_tcscmp(data.cFileName, _T(".")) == 0)
308 continue;
310 if(_tcscmp(data.cFileName, _T("..")) == 0)
311 continue;
313 CGitFileName filename;
315 filename.m_CaseFileName = filename.m_FileName = data.cFileName;
316 filename.m_FileName.MakeLower();
318 if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
319 filename.m_FileName += _T('/');
321 list.push_back(filename);
323 }while(::FindNextFile(handle, &data));
325 FindClose(handle);
327 std::sort(list.begin(), list.end(), SortCGitFileName);
328 return 0;
331 int GitStatus::EnumDirStatus(const CString &gitdir, const CString &subpath, git_wc_status_kind * status,BOOL IsFul, BOOL IsRecursive, BOOL IsIgnore, FILL_STATUS_CALLBACK callback, void *pData)
333 if (!status)
334 return 0;
336 CString path = subpath;
338 path.Replace(_T('\\'), _T('/'));
339 if (!path.IsEmpty() && path[path.GetLength() - 1] != _T('/'))
340 path += _T('/'); // Add trail / to show it is directory, not file name.
342 std::vector<CGitFileName> filelist;
343 GetFileList(CombinePath(gitdir, subpath), filelist);
345 g_IndexFileMap.CheckAndUpdate(gitdir,true);
347 g_HeadFileMap.CheckHeadAndUpdate(gitdir);
349 SHARED_INDEX_PTR indexptr = g_IndexFileMap.SafeGet(gitdir);
350 SHARED_TREE_PTR treeptr = g_HeadFileMap.SafeGet(gitdir);
352 // new git working tree has no index file
353 if (!indexptr.get())
355 for (auto it = filelist.cbegin(); it != filelist.cend(); ++it)
357 CString casepath = path;
358 casepath += it->m_CaseFileName;
360 bool bIsDir = false;
361 if (!it->m_FileName.IsEmpty() && it->m_FileName[it->m_FileName.GetLength() - 1] == _T('/'))
362 bIsDir = true;
364 if (IsIgnore)
366 if (g_IgnoreList.CheckIgnoreChanged(gitdir, casepath, bIsDir))
367 g_IgnoreList.LoadAllIgnoreFile(gitdir, casepath, bIsDir);
369 if (g_IgnoreList.IsIgnore(casepath, gitdir, bIsDir))
370 *status = git_wc_status_ignored;
371 else if (bIsDir)
372 continue;
373 else
374 *status = git_wc_status_unversioned;
376 else if (bIsDir)
377 continue;
378 else
379 *status = git_wc_status_unversioned;
381 if (callback)
382 callback(CombinePath(gitdir, casepath), *status, bIsDir, pData, false, false);
384 return 0;
387 CString lowcasepath = path;
388 lowcasepath.MakeLower();
390 for (auto it = filelist.cbegin(), itend = filelist.cend(); it != itend; ++it)
392 CString onepath(lowcasepath);
393 onepath += it->m_FileName;
394 CString casepath(path);
395 casepath += it->m_CaseFileName;
397 bool bIsDir = false;
398 if (!onepath.IsEmpty() && onepath[onepath.GetLength() - 1] == _T('/'))
399 bIsDir = true;
401 int matchLength = -1;
402 if (bIsDir)
403 matchLength = onepath.GetLength();
404 int pos = SearchInSortVector(*indexptr, onepath, matchLength);
405 int posintree = SearchInSortVector(*treeptr, onepath, matchLength);
407 if (pos < 0 && posintree < 0)
409 if (onepath.IsEmpty())
410 continue;
412 if (!IsIgnore)
414 *status = git_wc_status_unversioned;
415 if (callback)
416 callback(CombinePath(gitdir, casepath), *status, bIsDir, pData, false, false);
417 continue;
420 if (g_IgnoreList.CheckIgnoreChanged(gitdir, casepath, bIsDir))
421 g_IgnoreList.LoadAllIgnoreFile(gitdir, casepath, bIsDir);
423 if (g_IgnoreList.IsIgnore(casepath, gitdir, bIsDir))
424 *status = git_wc_status_ignored;
425 else
426 *status = git_wc_status_unversioned;
428 if (callback)
429 callback(CombinePath(gitdir, casepath), *status, bIsDir, pData, false, false);
431 else if (pos < 0 && posintree >= 0) /* check if file delete in index */
433 *status = git_wc_status_deleted;
434 if (callback)
435 callback(CombinePath(gitdir, casepath), *status, bIsDir, pData, false, false);
437 else if (pos >= 0 && posintree < 0) /* Check if file added */
439 *status = git_wc_status_added;
440 if (indexptr->at(pos).m_Flags & GIT_IDXENTRY_STAGEMASK)
441 *status = git_wc_status_conflicted;
442 if (callback)
443 callback(CombinePath(gitdir, casepath), *status, bIsDir, pData, false, false);
445 else
447 if (onepath.IsEmpty())
448 continue;
450 if (bIsDir)
452 *status = git_wc_status_normal;
453 if (callback)
454 callback(CombinePath(gitdir, casepath), *status, bIsDir, pData, false, false);
456 else
458 bool assumeValid = false;
459 bool skipWorktree = false;
460 git_wc_status_kind filestatus;
461 GetFileStatus(gitdir, casepath, &filestatus, IsFul, IsRecursive, IsIgnore, callback, pData, &assumeValid, &skipWorktree);
464 }/*End of For*/
466 /* Check deleted file in system */
467 int start = 0, end = 0;
468 int pos = SearchInSortVector(*indexptr, lowcasepath, lowcasepath.GetLength()); // match path prefix, (sub)folders end with slash
469 std::map<CString, bool> skipWorktreeMap;
471 if (GetRangeInSortVector(*indexptr, lowcasepath, lowcasepath.GetLength(), &start, &end, pos) == 0)
473 CString oldstring;
474 for (auto it = indexptr->cbegin() + start, itlast = indexptr->cbegin() + end; it <= itlast; ++it)
476 int commonPrefixLength = lowcasepath.GetLength();
477 int index = (*it).m_FileName.Find(_T('/'), commonPrefixLength);
478 if (index < 0)
479 index = (*it).m_FileName.GetLength();
480 else
481 ++index; // include slash at the end for subfolders, so that we do not match files by mistake
483 CString filename = (*it).m_FileName.Mid(commonPrefixLength, index - commonPrefixLength);
484 if (oldstring != filename)
486 oldstring = filename;
487 if (SearchInSortVector(filelist, filename, filename.GetLength()) < 0)
489 bool skipWorktree = false;
490 *status = git_wc_status_deleted;
491 if (((*it).m_FlagsExtended & GIT_IDXENTRY_SKIP_WORKTREE) != 0)
493 skipWorktreeMap[filename] = true;
494 skipWorktree = true;
495 *status = git_wc_status_normal;
497 if (callback)
498 callback(CombinePath(gitdir, (*it).m_FileName), *status, false, pData, false, skipWorktree);
504 start = end = 0;
505 pos = SearchInSortVector(*treeptr, lowcasepath, lowcasepath.GetLength()); // match path prefix, (sub)folders end with slash
506 if (GetRangeInSortVector(*treeptr, lowcasepath, lowcasepath.GetLength(), &start, &end, pos) == 0)
508 CString oldstring;
509 for (auto it = treeptr->cbegin() + start, itlast = treeptr->cbegin() + end; it <= itlast; ++it)
511 int commonPrefixLength = lowcasepath.GetLength();
512 int index = (*it).m_FileName.Find(_T('/'), commonPrefixLength);
513 if (index < 0)
514 index = (*it).m_FileName.GetLength();
515 else
516 ++index; // include slash at the end for subfolders, so that we do not match files by mistake
518 CString filename = (*it).m_FileName.Mid(commonPrefixLength, index - commonPrefixLength);
519 if (oldstring != filename && skipWorktreeMap[filename] != true)
521 oldstring = filename;
522 if (SearchInSortVector(filelist, filename, filename.GetLength()) < 0)
524 *status = git_wc_status_deleted;
525 if (callback)
526 callback(CombinePath(gitdir, (*it).m_FileName), *status, false, pData, false, false);
531 return 0;
533 #endif
535 #ifndef TGITCACHE
536 int GitStatus::GetDirStatus(const CString& gitdir, const CString& subpath, git_wc_status_kind* status, BOOL IsFul, BOOL IsRecursive, BOOL IsIgnore)
538 if (!status)
539 return 0;
541 CString path = subpath;
543 path.Replace(_T('\\'), _T('/'));
544 if (!path.IsEmpty() && path[path.GetLength() - 1] != _T('/'))
545 path += _T('/'); //Add trail / to show it is directory, not file name.
547 g_IndexFileMap.CheckAndUpdate(gitdir, true);
549 SHARED_INDEX_PTR indexptr = g_IndexFileMap.SafeGet(gitdir);
551 if (!indexptr)
553 *status = git_wc_status_unversioned;
554 return 0;
557 CString lowcasepath = path;
558 lowcasepath.MakeLower();
560 int pos = SearchInSortVector(*indexptr, lowcasepath, lowcasepath.GetLength());
562 // Not In Version Contorl
563 if (pos < 0)
565 if (!IsIgnore)
567 *status = git_wc_status_unversioned;
568 return 0;
571 // Check ignore always.
572 if (g_IgnoreList.CheckIgnoreChanged(gitdir, path, true))
573 g_IgnoreList.LoadAllIgnoreFile(gitdir, path, true);
575 if (g_IgnoreList.IsIgnore(path, gitdir, true))
576 *status = git_wc_status_ignored;
577 else
578 *status = git_wc_status_unversioned;
580 g_HeadFileMap.CheckHeadAndUpdate(gitdir);
582 SHARED_TREE_PTR treeptr = g_HeadFileMap.SafeGet(gitdir);
583 // Check init repository
584 if (treeptr->HeadIsEmpty() && path.IsEmpty())
585 *status = git_wc_status_normal;
586 // check if only one file in repository is deleted in index
587 else if (path.IsEmpty() && !treeptr->empty())
588 *status = git_wc_status_deleted;
590 return 0;
593 // In version control
594 *status = git_wc_status_normal;
596 int start = 0;
597 int end = 0;
599 GetRangeInSortVector(*indexptr, lowcasepath, lowcasepath.GetLength(), &start, &end, pos);
601 // Check Conflict;
602 for (auto it = indexptr->cbegin() + start, itlast = indexptr->cbegin() + end; indexptr->m_bHasConflicts && it <= itlast; ++it)
604 if (((*it).m_Flags & GIT_IDXENTRY_STAGEMASK) != 0)
606 *status = git_wc_status_conflicted;
607 break;
611 if (IsFul && (*status != git_wc_status_conflicted))
613 *status = git_wc_status_normal;
615 g_HeadFileMap.CheckHeadAndUpdate(gitdir);
617 // Check Add
619 // Check if new init repository
620 SHARED_TREE_PTR treeptr = g_HeadFileMap.SafeGet(gitdir);
622 if (!treeptr->empty() || treeptr->HeadIsEmpty())
624 for (auto it = indexptr->cbegin() + start, itlast = indexptr->cbegin() + end; it <= itlast; ++it)
626 pos = SearchInSortVector(*treeptr, (*it).m_FileName, -1);
628 if (pos < 0)
630 *status = max(git_wc_status_added, *status); // added file found
631 break;
634 if (pos >= 0 && treeptr->at(pos).m_Hash != (*it).m_IndexHash)
636 *status = max(git_wc_status_modified, *status); // modified file found
637 break;
641 // Check Delete
642 if (*status == git_wc_status_normal)
644 pos = SearchInSortVector(*treeptr, lowcasepath, lowcasepath.GetLength());
645 if (pos < 0)
646 *status = max(git_wc_status_added, *status); // added file found
647 else
649 int hstart, hend;
650 GetRangeInSortVector(*treeptr, lowcasepath, lowcasepath.GetLength(), &hstart, &hend, pos);
651 for (auto hit = treeptr->cbegin() + hstart, lastElement = treeptr->cbegin() + hend; hit <= lastElement; ++hit)
653 if (SearchInSortVector(*indexptr, (*hit).m_FileName, -1) < 0)
655 *status = max(git_wc_status_deleted, *status); // deleted file found
656 break;
662 } /* End lock*/
665 // When status == git_wc_status_conflicted, needn't check each file status
666 // because git_wc_status_conflicted is highest.s
667 if (*status == git_wc_status_conflicted)
668 return 0;
670 for (auto it = indexptr->cbegin() + start, itlast = indexptr->cbegin() + end; it <= itlast; ++it)
672 //skip child directory
673 if (!IsRecursive && (*it).m_FileName.Find(_T('/'), path.GetLength()) > 0)
674 continue;
676 git_wc_status_kind filestatus = git_wc_status_none;
677 bool assumeValid = false;
678 bool skipWorktree = false;
679 GetFileStatus(gitdir, (*it).m_FileName, &filestatus, IsFul, IsRecursive, IsIgnore, nullptr, nullptr, &assumeValid, &skipWorktree);
680 switch (filestatus)
682 case git_wc_status_added:
683 case git_wc_status_modified:
684 case git_wc_status_deleted:
685 case git_wc_status_conflicted:
686 *status = GetMoreImportant(filestatus, *status);
690 return 0;
692 #endif
694 #ifdef TGITCACHE
695 bool GitStatus::IsExistIndexLockFile(CString sDirName)
697 if (!PathIsDirectory(sDirName))
699 int x = sDirName.ReverseFind(_T('\\'));
700 if (x < 2)
701 return false;
703 sDirName.Truncate(x);
706 for (;;)
708 if (PathFileExists(CombinePath(sDirName, _T(".git"))))
710 if (PathFileExists(g_AdminDirMap.GetAdminDirConcat(sDirName, _T("index.lock"))))
711 return true;
713 return false;
716 int x = sDirName.ReverseFind(_T('\\'));
717 if (x < 2)
718 return false;
720 sDirName.Truncate(x);
723 #endif
725 bool GitStatus::ReleasePath(const CString &gitdir)
727 g_IndexFileMap.SafeClear(gitdir);
728 g_HeadFileMap.SafeClear(gitdir);
729 return true;
732 bool GitStatus::ReleasePathsRecursively(const CString &rootpath)
734 g_IndexFileMap.SafeClearRecursively(rootpath);
735 g_HeadFileMap.SafeClearRecursively(rootpath);
736 return true;