drop unused code for editing properties
[TortoiseGit.git] / src / Git / GitStatus.cpp
blob1502273a88987107ef1051d574d1da1d16ba18ae
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2011 - 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 "resource.h"
23 #include "..\TortoiseShell\resource.h"
24 //#include "git_config.h"
25 #include "GitStatus.h"
26 #include "UnicodeUtils.h"
27 //#include "GitGlobal.h"
28 //#include "GitHelpers.h"
29 #ifdef _MFC_VER
30 //# include "Git.h"
31 //# include "MessageBox.h"
32 //# include "registry.h"
33 //# include "TGitPath.h"
34 //# include "PathUtils.h"
35 #endif
36 #include "git.h"
37 #include "gitindex.h"
38 #include "shellcache.h"
40 CGitIndexFileMap g_IndexFileMap;
41 CGitHeadFileMap g_HeadFileMap;
42 CGitIgnoreList g_IgnoreList;
44 GitStatus::GitStatus(bool * /*pbCanceled*/)
45 : status(NULL)
47 #if 0
48 m_pool = git_pool_create (NULL);
50 git_error_clear(git_client_create_context(&ctx, m_pool));
52 if (pbCanceled)
54 ctx->cancel_func = cancel;
55 ctx->cancel_baton = pbCanceled;
58 #ifdef _MFC_VER
59 git_error_clear(git_config_ensure(NULL, m_pool));
61 // set up authentication
62 m_prompt.Init(m_pool, ctx);
64 // set up the configuration
65 m_err = git_config_get_config (&(ctx->config), g_pConfigDir, m_pool);
67 if (m_err)
69 ::MessageBox(NULL, this->GetLastErrorMsg(), _T("TortoiseGit"), MB_ICONERROR);
70 git_error_clear(m_err);
71 git_pool_destroy (m_pool); // free the allocated memory
72 exit(-1);
75 // set up the Git_SSH param
76 CString tgit_ssh = CRegString(_T("Software\\TortoiseGit\\SSH"));
77 if (tgit_ssh.IsEmpty())
78 tgit_ssh = CPathUtils::GetAppDirectory() + _T("TortoisePlink.exe");
79 tgit_ssh.Replace('\\', '/');
80 if (!tgit_ssh.IsEmpty())
82 git_config_t * cfg = (git_config_t *)apr_hash_get ((apr_hash_t *)ctx->config, Git_CONFIG_CATEGORY_CONFIG,
83 APR_HASH_KEY_STRING);
84 git_config_set(cfg, Git_CONFIG_SECTION_TUNNELS, "ssh", CUnicodeUtils::GetUTF8(tgit_ssh));
86 #else
87 git_error_clear(git_config_ensure(NULL, m_pool));
89 // set up the configuration
90 m_err = git_config_get_config (&(ctx->config), g_pConfigDir, m_pool);
92 #endif
93 #endif
96 GitStatus::~GitStatus(void)
98 #if 0
99 git_error_clear(m_err);
100 git_pool_destroy (m_pool); // free the allocated memory
101 #endif
104 void GitStatus::ClearPool()
106 #if 0
107 git_pool_clear(m_pool);
108 #endif
111 #ifdef _MFC_VER
112 CString GitStatus::GetLastErrorMsg() const
114 // return Git::GetErrorString(m_err);
115 return CString("");
117 #else
118 stdstring GitStatus::GetLastErrorMsg() const
121 stdstring msg;
122 #if 0
123 char errbuf[256];
125 if (m_err != NULL)
127 git_error_t * ErrPtr = m_err;
128 if (ErrPtr->message)
130 msg = CUnicodeUtils::StdGetUnicode(ErrPtr->message);
132 else
134 /* Is this a Subversion-specific error code? */
135 if ((ErrPtr->apr_err > APR_OS_START_USEERR)
136 && (ErrPtr->apr_err <= APR_OS_START_CANONERR))
137 msg = CUnicodeUtils::StdGetUnicode(git_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)));
138 /* Otherwise, this must be an APR error code. */
139 else
141 git_error_t *temp_err = NULL;
142 const char * err_string = NULL;
143 temp_err = git_utf_cstring_to_utf8(&err_string, apr_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)-1), ErrPtr->pool);
144 if (temp_err)
146 git_error_clear (temp_err);
147 msg = _T("Can't recode error string from APR");
149 else
151 msg = CUnicodeUtils::StdGetUnicode(err_string);
157 while (ErrPtr->child)
159 ErrPtr = ErrPtr->child;
160 msg += _T("\n");
161 if (ErrPtr->message)
163 msg += CUnicodeUtils::StdGetUnicode(ErrPtr->message);
165 else
167 /* Is this a Subversion-specific error code? */
168 if ((ErrPtr->apr_err > APR_OS_START_USEERR)
169 && (ErrPtr->apr_err <= APR_OS_START_CANONERR))
170 msg += CUnicodeUtils::StdGetUnicode(git_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)));
171 /* Otherwise, this must be an APR error code. */
172 else
174 git_error_t *temp_err = NULL;
175 const char * err_string = NULL;
176 temp_err = git_utf_cstring_to_utf8(&err_string, apr_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)-1), ErrPtr->pool);
177 if (temp_err)
179 git_error_clear (temp_err);
180 msg += _T("Can't recode error string from APR");
182 else
184 msg += CUnicodeUtils::StdGetUnicode(err_string);
190 return msg;
191 } // if (m_err != NULL)
192 #endif
193 return msg;
195 #endif
197 // static method
198 git_wc_status_kind GitStatus::GetAllStatus(const CTGitPath& path, git_depth_t depth)
200 git_wc_status_kind statuskind;
201 // git_client_ctx_t * ctx;
203 // apr_pool_t * pool;
204 // git_error_t * err;
205 BOOL err;
206 BOOL isDir;
207 CString sProjectRoot;
209 isDir = path.IsDirectory();
210 if (!path.HasAdminDir(&sProjectRoot))
211 return git_wc_status_none;
213 // pool = git_pool_create (NULL); // create the memory pool
215 // git_error_clear(git_client_create_context(&ctx, pool));
217 // git_revnum_t youngest = Git_INVALID_REVNUM;
218 // git_opt_revision_t rev;
219 // rev.kind = git_opt_revision_unspecified;
220 statuskind = git_wc_status_none;
222 const BOOL bIsRecursive = (depth == git_depth_infinity || depth == git_depth_unknown); // taken from SVN source
224 CString sSubPath;
225 CString s = path.GetWinPathString();
226 if (s.GetLength() > sProjectRoot.GetLength())
228 if (sProjectRoot.GetLength() == 3 && sProjectRoot[1] == _T(':'))
229 sSubPath = s.Right(s.GetLength() - sProjectRoot.GetLength());
230 else
231 sSubPath = s.Right(s.GetLength() - sProjectRoot.GetLength() - 1/*otherwise it gets initial slash*/);
234 bool isfull = ((DWORD)CRegStdDWORD(_T("Software\\TortoiseGit\\CacheType"),
235 GetSystemMetrics(SM_REMOTESESSION) ? ShellCache::dll : ShellCache::exe) == ShellCache::dllFull);
237 if(isDir)
239 err = GetDirStatus(sProjectRoot,sSubPath,&statuskind, isfull,bIsRecursive,isfull,NULL, NULL);
242 else
244 err = GetFileStatus(sProjectRoot,sSubPath,&statuskind,isfull, false,isfull, NULL,NULL);
247 return statuskind;
250 // static method
251 git_wc_status_kind GitStatus::GetAllStatusRecursive(const CTGitPath& path)
253 return GetAllStatus(path, git_depth_infinity);
256 // static method
257 git_wc_status_kind GitStatus::GetMoreImportant(git_wc_status_kind status1, git_wc_status_kind status2)
259 if (GetStatusRanking(status1) >= GetStatusRanking(status2))
260 return status1;
261 return status2;
263 // static private method
264 int GitStatus::GetStatusRanking(git_wc_status_kind status)
266 switch (status)
268 case git_wc_status_none:
269 return 0;
270 case git_wc_status_unversioned:
271 return 1;
272 case git_wc_status_ignored:
273 return 2;
274 case git_wc_status_incomplete:
275 return 4;
276 case git_wc_status_normal:
277 case git_wc_status_external:
278 return 5;
279 case git_wc_status_added:
280 return 6;
281 case git_wc_status_missing:
282 return 7;
283 case git_wc_status_deleted:
284 return 8;
285 case git_wc_status_replaced:
286 return 9;
287 case git_wc_status_modified:
288 return 10;
289 case git_wc_status_merged:
290 return 11;
291 case git_wc_status_conflicted:
292 return 12;
293 case git_wc_status_obstructed:
294 return 13;
296 return 0;
299 git_revnum_t GitStatus::GetStatus(const CTGitPath& path, bool update /* = false */, bool noignore /* = false */, bool /*noexternals*/ /* = false */)
301 // NOTE: unlike the SVN version this one does not cache the enumerated files, because in practice no code in all of
302 // Tortoise uses this, all places that call GetStatus create a temp GitStatus object which gets destroyed right
303 // after the call again
305 // apr_hash_t * statushash;
306 // apr_hash_t * exthash;
307 // apr_array_header_t * statusarray;
308 // const sort_item* item;
310 // git_error_clear(m_err);
311 // statushash = apr_hash_make(m_pool);
312 // exthash = apr_hash_make(m_pool);
313 git_revnum_t youngest = GIT_INVALID_REVNUM;
314 // git_opt_revision_t rev;
315 // rev.kind = git_opt_revision_unspecified;
317 CString sProjectRoot;
318 if ( !path.HasAdminDir(&sProjectRoot) )
319 return youngest;
321 struct hashbaton_t hashbaton;
322 // hashbaton.hash = statushash;
323 // hashbaton.exthash = exthash;
324 hashbaton.pThis = this;
326 bool isfull = ((DWORD)CRegStdDWORD(_T("Software\\TortoiseGit\\CacheType"),
327 GetSystemMetrics(SM_REMOTESESSION) ? ShellCache::dll : ShellCache::exe) == ShellCache::dllFull);
330 LPCTSTR lpszSubPath = NULL;
331 CString sSubPath;
332 CString s = path.GetWinPathString();
333 if (s.GetLength() > sProjectRoot.GetLength())
335 sSubPath = s.Right(s.GetLength() - sProjectRoot.GetLength());
336 lpszSubPath = sSubPath;
337 // skip initial slash if necessary
338 if (*lpszSubPath == _T('\\'))
339 lpszSubPath++;
342 m_status.prop_status = m_status.text_status = git_wc_status_none;
344 if(path.IsDirectory())
346 m_err = GetDirStatus(sProjectRoot,CString(lpszSubPath),&m_status.text_status , isfull, false,!noignore, NULL, NULL);
349 else
351 m_err = GetFileStatus(sProjectRoot,CString(lpszSubPath),&m_status.text_status ,isfull, false,!noignore, NULL,NULL);
355 // Error present if function is not under version control
356 if (m_err) /*|| (apr_hash_count(statushash) == 0)*/
358 status = NULL;
359 return GIT_INVALID_REVNUM;
362 // Convert the unordered hash to an ordered, sorted array
363 /*statusarray = sort_hash (statushash,
364 sort_compare_items_as_paths,
365 m_pool);*/
367 // only the first entry is needed (no recurse)
368 // item = &APR_ARRAY_IDX (statusarray, 0, const sort_item);
370 // status = (git_wc_status2_t *) item->value;
371 status = &m_status;
373 if (update)
375 // done to match TSVN functionality of this function (not sure if any code uses the reutrn val)
376 // if TGit does not need this, then change the return type of function
377 youngest = g_Git.GetHash(_T("HEAD"));
380 return youngest;
383 git_wc_status2_t * GitStatus::GetFirstFileStatus(const CTGitPath& /*path*/, CTGitPath& /*retPath*/, bool /*update*/, git_depth_t /*depth*/, bool /*bNoIgnore*/ /* = true */, bool /*bNoExternals*/ /* = false */)
385 static git_wc_status2 st;
387 m_fileCache.Reset();
389 m_fileCache.Init( CStringA( path.GetWinPathString().GetString() ) );
390 MessageBox(NULL, path.GetWinPathString(), _T("GetFirstFile"), MB_OK);
391 m_fileCache.m_pFileIter = m_fileCache.m_pFiles;
392 st.text_status = git_wc_status_none;
394 if (m_fileCache.m_pFileIter)
396 switch(m_fileCache.m_pFileIter->nStatus)
398 case WGFS_Normal: st.text_status = git_wc_status_normal; break;
399 case WGFS_Modified: st.text_status = git_wc_status_modified; break;
400 case WGFS_Deleted: st.text_status = git_wc_status_deleted; break;
403 //retPath.SetFromGit((const char*)item->key);
405 m_fileCache.m_pFileIter = m_fileCache.m_pFileIter->pNext;
408 return &st;
410 #if 0
411 const sort_item* item;
413 git_error_clear(m_err);
414 m_statushash = apr_hash_make(m_pool);
415 m_externalhash = apr_hash_make(m_pool);
416 headrev = Git_INVALID_REVNUM;
417 git_opt_revision_t rev;
418 rev.kind = git_opt_revision_unspecified;
419 struct hashbaton_t hashbaton;
420 hashbaton.hash = m_statushash;
421 hashbaton.exthash = m_externalhash;
422 hashbaton.pThis = this;
423 m_statushashindex = 0;
424 m_err = git_client_status4 (&headrev,
425 path.GetGitApiPath(m_pool),
426 &rev,
427 getstatushash,
428 &hashbaton,
429 depth,
430 TRUE, //getall
431 update, //update
432 bNoIgnore, //noignore
433 bNoExternals, //noexternals
434 NULL,
435 ctx,
436 m_pool);
439 // Error present if function is not under version control
440 if ((m_err != NULL) || (apr_hash_count(m_statushash) == 0))
442 return NULL;
445 // Convert the unordered hash to an ordered, sorted array
446 m_statusarray = sort_hash (m_statushash,
447 sort_compare_items_as_paths,
448 m_pool);
450 // only the first entry is needed (no recurse)
451 m_statushashindex = 0;
452 item = &APR_ARRAY_IDX (m_statusarray, m_statushashindex, const sort_item);
453 retPath.SetFromGit((const char*)item->key);
454 return (git_wc_status2_t *) item->value;
455 #endif
457 return 0;
460 unsigned int GitStatus::GetVersionedCount() const
462 // return /**/m_fileCache.GetFileCount();
464 unsigned int count = 0;
465 #if 0
466 const sort_item* item;
467 for (unsigned int i=0; i<apr_hash_count(m_statushash); ++i)
469 item = &APR_ARRAY_IDX(m_statusarray, i, const sort_item);
470 if (item)
472 if (GitStatus::GetMoreImportant(((git_wc_status_t *)item->value)->text_status, git_wc_status_ignored)!=git_wc_status_ignored)
473 count++;
476 #endif
477 return count;
480 git_wc_status2_t * GitStatus::GetNextFileStatus(CTGitPath& /*retPath*/)
482 static git_wc_status2 st;
484 st.text_status = git_wc_status_none;
486 /*if (m_fileCache.m_pFileIter)
488 switch(m_fileCache.m_pFileIter->nStatus)
490 case WGFS_Normal: st.text_status = git_wc_status_normal; break;
491 case WGFS_Modified: st.text_status = git_wc_status_modified; break;
492 case WGFS_Deleted: st.text_status = git_wc_status_deleted; break;
495 m_fileCache.m_pFileIter = m_fileCache.m_pFileIter->pNext;
498 return &st;
500 #if 0
501 const sort_item* item;
503 if ((m_statushashindex+1) >= apr_hash_count(m_statushash))
504 return NULL;
505 m_statushashindex++;
507 item = &APR_ARRAY_IDX (m_statusarray, m_statushashindex, const sort_item);
508 retPath.SetFromGit((const char*)item->key);
509 return (git_wc_status2_t *) item->value;
510 #endif
511 return 0;
514 bool GitStatus::IsExternal(const CTGitPath& /*path*/) const
516 #if 0
517 if (apr_hash_get(m_externalhash, path.GetGitApiPath(m_pool), APR_HASH_KEY_STRING))
518 return true;
519 #endif
520 return false;
523 bool GitStatus::IsInExternal(const CTGitPath& /*path*/) const
525 #if 0
526 if (apr_hash_count(m_statushash) == 0)
527 return false;
529 GitPool localpool(m_pool);
530 apr_hash_index_t *hi;
531 const char* key;
532 for (hi = apr_hash_first(localpool, m_externalhash); hi; hi = apr_hash_next(hi))
534 apr_hash_this(hi, (const void**)&key, NULL, NULL);
535 if (key)
537 if (CTGitPath(CUnicodeUtils::GetUnicode(key)).IsAncestorOf(path))
538 return true;
541 #endif
542 return false;
546 void GitStatus::GetStatusString(git_wc_status_kind status, size_t buflen, TCHAR * string)
548 TCHAR * buf;
549 switch (status)
551 case git_wc_status_none:
552 buf = _T("none\0");
553 break;
554 case git_wc_status_unversioned:
555 buf = _T("unversioned\0");
556 break;
557 case git_wc_status_normal:
558 buf = _T("normal\0");
559 break;
560 case git_wc_status_added:
561 buf = _T("added\0");
562 break;
563 case git_wc_status_missing:
564 buf = _T("missing\0");
565 break;
566 case git_wc_status_deleted:
567 buf = _T("deleted\0");
568 break;
569 case git_wc_status_replaced:
570 buf = _T("replaced\0");
571 break;
572 case git_wc_status_modified:
573 buf = _T("modified\0");
574 break;
575 case git_wc_status_merged:
576 buf = _T("merged\0");
577 break;
578 case git_wc_status_conflicted:
579 buf = _T("conflicted\0");
580 break;
581 case git_wc_status_obstructed:
582 buf = _T("obstructed\0");
583 break;
584 case git_wc_status_ignored:
585 buf = _T("ignored");
586 break;
587 case git_wc_status_external:
588 buf = _T("external");
589 break;
590 case git_wc_status_incomplete:
591 buf = _T("incomplete\0");
592 break;
593 default:
594 buf = _T("\0");
595 break;
597 _stprintf_s(string, buflen, _T("%s"), buf);
600 void GitStatus::GetStatusString(HINSTANCE hInst, git_wc_status_kind status, TCHAR * string, int size, WORD lang)
602 switch (status)
604 case git_wc_status_none:
605 LoadStringEx(hInst, IDS_STATUSNONE, string, size, lang);
606 break;
607 case git_wc_status_unversioned:
608 LoadStringEx(hInst, IDS_STATUSUNVERSIONED, string, size, lang);
609 break;
610 case git_wc_status_normal:
611 LoadStringEx(hInst, IDS_STATUSNORMAL, string, size, lang);
612 break;
613 case git_wc_status_added:
614 LoadStringEx(hInst, IDS_STATUSADDED, string, size, lang);
615 break;
616 case git_wc_status_missing:
617 LoadStringEx(hInst, IDS_STATUSABSENT, string, size, lang);
618 break;
619 case git_wc_status_deleted:
620 LoadStringEx(hInst, IDS_STATUSDELETED, string, size, lang);
621 break;
622 case git_wc_status_replaced:
623 LoadStringEx(hInst, IDS_STATUSREPLACED, string, size, lang);
624 break;
625 case git_wc_status_modified:
626 LoadStringEx(hInst, IDS_STATUSMODIFIED, string, size, lang);
627 break;
628 case git_wc_status_merged:
629 LoadStringEx(hInst, IDS_STATUSMERGED, string, size, lang);
630 break;
631 case git_wc_status_conflicted:
632 LoadStringEx(hInst, IDS_STATUSCONFLICTED, string, size, lang);
633 break;
634 case git_wc_status_ignored:
635 LoadStringEx(hInst, IDS_STATUSIGNORED, string, size, lang);
636 break;
637 case git_wc_status_obstructed:
638 LoadStringEx(hInst, IDS_STATUSOBSTRUCTED, string, size, lang);
639 break;
640 case git_wc_status_external:
641 LoadStringEx(hInst, IDS_STATUSEXTERNAL, string, size, lang);
642 break;
643 case git_wc_status_incomplete:
644 LoadStringEx(hInst, IDS_STATUSINCOMPLETE, string, size, lang);
645 break;
646 default:
647 LoadStringEx(hInst, IDS_STATUSNONE, string, size, lang);
648 break;
652 #ifdef _MFC_VER
653 CString GitStatus::GetDepthString(git_depth_t depth)
655 #if 0
656 CString sDepth;
657 switch (depth)
659 case git_depth_unknown:
660 sDepth.LoadString(IDS_Git_DEPTH_UNKNOWN);
661 break;
662 case git_depth_empty:
663 sDepth.LoadString(IDS_Git_DEPTH_EMPTY);
664 break;
665 case git_depth_files:
666 sDepth.LoadString(IDS_Git_DEPTH_FILES);
667 break;
668 case git_depth_immediates:
669 sDepth.LoadString(IDS_Git_DEPTH_IMMEDIATE);
670 break;
671 case git_depth_infinity:
672 sDepth.LoadString(IDS_Git_DEPTH_INFINITE);
673 break;
675 return sDepth;
676 #endif
677 return CString("");
679 #endif
681 void GitStatus::GetDepthString(HINSTANCE /*hInst*/, git_depth_t /*depth*/, TCHAR * /*string*/, int /*size*/, WORD /*lang*/)
683 #if 0
684 switch (depth)
686 case git_depth_unknown:
687 LoadStringEx(hInst, IDS_SVN_DEPTH_UNKNOWN, string, size, lang);
688 break;
689 case git_depth_empty:
690 LoadStringEx(hInst, IDS_SVN_DEPTH_EMPTY, string, size, lang);
691 break;
692 case git_depth_files:
693 LoadStringEx(hInst, IDS_SVN_DEPTH_FILES, string, size, lang);
694 break;
695 case git_depth_immediates:
696 LoadStringEx(hInst, IDS_SVN_DEPTH_IMMEDIATE, string, size, lang);
697 break;
698 case git_depth_infinity:
699 LoadStringEx(hInst, IDS_SVN_DEPTH_INFINITE, string, size, lang);
700 break;
702 #endif
706 int GitStatus::LoadStringEx(HINSTANCE hInstance, UINT uID, LPTSTR lpBuffer, int nBufferMax, WORD wLanguage)
708 const STRINGRESOURCEIMAGE* pImage;
709 const STRINGRESOURCEIMAGE* pImageEnd;
710 ULONG nResourceSize;
711 HGLOBAL hGlobal;
712 UINT iIndex;
713 int ret;
715 HRSRC hResource = FindResourceEx(hInstance, RT_STRING, MAKEINTRESOURCE(((uID>>4)+1)), wLanguage);
716 if (!hResource)
718 // try the default language before giving up!
719 hResource = FindResource(hInstance, MAKEINTRESOURCE(((uID>>4)+1)), RT_STRING);
720 if (!hResource)
721 return 0;
723 hGlobal = LoadResource(hInstance, hResource);
724 if (!hGlobal)
725 return 0;
726 pImage = (const STRINGRESOURCEIMAGE*)::LockResource(hGlobal);
727 if(!pImage)
728 return 0;
730 nResourceSize = ::SizeofResource(hInstance, hResource);
731 pImageEnd = (const STRINGRESOURCEIMAGE*)(LPBYTE(pImage)+nResourceSize);
732 iIndex = uID&0x000f;
734 while ((iIndex > 0) && (pImage < pImageEnd))
736 pImage = (const STRINGRESOURCEIMAGE*)(LPBYTE(pImage)+(sizeof(STRINGRESOURCEIMAGE)+(pImage->nLength*sizeof(WCHAR))));
737 iIndex--;
739 if (pImage >= pImageEnd)
740 return 0;
741 if (pImage->nLength == 0)
742 return 0;
744 ret = pImage->nLength;
745 if (pImage->nLength > nBufferMax)
747 wcsncpy_s(lpBuffer, nBufferMax, pImage->achString, pImage->nLength-1);
748 lpBuffer[nBufferMax-1] = 0;
750 else
752 wcsncpy_s(lpBuffer, nBufferMax, pImage->achString, pImage->nLength);
753 lpBuffer[ret] = 0;
755 return ret;
758 BOOL GitStatus::getallstatus(const struct wgFile_s *pFile, void *pUserData)
760 git_wc_status_kind * s = (git_wc_status_kind *)pUserData;
761 *s = GitStatus::GetMoreImportant(*s, GitStatusFromWingit(pFile->nStatus));
762 return FALSE;
765 BOOL GitStatus::getstatus(const struct wgFile_s *pFile, void *pUserData)
767 git_wc_status2_t * s = (git_wc_status2_t*)pUserData;
768 s->prop_status = s->text_status = GitStatus::GetMoreImportant(s->prop_status, GitStatusFromWingit(pFile->nStatus));
769 return FALSE;
772 #if 0
773 git_error_t * GitStatus::getallstatus(void * baton, const char * /*path*/, git_wc_status2_t * status, apr_pool_t * /*pool*/)
775 git_wc_status_kind * s = (git_wc_status_kind *)baton;
776 *s = GitStatus::GetMoreImportant(*s, status->text_status);
777 *s = GitStatus::GetMoreImportant(*s, status->prop_status);
778 return Git_NO_ERROR;
780 #endif
782 #if 0
783 git_error_t * GitStatus::getstatushash(void * baton, const char * path, git_wc_status2_t * status, apr_pool_t * /*pool*/)
785 hashbaton_t * hash = (hashbaton_t *)baton;
786 const StdStrAVector& filterList = hash->pThis->m_filterFileList;
787 if (status->text_status == git_wc_status_external)
789 apr_hash_set (hash->exthash, apr_pstrdup(hash->pThis->m_pool, path), APR_HASH_KEY_STRING, (const void*)1);
790 return Git_NO_ERROR;
792 if(filterList.size() > 0)
794 // We have a filter active - we're only interested in files which are in
795 // the filter
796 if(!binary_search(filterList.begin(), filterList.end(), path))
798 // This item is not in the filter - don't store it
799 return Git_NO_ERROR;
802 git_wc_status2_t * statuscopy = git_wc_dup_status2 (status, hash->pThis->m_pool);
803 apr_hash_set (hash->hash, apr_pstrdup(hash->pThis->m_pool, path), APR_HASH_KEY_STRING, statuscopy);
804 return Git_NO_ERROR;
807 apr_array_header_t * GitStatus::sort_hash (apr_hash_t *ht,
808 int (*comparison_func) (const GitStatus::sort_item *, const GitStatus::sort_item *),
809 apr_pool_t *pool)
811 apr_hash_index_t *hi;
812 apr_array_header_t *ary;
814 /* allocate an array with only one element to begin with. */
815 ary = apr_array_make (pool, 1, sizeof(sort_item));
817 /* loop over hash table and push all keys into the array */
818 for (hi = apr_hash_first (pool, ht); hi; hi = apr_hash_next (hi))
820 sort_item *item = (sort_item*)apr_array_push (ary);
822 apr_hash_this (hi, &item->key, &item->klen, &item->value);
825 /* now quick sort the array. */
826 qsort (ary->elts, ary->nelts, ary->elt_size,
827 (int (*)(const void *, const void *))comparison_func);
829 return ary;
832 int GitStatus::sort_compare_items_as_paths (const sort_item *a, const sort_item *b)
834 const char *astr, *bstr;
836 astr = (const char*)a->key;
837 bstr = (const char*)b->key;
838 return git_path_compare_paths (astr, bstr);
840 #endif
842 git_error_t* GitStatus::cancel(void * /*baton*/)
844 #if 0
845 volatile bool * canceled = (bool *)baton;
846 if (*canceled)
848 CString temp;
849 temp.LoadString(IDS_Git_USERCANCELLED);
850 return git_error_create(Git_ERR_CANCELLED, NULL, CUnicodeUtils::GetUTF8(temp));
852 return Git_NO_ERROR;
853 #endif
854 return 0;
857 #ifdef _MFC_VER
859 // Set-up a filter to restrict the files which will have their status stored by a get-status
860 void GitStatus::SetFilter(const CTGitPathList& fileList)
862 m_filterFileList.clear();
863 for(int fileIndex = 0; fileIndex < fileList.GetCount(); fileIndex++)
865 // m_filterFileList.push_back(fileList[fileIndex].GetGitApiPath(m_pool));
867 // Sort the list so that we can do binary searches
868 std::sort(m_filterFileList.begin(), m_filterFileList.end());
871 void GitStatus::ClearFilter()
873 m_filterFileList.clear();
876 #endif // _MFC_VER
878 typedef CComCritSecLock<CComCriticalSection> CAutoLocker;
880 int GitStatus::GetFileStatus(const CString &gitdir,const CString &pathParam,git_wc_status_kind * status,BOOL IsFull, BOOL /*IsRecursive*/,BOOL IsIgnore, FIll_STATUS_CALLBACK callback,void *pData)
884 CString path = pathParam;
886 TCHAR oldpath[MAX_PATH+1];
887 memset(oldpath,0,MAX_PATH+1);
889 path.Replace(_T('\\'),_T('/'));
891 CString lowcasepath =path;
892 lowcasepath.MakeLower();
894 if(status)
896 git_wc_status_kind st = git_wc_status_none;
897 CGitHash hash;
899 g_IndexFileMap.GetFileStatus(gitdir,path,&st,IsFull,false,callback,pData,&hash);
901 if( st == git_wc_status_conflicted )
903 *status =st;
904 if(callback)
905 callback(gitdir+_T("/")+path,st,false,pData);
906 return 0;
909 if( st == git_wc_status_unversioned )
911 if(!IsIgnore)
913 *status = git_wc_status_unversioned;
914 if(callback)
915 callback(gitdir+_T("/")+path, *status, false,pData);
916 return 0;
919 if( g_IgnoreList.CheckIgnoreChanged(gitdir,path))
921 g_IgnoreList.LoadAllIgnoreFile(gitdir,path);
923 if( g_IgnoreList.IsIgnore(path, gitdir) )
925 st = git_wc_status_ignored;
927 *status = st;
928 if(callback)
929 callback(gitdir+_T("/")+path,st, false, pData);
931 return 0;
934 if( st == git_wc_status_normal && IsFull)
937 g_HeadFileMap.CheckHeadUpdate(gitdir);
938 bool b=false;
940 SHARED_TREE_PTR treeptr;
942 treeptr=g_HeadFileMap.SafeGet(gitdir);
944 b = treeptr->m_Head != treeptr->m_TreeHash;
946 if(b)
948 treeptr->ReadHeadHash(gitdir);
950 // Init Repository
951 if( treeptr->m_HeadFile.IsEmpty() )
953 *status =st=git_wc_status_added;
954 if(callback)
955 callback(gitdir+_T("/")+path,st,false,pData);
956 return 0;
958 if(treeptr->ReadTree())
960 treeptr->m_LastModifyTimeHead = 0;
961 //Check if init repository
962 *status = treeptr->m_Head.IsEmpty()? git_wc_status_added: st;
963 if(callback)
964 callback(gitdir+_T("/")+path,*status,false,pData);
965 return 0;
967 g_HeadFileMap.SafeSet(gitdir, treeptr);
970 // Check Head Tree Hash;
972 //add item
974 int start =SearchInSortVector(*treeptr,lowcasepath.GetBuffer(),-1);
976 if(start<0)
978 *status =st=git_wc_status_added;
979 ATLTRACE(_T("File miss in head tree %s"), path);
980 if(callback)
981 callback(gitdir+_T("/")+path,st,false, pData);
982 return 0;
985 //staged and not commit
986 if( treeptr->at(start).m_Hash != hash )
988 *status =st=git_wc_status_modified;
989 if(callback)
990 callback(gitdir+_T("/")+path,st, false, pData);
991 return 0;
996 *status =st;
997 if(callback)
998 callback(gitdir+_T("/")+path,st,false, pData);
999 return 0;
1002 catch(...)
1004 if(status)
1005 *status = git_wc_status_none;
1006 return -1;
1009 return 0;
1013 int GitStatus::GetHeadHash(const CString &gitdir, CGitHash &hash)
1015 return g_HeadFileMap.GetHeadHash(gitdir, hash);
1018 bool GitStatus::IsGitReposChanged(const CString &gitdir,const CString &subpaths, int mode)
1020 if( mode & GIT_MODE_INDEX)
1022 return g_IndexFileMap.CheckAndUpdate(gitdir, true);
1025 if( mode & GIT_MODE_HEAD)
1027 if(g_HeadFileMap.CheckHeadUpdate(gitdir))
1028 return true;
1031 if( mode & GIT_MODE_IGNORE)
1033 if(g_IgnoreList.CheckIgnoreChanged(gitdir,subpaths))
1034 return true;
1036 return false;
1039 int GitStatus::LoadIgnoreFile(const CString &gitdir,const CString &subpaths)
1041 return g_IgnoreList.LoadAllIgnoreFile(gitdir,subpaths);
1043 int GitStatus::IsUnderVersionControl(const CString &gitdir, const CString &path, bool isDir,bool *isVersion)
1045 return g_IndexFileMap.IsUnderVersionControl(gitdir, path, isDir, isVersion);
1048 __int64 GitStatus::GetIndexFileTime(const CString &gitdir)
1050 SHARED_INDEX_PTR ptr=g_IndexFileMap.SafeGet(gitdir);
1051 if(ptr.get() == NULL)
1052 return 0;
1054 return ptr->m_LastModifyTime;
1057 int GitStatus::GetIgnoreFileChangeTimeList(const CString &dir, std::vector<__int64> &timelist)
1059 return g_IgnoreList.GetIgnoreFileChangeTimeList(dir,timelist);
1061 int GitStatus::IsIgnore(const CString &gitdir, const CString &path, bool *isIgnore)
1063 if(::g_IgnoreList.CheckIgnoreChanged(gitdir,path))
1064 g_IgnoreList.LoadAllIgnoreFile(gitdir,path);
1066 *isIgnore = g_IgnoreList.IsIgnore(path,gitdir);
1068 return 0;
1071 static bool SortFileName(CGitFileName &Item1, CGitFileName &Item2)
1073 return Item1.m_FileName.Compare(Item2.m_FileName)<0;
1076 int GitStatus::GetFileList(const CString &gitdir, const CString &subpath, std::vector<CGitFileName> &list)
1078 WIN32_FIND_DATA data;
1079 HANDLE handle=::FindFirstFile(gitdir+_T("\\")+subpath+_T("\\*.*"), &data);
1082 if(_tcscmp(data.cFileName, _T(".git")) == 0)
1083 continue;
1085 if(_tcscmp(data.cFileName, _T(".")) == 0)
1086 continue;
1088 if(_tcscmp(data.cFileName, _T("..")) == 0)
1089 continue;
1091 CGitFileName filename;
1093 filename.m_CaseFileName = filename.m_FileName = data.cFileName;
1094 filename.m_FileName.MakeLower();
1096 if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1098 filename.m_FileName += _T('/');
1101 list.push_back(filename);
1103 }while(::FindNextFile(handle, &data));
1105 FindClose(handle);
1107 std::sort(list.begin(), list.end(), SortFileName);
1108 return 0;
1111 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)
1115 TCHAR oldpath[MAX_PATH+1];
1116 memset(oldpath,0,MAX_PATH+1);
1118 CString path =subpath;
1120 path.Replace(_T('\\'),_T('/'));
1121 if(!path.IsEmpty())
1122 if(path[path.GetLength()-1] != _T('/'))
1123 path += _T('/'); //Add trail / to show it is directory, not file name.
1125 CString lowcasepath = path;
1126 lowcasepath.MakeLower();
1128 std::vector<CGitFileName> filelist;
1129 GetFileList(gitdir, subpath, filelist);
1131 if(status)
1133 g_IndexFileMap.CheckAndUpdate(gitdir,true);
1135 if(g_HeadFileMap.CheckHeadUpdate(gitdir) || g_HeadFileMap.IsHashChanged(gitdir))
1137 SHARED_TREE_PTR treeptr = g_HeadFileMap.SafeGet(gitdir);
1138 treeptr->ReadHeadHash(gitdir);
1139 if(!treeptr->ReadTree())
1141 g_HeadFileMap.SafeSet(gitdir, treeptr);
1145 SHARED_INDEX_PTR indexptr = g_IndexFileMap.SafeGet(gitdir);
1146 SHARED_TREE_PTR treeptr = g_HeadFileMap.SafeGet(gitdir);
1148 if( indexptr.get() == NULL)
1149 return -1;
1151 std::vector<CGitFileName>::iterator it;
1152 CString onepath;
1153 CString casepath;
1154 for(it = filelist.begin(); it<filelist.end();it++)
1156 casepath=onepath = path;
1157 onepath.MakeLower();
1158 onepath += it->m_FileName;
1159 casepath += it->m_CaseFileName;
1161 int pos = SearchInSortVector(*indexptr, onepath.GetBuffer(), onepath.GetLength());
1162 int posintree = SearchInSortVector(*treeptr, onepath.GetBuffer(), onepath.GetLength());
1164 bool bIsDir =false;
1165 if(onepath.GetLength()>0 && onepath[onepath.GetLength()-1] == _T('/'))
1166 bIsDir =true;
1168 if(pos <0 && posintree<0)
1170 if(onepath.GetLength() ==0)
1171 continue;
1173 if(bIsDir) /*check if it is directory*/
1175 if(::PathFileExists(gitdir+onepath+_T("/.git")))
1176 { /* That is git submodule */
1177 *status = git_wc_status_unknown;
1178 if(callback)
1179 callback(gitdir+_T("/")+casepath, *status, bIsDir, pData);
1180 continue;
1184 if(!IsIgnore)
1186 *status = git_wc_status_unversioned;
1187 if(callback)
1188 callback(gitdir+_T("/")+casepath, *status, bIsDir,pData);
1189 continue;
1192 if(::g_IgnoreList.CheckIgnoreChanged(gitdir,casepath))
1193 g_IgnoreList.LoadAllIgnoreFile(gitdir,casepath);
1195 if(g_IgnoreList.IsIgnore(casepath,gitdir))
1196 *status = git_wc_status_ignored;
1197 else
1198 *status = git_wc_status_unversioned;
1200 if(callback)
1201 callback(gitdir+_T("/")+casepath, *status, bIsDir,pData);
1204 else if(pos <0 && posintree>=0) /* check if file delete in index */
1206 *status = git_wc_status_deleted;
1207 if(callback)
1208 callback(gitdir+_T("/")+casepath, *status, bIsDir,pData);
1211 else if(pos >=0 && posintree <0) /* Check if file added */
1213 *status = git_wc_status_added;
1214 if(callback)
1215 callback(gitdir+_T("/")+casepath, *status, bIsDir,pData);
1217 else
1219 if(onepath.GetLength() ==0)
1220 continue;
1222 if(onepath[onepath.GetLength()-1] == _T('/'))
1224 *status = git_wc_status_normal;
1225 if(callback)
1226 callback(gitdir+_T("/")+casepath, *status, bIsDir,pData);
1228 else
1230 git_wc_status_kind filestatus;
1231 GetFileStatus(gitdir,casepath, &filestatus,IsFul, IsRecursive,IsIgnore, callback,pData);
1235 }/*End of For*/
1237 /* Check deleted file in system */
1238 int start=0, end=0;
1239 int pos=SearchInSortVector(*indexptr, lowcasepath.GetBuffer(), lowcasepath.GetLength());
1241 if(pos>=0 && GetRangeInSortVector(*indexptr,lowcasepath.GetBuffer(),lowcasepath.GetLength(),&start,&end,pos))
1243 CGitIndexList::iterator it;
1244 CString oldstring;
1246 for(it = indexptr->begin()+start; it <= indexptr->begin()+end; it++)
1248 int start = lowcasepath.GetLength();
1249 int index = (*it).m_FileName.Find(_T('/'), start);
1250 if(index<0)
1251 index = (*it).m_FileName.GetLength();
1253 CString filename = (*it).m_FileName.Mid(start, index-start);
1254 if(oldstring != filename)
1256 oldstring = filename;
1257 if(SearchInSortVector(filelist, filename.GetBuffer(), filename.GetLength())<0)
1259 *status = git_wc_status_deleted;
1260 if(callback)
1261 callback(gitdir+_T("/")+filename, *status, false,pData);
1267 start = end =0;
1268 pos=SearchInSortVector(*treeptr, lowcasepath.GetBuffer(), lowcasepath.GetLength());
1269 if(pos>=0 && GetRangeInSortVector(*treeptr,lowcasepath.GetBuffer(),lowcasepath.GetLength(),&start,&end,pos) == 0)
1271 CGitHeadFileList::iterator it;
1272 CString oldstring;
1274 for(it = treeptr->begin()+start; it <= treeptr->begin()+end; it++)
1276 int start = lowcasepath.GetLength();
1277 int index = (*it).m_FileName.Find(_T('/'), start);
1278 if(index<0)
1279 index = (*it).m_FileName.GetLength();
1281 CString filename = (*it).m_FileName.Mid(start, index-start);
1282 if(oldstring != filename)
1284 oldstring = filename;
1285 if(SearchInSortVector(filelist, filename.GetBuffer(), filename.GetLength())<0)
1287 *status = git_wc_status_deleted;
1288 if(callback)
1289 callback(gitdir+_T("/")+(*it).m_FileName, *status, false,pData);
1295 }/*End of if status*/
1296 }catch(...)
1298 return -1;
1300 return 0;
1303 int GitStatus::GetDirStatus(const CString &gitdir,const CString &subpath,git_wc_status_kind * status,BOOL IsFul, BOOL IsRecursive,BOOL IsIgnore,FIll_STATUS_CALLBACK callback,void *pData)
1307 TCHAR oldpath[MAX_PATH+1];
1308 memset(oldpath,0,MAX_PATH+1);
1310 CString path =subpath;
1312 path.Replace(_T('\\'),_T('/'));
1313 if(!path.IsEmpty())
1314 if(path[path.GetLength()-1] != _T('/'))
1315 path += _T('/'); //Add trail / to show it is directory, not file name.
1317 CString lowcasepath = path;
1318 lowcasepath.MakeLower();
1320 if(status)
1322 g_IndexFileMap.CheckAndUpdate(gitdir, true);
1324 SHARED_INDEX_PTR indexptr = g_IndexFileMap.SafeGet(gitdir);
1326 if (indexptr == NULL)
1328 *status = git_wc_status_unversioned;
1329 return 0;
1332 if(subpath.IsEmpty() && (!indexptr.use_count()))
1333 { // for new init repository
1334 *status = git_wc_status_normal;
1335 if(callback)
1336 callback(gitdir+_T("/")+path, *status, false,pData);
1337 return 0;
1340 int pos=SearchInSortVector(*indexptr,lowcasepath.GetBuffer(),lowcasepath.GetLength());
1342 //Not In Version Contorl
1343 if(pos<0)
1345 if(!IsIgnore)
1347 *status = git_wc_status_unversioned;
1348 if(callback)
1349 callback(gitdir+_T("/")+path, *status, false,pData);
1350 return 0;
1352 //Check ignore always.
1354 if(::g_IgnoreList.CheckIgnoreChanged(gitdir,path))
1355 g_IgnoreList.LoadAllIgnoreFile(gitdir,path);
1357 if(g_IgnoreList.IsIgnore(path,gitdir))
1358 *status = git_wc_status_ignored;
1359 else
1360 *status = git_wc_status_unversioned;
1362 g_HeadFileMap.CheckHeadUpdate(gitdir);
1364 SHARED_TREE_PTR treeptr = g_HeadFileMap.SafeGet(gitdir);
1365 //Check init repository
1366 if(treeptr->m_Head.IsEmpty() && path.IsEmpty())
1367 *status = git_wc_status_normal;
1371 else // In version control
1373 *status = git_wc_status_normal;
1375 int start=0;
1376 int end=0;
1377 if(path.IsEmpty())
1379 start=0;
1380 end=indexptr->size()-1;
1382 GetRangeInSortVector(*indexptr,lowcasepath.GetBuffer(),lowcasepath.GetLength(),&start,&end,pos);
1383 CGitIndexList::iterator it;
1385 it = indexptr->begin()+start;
1387 // Check Conflict;
1388 for(int i=start;i<=end;i++)
1390 if( ((*it).m_Flags & CE_STAGEMASK) !=0)
1392 *status = git_wc_status_conflicted;
1393 if(callback)
1395 int dirpos = (*it).m_FileName.Find(_T('/'), path.GetLength());
1396 if(dirpos<0 || IsRecursive)
1397 callback(gitdir+_T("\\")+ it->m_FileName,git_wc_status_conflicted,false,pData);
1399 else
1400 break;
1402 it++;
1405 if( IsFul && (*status != git_wc_status_conflicted))
1407 *status = git_wc_status_normal;
1409 if(g_HeadFileMap.CheckHeadUpdate(gitdir))
1411 SHARED_TREE_PTR treeptr = g_HeadFileMap.SafeGet(gitdir);
1413 treeptr->ReadHeadHash(gitdir);
1415 if(treeptr->ReadTree())
1417 g_HeadFileMap.SafeSet(gitdir, treeptr);
1420 //Check Add
1421 it = indexptr->begin()+start;
1425 //Check if new init repository
1426 SHARED_TREE_PTR treeptr = g_HeadFileMap.SafeGet(gitdir);
1428 if( treeptr->size() > 0 || treeptr->m_Head.IsEmpty() )
1430 for(int i=start;i<=end;i++)
1432 pos =SearchInSortVector(*treeptr, (*it).m_FileName.GetBuffer(), -1);
1434 if(pos < 0)
1436 *status = max(git_wc_status_modified, *status); // added file found
1437 if(callback)
1439 int dirpos = (*it).m_FileName.Find(_T('/'), path.GetLength());
1440 if(dirpos<0 || IsRecursive)
1441 callback(gitdir+_T("\\")+ it->m_FileName,git_wc_status_added,false, pData);
1444 else
1445 break;
1448 if( pos>=0 && treeptr->at(pos).m_Hash != (*it).m_IndexHash)
1450 *status = max(git_wc_status_modified, *status); // modified file found
1451 if(callback)
1453 int dirpos = (*it).m_FileName.Find(_T('/'), path.GetLength());
1454 if(dirpos<0 || IsRecursive)
1455 callback(gitdir+_T("\\")+ it->m_FileName, git_wc_status_modified,false, pData);
1458 else
1459 break;
1462 it++;
1465 //Check Delete
1466 if( *status == git_wc_status_normal )
1468 pos = SearchInSortVector(*treeptr, lowcasepath.GetBuffer(), lowcasepath.GetLength());
1469 if(pos <0)
1471 *status = max(git_wc_status_modified, *status); // added file found
1474 else
1476 int hstart,hend;
1477 GetRangeInSortVector(*treeptr,lowcasepath.GetBuffer(),lowcasepath.GetLength(),&hstart,&hend,pos);
1478 CGitHeadFileList::iterator hit;
1479 hit = treeptr->begin()+start;
1480 CGitHeadFileList::iterator lastElement = treeptr->end();
1481 for(int i=hstart; i <= hend && hit != lastElement; i++)
1483 if( SearchInSortVector(*indexptr,(*hit).m_FileName.GetBuffer(),-1) < 0)
1485 *status = max(git_wc_status_modified, *status); // deleted file found
1486 break;
1488 hit++;
1493 }/* End lock*/
1495 // If define callback, it need update each file status.
1496 // If not define callback, status == git_wc_status_conflicted, needn't check each file status
1497 // because git_wc_status_conflicted is highest.s
1498 if(callback || (*status != git_wc_status_conflicted))
1500 //Check File Time;
1501 //if(IsRecursive)
1503 CString sub, currentPath;
1504 it = indexptr->begin()+start;
1505 for(int i=start;i<=end;i++,it++)
1507 if( !IsRecursive )
1509 //skip child directory
1510 int pos = (*it).m_FileName.Find(_T('/'), path.GetLength());
1512 if( pos > 0)
1514 currentPath = (*it).m_FileName.Left(pos);
1515 if( callback && (sub != currentPath) )
1517 sub = currentPath;
1518 ATLTRACE(_T("index subdir %s\n"),sub);
1519 if(callback) callback(gitdir + _T("\\")+sub,
1520 git_wc_status_normal,true, pData);
1522 continue;
1526 git_wc_status_kind filestatus = git_wc_status_none;
1528 GetFileStatus(gitdir,(*it).m_FileName, &filestatus,IsFul, IsRecursive,IsIgnore, callback,pData);
1530 if (filestatus > git_wc_status_normal && filestatus != git_wc_status_conflicted)
1531 *status = git_wc_status_modified; // folders can only be modified or conflicted
1537 if(callback) callback(gitdir+_T("/")+subpath,*status,true, pData);
1540 }catch(...)
1542 if(status)
1543 *status = git_wc_status_none;
1544 return -1;
1547 return 0;
1550 bool GitStatus::IsExistIndexLockFile(const CString &gitdir)
1552 CString sDirName= gitdir;
1554 for (;;)
1556 if(PathFileExists(sDirName + _T("\\.git")))
1558 if(PathFileExists(sDirName + _T("\\.git\\index.lock")))
1559 return true;
1560 else
1561 return false;
1564 int x = sDirName.ReverseFind(_T('\\'));
1565 if (x < 2)
1566 return false;
1568 sDirName = sDirName.Left(x);
1571 return false;