Fixed issue #221: After resolving all merge conflicts, it's not obvious the project...
[TortoiseGit.git] / src / Git / GitIndex.cpp
blob470aeab9460e3c86a597d8e0d7d6e9e5f72f5f3b
1 #include "StdAfx.h"
2 #include "Git.h"
3 #include "atlconv.h"
4 #include "GitRev.h"
5 #include "registry.h"
6 #include "GitConfig.h"
7 #include <map>
8 #include "UnicodeUtils.h"
9 #include "TGitPath.h"
10 #include "gitindex.h"
11 #include <sys/types.h>
12 #include <sys/stat.h>
14 typedef CComCritSecLock<CComCriticalSection> CAutoLocker;
16 #define FILL_DATA() \
17 m_FileName.Empty();\
18 g_Git.StringAppend(&m_FileName,(BYTE*)entry->name,CP_ACP,Big2lit(entry->flags)&CE_NAMEMASK);\
19 this->m_Flags=Big2lit(entry->flags);\
20 this->m_ModifyTime=Big2lit(entry->mtime.sec);\
21 this->m_IndexHash=(char*)(entry->sha1);
23 int CGitIndex::FillData(ondisk_cache_entry * entry)
25 FILL_DATA();
26 return 0;
29 int CGitIndex::FillData(ondisk_cache_entry_extended * entry)
31 FILL_DATA();
32 this->m_Flags |= ((int)Big2lit(entry->flags2))<<16;
33 return 0;
36 int CGitIndex::Print()
38 _tprintf(_T("0x%08X 0x%08X %s %s\n"),
39 (int)this->m_ModifyTime,
40 this->m_Flags,
41 this->m_IndexHash.ToString(),
42 this->m_FileName);
44 return 0;
47 CGitIndexList::CGitIndexList()
49 this->m_LastModifyTime=0;
52 int CGitIndexList::ReadIndex(CString IndexFile)
54 HANDLE hfile=INVALID_HANDLE_VALUE;
55 int ret=0;
56 BYTE *buffer=NULL,*p;
57 CGitIndex GitIndex;
59 try
63 this->clear();
64 this->m_Map.clear();
66 hfile = CreateFile(IndexFile,
67 GENERIC_READ,
68 FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE,
69 NULL,
70 OPEN_EXISTING,
71 FILE_ATTRIBUTE_NORMAL,
72 NULL);
75 if(hfile == INVALID_HANDLE_VALUE)
77 ret = -1 ;
78 break;
81 cache_header *header;
82 DWORD size=0,filesize=0;
84 filesize=GetFileSize(hfile,NULL);
86 if(filesize == INVALID_FILE_SIZE )
88 ret =-1;
89 break;
92 buffer = new BYTE[filesize];
93 p=buffer;
94 if(buffer == NULL)
96 ret = -1;
97 break;
99 if(! ReadFile( hfile, buffer,filesize,&size,NULL) )
101 ret = GetLastError();
102 break;
105 CloseHandle(hfile);
106 hfile = INVALID_HANDLE_VALUE; /* close early to above lock time long*/
108 if (size != filesize)
110 ret = -1;
111 break;
113 header = (cache_header *) buffer;
114 if( Big2lit(header->hdr_signature) != CACHE_SIGNATURE )
116 ret = -1;
117 break;
119 p+= sizeof(cache_header);
121 int entries = Big2lit(header->hdr_entries);
122 for(int i=0;i<entries;i++)
124 ondisk_cache_entry *entry;
125 ondisk_cache_entry_extended *entryex;
126 entry=(ondisk_cache_entry*)p;
127 entryex=(ondisk_cache_entry_extended*)p;
128 int flags=Big2lit(entry->flags);
129 if( flags & CE_EXTENDED)
131 GitIndex.FillData(entryex);
132 p+=ondisk_ce_size(entryex);
134 }else
136 GitIndex.FillData(entry);
137 p+=ondisk_ce_size(entry);
140 if(p>buffer+filesize)
142 ret = -1;
143 break;
145 this->push_back(GitIndex);
146 this->m_Map[GitIndex.m_FileName]=this->size()-1;
149 }while(0);
150 }catch(...)
152 ret= -1;
155 if(hfile != INVALID_HANDLE_VALUE)
156 CloseHandle(hfile);
157 if(buffer)
158 delete buffer;
159 return ret;
162 int CGitIndexList::GetFileStatus(CString &gitdir,CString &path,git_wc_status_kind *status,__int64 time,FIll_STATUS_CALLBACK callback,void *pData, CGitHash *pHash)
165 if(status)
167 if(m_Map.find(path) == m_Map.end() )
169 *status = git_wc_status_unversioned;
171 if(pHash)
172 pHash->Empty();
174 }else
176 int index = m_Map[path];
177 if(index <0)
178 return -1;
179 if(index >= size() )
180 return -1;
182 if( time == at(index).m_ModifyTime )
184 *status = git_wc_status_normal;
185 }else
187 *status = git_wc_status_modified;
190 if(at(index).m_Flags & CE_STAGEMASK )
191 *status = git_wc_status_conflicted;
192 else if(at(index).m_Flags & CE_INTENT_TO_ADD)
193 *status = git_wc_status_added;
195 if(pHash)
196 *pHash = at(index).m_IndexHash;
198 if(callback)
199 callback(gitdir+_T("\\")+path,*status,false, pData);
201 return 0;
204 int CGitIndexList::GetStatus(CString &gitdir,CString &path, git_wc_status_kind *status,
205 BOOL IsFull, BOOL IsRecursive,
206 FIll_STATUS_CALLBACK callback,void *pData,
207 CGitHash *pHash)
209 int result;
210 git_wc_status_kind dirstatus = git_wc_status_none;
211 __int64 time;
212 bool isDir=false;
214 if(status)
216 if(path.IsEmpty())
217 result = g_Git.GetFileModifyTime(gitdir,&time,&isDir);
218 else
219 result = g_Git.GetFileModifyTime( gitdir+_T("\\")+path, &time, &isDir );
221 if(result)
223 *status = git_wc_status_deleted;
224 if(callback)
225 callback(gitdir+_T("\\")+path,git_wc_status_deleted,false, pData);
227 return 0;
229 if(isDir)
231 if(!path.IsEmpty())
233 if( path.Right(1) != _T("\\"))
234 path+=_T("\\");
236 int len =path.GetLength();
238 for(int i=0;i<size();i++)
240 if( at(i).m_FileName.GetLength() > len )
242 if(at(i).m_FileName.Left(len) == path)
244 if( !IsFull )
246 *status = git_wc_status_normal;
247 if(callback)
248 callback(gitdir+_T("\\")+path,*status,false, pData);
249 return 0;
251 }else
253 result = g_Git.GetFileModifyTime( gitdir+_T("\\")+at(i).m_FileName , &time);
254 if(result)
255 continue;
257 *status = git_wc_status_none;
258 GetFileStatus(gitdir,at(i).m_FileName,status,time,callback,pData);
259 if( *status != git_wc_status_none )
261 if( dirstatus == git_wc_status_none)
263 dirstatus = git_wc_status_normal;
265 if( *status != git_wc_status_normal )
267 dirstatus = git_wc_status_modified;
276 if( dirstatus != git_wc_status_none )
278 *status = dirstatus;
280 else
282 *status = git_wc_status_unversioned;
284 if(callback)
285 callback(gitdir+_T("\\")+path,*status,false, pData);
287 return 0;
289 }else
291 GetFileStatus(gitdir,path,status,time,callback,pData,pHash);
294 return 0;
297 int CGitIndexFileMap::CheckAndUpdateIndex(CString &gitdir,bool *loaded)
299 __int64 time;
300 int result;
304 CString IndexFile;
305 IndexFile=gitdir+_T("\\.git\\index");
306 /* Get data associated with "crt_stat.c": */
307 result = g_Git.GetFileModifyTime( IndexFile, &time );
309 // WIN32_FILE_ATTRIBUTE_DATA FileInfo;
310 // GetFileAttributesEx(_T("D:\\tortoisegit\\src\\gpl.txt"),GetFileExInfoStandard,&FileInfo);
311 // result = _tstat64( _T("D:\\tortoisegit\\src\\gpl.txt"), &buf );
313 if(loaded)
314 *loaded = false;
316 if(result)
317 return result;
319 if((*this)[gitdir].m_LastModifyTime != time )
321 if((*this)[gitdir].ReadIndex(IndexFile))
322 return -1;
323 if(loaded)
324 *loaded =true;
326 (*this)[gitdir].m_LastModifyTime = time;
328 }catch(...)
330 return -1;
332 return 0;
335 int CGitIndexFileMap::GetFileStatus(CString &gitdir, CString &path, git_wc_status_kind *status,BOOL IsFull, BOOL IsRecursive,
336 FIll_STATUS_CALLBACK callback,void *pData,
337 CGitHash *pHash)
339 int result;
342 CheckAndUpdateIndex(gitdir);
343 (*this)[gitdir].GetStatus(gitdir,path,status,IsFull,IsRecursive,callback,pData,pHash);
345 }catch(...)
347 return -1;
349 return 0;
352 int CGitIndexFileMap::IsUnderVersionControl(CString &gitdir, CString &path, bool isDir,bool *isVersion)
356 if(path.IsEmpty())
358 *isVersion =true;
359 return 0;
361 CString subpath=path;
362 subpath.Replace(_T('\\'), _T('/'));
363 if(isDir)
364 subpath+=_T('/');
366 CheckAndUpdateIndex(gitdir);
367 if(isDir)
369 *isVersion = (SearchInSortVector((*this)[gitdir], subpath.GetBuffer(), subpath.GetLength()) >= 0);
371 else
373 *isVersion = ((*this)[gitdir].m_Map.find(subpath) != (*this)[gitdir].m_Map.end());
376 }catch(...)
378 return -1;
380 return 0;
383 int CGitHeadFileList::GetPackRef(CString &gitdir)
385 CString PackRef = gitdir;
386 PackRef += _T("\\.git\\packed-refs");
388 __int64 mtime;
389 if( g_Git.GetFileModifyTime(PackRef, &mtime))
391 //packed refs is not existed
392 this->m_PackRefFile.Empty();
393 this->m_PackRefMap.clear();
394 return 0;
396 }else if(mtime == m_LastModifyTimePackRef)
398 return 0;
400 }else
402 this->m_PackRefFile = PackRef;
403 this->m_LastModifyTimePackRef = mtime;
406 this->m_PackRefMap.clear();
408 int ret =0;
409 HANDLE hfile = CreateFile(PackRef,
410 GENERIC_READ,
411 FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE,
412 NULL,
413 OPEN_EXISTING,
414 FILE_ATTRIBUTE_NORMAL,
415 NULL);
418 if(hfile == INVALID_HANDLE_VALUE)
420 ret = -1;
421 break;
424 int filesize = GetFileSize(hfile,NULL);
425 DWORD size =0;
426 char *buff;
427 buff = new char[filesize];
429 ReadFile(hfile,buff,filesize,&size,NULL);
431 if(size != filesize)
433 ret = -1;
434 break;
437 CString hash;
438 CString ref;
440 for(int i=0;i<filesize;i++)
442 hash.Empty();
443 ref.Empty();
444 if(buff[i] == '#')
446 while(buff[i] != '\n')
447 { i++;
448 if( i==filesize)
449 break;
451 i++;
454 if( i== filesize)
455 break;
457 while(buff[i] != ' ')
459 hash.AppendChar(buff[i]);
460 i++;
461 if(i==filesize)
462 break;
465 i++;
466 if( i== filesize)
467 break;
469 while(buff[i] != '\n')
471 ref.AppendChar(buff[i]);
472 i++;
473 if( i== filesize)
474 break;
477 i++;
479 if( !ref.IsEmpty() )
481 this->m_PackRefMap[ref] = hash;
487 delete buff;
489 }while(0);
491 if( hfile != INVALID_HANDLE_VALUE)
492 CloseHandle(hfile);
494 return ret;
497 int CGitHeadFileList::ReadHeadHash(CString gitdir)
499 CString HeadFile = gitdir;
500 HeadFile += _T("\\.git\\HEAD");
503 HANDLE hfile=INVALID_HANDLE_VALUE;
504 HANDLE href = INVALID_HANDLE_VALUE;
506 int ret = 0;
507 m_Gitdir = gitdir;
509 m_HeadFile = HeadFile;
511 if( g_Git.GetFileModifyTime(m_HeadFile,&m_LastModifyTimeHead))
512 return -1;
518 hfile = CreateFile(HeadFile,
519 GENERIC_READ,
520 FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE,
521 NULL,
522 OPEN_EXISTING,
523 FILE_ATTRIBUTE_NORMAL,
524 NULL);
526 if(hfile == INVALID_HANDLE_VALUE)
528 ret = -1;
529 break;
532 DWORD size=0,filesize=0;
533 unsigned char buffer[40] ;
534 ReadFile(hfile,buffer,4,&size,NULL);
535 if(size !=4)
537 ret = -1;
538 break;
540 buffer[4]=0;
541 if(strcmp((const char*)buffer,"ref:") == 0)
543 filesize = GetFileSize(hfile,NULL);
545 unsigned char *p = (unsigned char*)malloc(filesize -4);
547 ReadFile(hfile,p,filesize-4,&size,NULL);
549 m_HeadRefFile.Empty();
550 g_Git.StringAppend(&this->m_HeadRefFile,p,CP_ACP,filesize-4);
551 CString ref = this->m_HeadRefFile;
552 ref=ref.Trim();
553 int start =0;
554 ref=ref.Tokenize(_T("\n"),start);
555 free(p);
556 m_HeadRefFile=gitdir+_T("\\.git\\")+m_HeadRefFile.Trim();
557 m_HeadRefFile.Replace(_T('/'),_T('\\'));
559 __int64 time;
560 if(g_Git.GetFileModifyTime(m_HeadRefFile,&time,NULL))
562 if( GetPackRef(gitdir))
564 ret = -1;
565 break;
567 if(this->m_PackRefMap.find(ref) == m_PackRefMap.end())
569 ret = -1;
570 break;
572 this ->m_Head = m_PackRefMap[ref];
573 ret =0;
574 break;
577 href = CreateFile(m_HeadRefFile,
578 GENERIC_READ,
579 FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE,
580 NULL,
581 OPEN_EXISTING,
582 FILE_ATTRIBUTE_NORMAL,
583 NULL);
585 if(href == INVALID_HANDLE_VALUE)
587 if( GetPackRef(gitdir))
589 ret = -1;
590 break;
593 if(this->m_PackRefMap.find(ref) == m_PackRefMap.end())
595 ret = -1;
596 break;
598 this ->m_Head = m_PackRefMap[ref];
599 ret =0;
600 break;
602 ReadFile(href,buffer,40,&size,NULL);
603 if(size != 40)
605 ret =-1;
606 break;
608 this->m_Head.ConvertFromStrA((char*)buffer);
610 this->m_LastModifyTimeRef = time;
612 }else
614 ReadFile(hfile,buffer+4,40-4,&size,NULL);
615 if(size !=36)
617 ret =-1;
618 break;
620 m_HeadRefFile.Empty();
622 this->m_Head.ConvertFromStrA((char*)buffer);
624 }while(0);
625 }catch(...)
627 ret = -1;
630 if(hfile != INVALID_HANDLE_VALUE)
631 CloseHandle(hfile);
632 if(href != INVALID_HANDLE_VALUE)
633 CloseHandle(href);
635 return ret;
638 bool CGitHeadFileList::CheckHeadUpdate()
640 if(this->m_HeadFile.IsEmpty())
641 return true;
643 __int64 mtime=0;
645 if( g_Git.GetFileModifyTime(m_HeadFile,&mtime))
646 return true;
648 if(mtime != this->m_LastModifyTimeHead)
649 return true;
651 if(!this->m_HeadRefFile.IsEmpty())
653 if(g_Git.GetFileModifyTime(m_HeadRefFile,&mtime))
654 return true;
656 if(mtime != this->m_LastModifyTimeRef)
657 return true;
660 if(!this->m_PackRefFile.IsEmpty())
662 if(g_Git.GetFileModifyTime(m_PackRefFile,&mtime))
663 return true;
665 if(mtime != this->m_LastModifyTimePackRef)
666 return true;
668 return false;
671 int CGitHeadFileList::ReadTree()
673 int ret;
674 if( this->m_Head.IsEmpty())
675 return -1;
677 CAutoLocker lock(g_Git.m_critGitDllSec);
679 if(m_Gitdir != g_Git.m_CurrentDir)
681 g_Git.SetCurrentDir(m_Gitdir);
682 SetCurrentDirectory(g_Git.m_CurrentDir);
683 git_init();
686 this->m_Map.clear();
687 this->clear();
689 ret = git_read_tree(this->m_Head.m_hash,CGitHeadFileList::CallBack,this);
690 if(!ret)
691 m_TreeHash = m_Head;
693 return ret;
696 int CGitHeadFileList::CallBack(const unsigned char *sha1, const char *base, int baselen,
697 const char *pathname, unsigned mode, int stage, void *context)
699 #define S_IFGITLINK 0160000
701 CGitHeadFileList *p = (CGitHeadFileList*)context;
702 if( mode&S_IFDIR )
704 if( (mode&S_IFMT) != S_IFGITLINK)
705 return READ_TREE_RECURSIVE;
708 unsigned int cur = p->size();
709 p->resize(p->size()+1);
710 p->at(cur).m_Hash = (char*)sha1;
711 p->at(cur).m_FileName.Empty();
713 if(base)
714 g_Git.StringAppend(&p->at(cur).m_FileName,(BYTE*)base,CP_ACP,baselen);
716 g_Git.StringAppend(&p->at(cur).m_FileName,(BYTE*)pathname,CP_ACP);
718 //p->at(cur).m_FileName.Replace(_T('/'),_T('\\'));
720 p->m_Map[p->at(cur).m_FileName]=cur;
722 if( (mode&S_IFMT) == S_IFGITLINK)
723 return 0;
725 return READ_TREE_RECURSIVE;
728 int CGitIgnoreItem::FetchIgnoreList(CString &projectroot, CString &file)
730 if(this->m_pExcludeList)
732 free(m_pExcludeList);
733 m_pExcludeList=NULL;
736 this->m_BaseDir.Empty();
737 if( projectroot.GetLength() < file.GetLength())
739 CString base = file.Mid(projectroot.GetLength()+1);
740 base.Replace(_T('\\'), _T('/'));
741 if(base != _T(".git/info/exclude"))
743 int start=base.ReverseFind(_T('/'));
744 if(start>=0)
746 base=base.Left(start);
747 this->m_BaseDir = CUnicodeUtils::GetMulti(base,CP_ACP) ;
753 if(g_Git.GetFileModifyTime(file,&m_LastModifyTime))
754 return -1;
756 if(git_create_exclude_list(&this->m_pExcludeList))
757 return -1;
760 HANDLE hfile = CreateFile(file,
761 GENERIC_READ,
762 FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE,
763 NULL,
764 OPEN_EXISTING,
765 FILE_ATTRIBUTE_NORMAL,
766 NULL);
769 if(hfile == INVALID_HANDLE_VALUE)
771 return -1 ;
774 DWORD size=0,filesize=0;
776 filesize=GetFileSize(hfile,NULL);
778 if(filesize == INVALID_FILE_SIZE )
780 CloseHandle(hfile);
781 return -1;
784 BYTE *buffer = new BYTE[filesize+1];
786 if(buffer == NULL)
788 CloseHandle(hfile);
789 return -1;
792 if(! ReadFile( hfile, buffer,filesize,&size,NULL) )
794 CloseHandle(hfile);
795 return GetLastError();
798 CloseHandle(hfile);
800 BYTE *p = buffer;
801 for(int i=0;i<size;i++)
803 if( buffer[i] == '\n' || buffer[i] =='\r' || i==(size-1) )
805 if (buffer[i] == '\n' || buffer[i] =='\r')
806 buffer[i]=0;
807 if( i== size-1)
808 buffer[size]=0;
810 if(p[0] != '#' && p[0] != 0)
811 git_add_exclude((const char*)p,
812 this->m_BaseDir.GetBuffer(),
813 m_BaseDir.GetLength(),
814 this->m_pExcludeList);
816 p=buffer+i+1;
819 /* Can't free buffer, exluced list will use this buffer*/
820 //delete buffer;
821 //buffer=NULL;
823 return 0;
826 bool CGitIgnoreList::CheckFileChanged(CString &path)
828 __int64 time=0;
829 int ret=g_Git.GetFileModifyTime(path, &time);
831 bool cacheExist = (m_Map.find(path) != m_Map.end());
833 // both cache and file is not exist
834 if( (ret != 0) && (!cacheExist))
835 return false;
837 // file exist but cache miss
838 if( (ret == 0) && (!cacheExist))
839 return true;
841 // file not exist but cache exist
842 if( (ret != 0) && (cacheExist))
844 return true;
846 // file exist and cache exist
847 if( m_Map[path].m_LastModifyTime == time )
848 return false;
850 return true;
854 bool CGitIgnoreList::CheckIgnoreChanged(CString &gitdir,CString &path)
856 CString temp;
857 temp=gitdir;
858 temp+=_T("\\");
859 temp+=path;
861 temp.Replace(_T('/'), _T('\\'));
863 while(!temp.IsEmpty())
865 temp+=_T("\\.git");
867 if(CGit::GitPathFileExists(temp))
869 CString gitignore=temp;
870 gitignore += _T("ignore");
871 if( CheckFileChanged(gitignore) )
872 return true;
874 temp+=_T("\\info\\exclude");
876 if( CheckFileChanged(temp) )
877 return true;
878 else
879 return false;
880 }else
882 temp+=_T("ignore");
883 if( CheckFileChanged(temp) )
884 return true;
887 int found=0;
888 int i;
889 for( i=temp.GetLength() -1;i>=0;i--)
891 if(temp[i] == _T('\\'))
892 found ++;
894 if(found == 2)
895 break;
898 temp = temp.Left(i);
900 return true;
903 int CGitIgnoreList::LoadAllIgnoreFile(CString &gitdir,CString &path)
905 CString temp;
907 temp=gitdir;
908 temp+=_T("\\");
909 temp+=path;
911 temp.Replace(_T('/'), _T('\\'));
913 while(!temp.IsEmpty())
915 temp+=_T("\\.git");
917 if(CGit::GitPathFileExists(temp))
919 CString gitignore = temp;
920 gitignore += _T("ignore");
921 if( CheckFileChanged(gitignore) )
923 if(CGit::GitPathFileExists(temp)) //if .gitignore remove, we need remote cache
925 m_Map[gitignore].FetchIgnoreList(gitdir,gitignore);
927 else
928 m_Map.erase(gitignore);
931 temp+=_T("\\info\\exclude");
933 if( CheckFileChanged(temp) )
935 if(CGit::GitPathFileExists(temp)) //if .gitignore remove, we need remote cache
936 return m_Map[temp].FetchIgnoreList(gitdir,temp);
937 else
939 m_Map.erase(temp);
940 return 0;
944 return 0;
946 }else
948 temp+=_T("ignore");
949 if( CheckFileChanged(temp) )
951 if(CGit::GitPathFileExists(temp)) //if .gitignore remove, we need remote cache
952 m_Map[temp].FetchIgnoreList(gitdir,temp);
953 else
954 m_Map.erase(temp);
958 int found=0;
959 int i;
960 for( i=temp.GetLength() -1;i>=0;i--)
962 if(temp[i] == _T('\\'))
963 found ++;
965 if(found == 2)
966 break;
969 temp = temp.Left(i);
971 return 0;
973 int CGitIgnoreList::GetIgnoreFileChangeTimeList(CString &path, std::vector<__int64> &timelist)
975 CString temp=path;
976 CString ignore=temp;
977 int start =0;
980 ignore=temp;
981 ignore+=_T("\\.gitignore");
982 std::map<CString, CGitIgnoreItem>::iterator itMap;
983 itMap = m_Map.find(ignore);
984 if(itMap == m_Map.end())
986 timelist.push_back(0);
988 }else
990 timelist.push_back(itMap->second.m_LastModifyTime);
993 ignore =temp;
994 ignore += _T("\\.git\\info\\exclude");
996 itMap = m_Map.find(ignore);
997 if(itMap == m_Map.end())
1000 }else
1002 timelist.push_back(itMap->second.m_LastModifyTime);
1003 return 0;
1006 ignore=temp;
1007 ignore+=_T("\\.git");
1009 if(CGit::GitPathFileExists(ignore))
1010 return 0;
1012 start = temp.ReverseFind(_T('\\'));
1013 if(start>0)
1014 temp=temp.Left(start);
1016 }while(start>0);
1018 return -1;
1021 bool CGitIgnoreList::IsIgnore(CString &path,CString &projectroot)
1023 CString str=path;
1025 str.Replace(_T('\\'),_T('/'));
1027 int ret;
1028 ret = CheckIgnore(path, projectroot);
1029 while(ret < 0)
1031 int start=str.ReverseFind(_T('/'));
1032 if(start<0)
1033 return (ret == 1);
1035 str=str.Left(start);
1036 ret = CheckIgnore(str, projectroot);
1039 return (ret == 1);
1041 int CGitIgnoreList::CheckIgnore(CString &path,CString &projectroot)
1043 __int64 time=0;
1044 bool dir=0;
1045 CString temp=projectroot+_T("\\")+path;
1046 temp.Replace(_T('/'), _T('\\'));
1048 CStringA patha;
1050 patha = CUnicodeUtils::GetMulti(path,CP_ACP) ;
1051 patha.Replace('\\','/');
1053 if(g_Git.GetFileModifyTime(temp,&time,&dir))
1054 return -1;
1056 int type=0;
1057 if( dir )
1058 type = DT_DIR;
1059 else
1060 type = DT_REG;
1062 while(!temp.IsEmpty())
1064 int x;
1065 x=temp.ReverseFind(_T('\\'));
1066 if(x<0) x=0;
1067 temp=temp.Left(x);
1069 temp+=_T("\\.gitignore");
1071 char *base;
1073 patha.Replace('\\', '/');
1074 int pos=patha.ReverseFind('/');
1075 base = pos>=0? patha.GetBuffer()+pos+1:patha.GetBuffer();
1077 if(this->m_Map.find(temp) == m_Map.end() )
1080 }else
1082 int ret=-1;
1084 if(m_Map[temp].m_pExcludeList)
1085 ret = git_check_excluded_1( patha, patha.GetLength(), base, &type, m_Map[temp].m_pExcludeList);
1087 if(ret == 1)
1088 return 1;
1089 if(ret == 0)
1090 return 0;
1093 temp = temp.Left(temp.GetLength()-11);
1094 temp +=_T("\\.git\\info\\exclude");
1096 if(this->m_Map.find(temp) == m_Map.end() )
1099 }else
1101 int ret=-1;
1103 if(m_Map[temp].m_pExcludeList)
1104 git_check_excluded_1( patha, patha.GetLength(), base, &type, m_Map[temp].m_pExcludeList);
1106 if(ret == 1)
1107 return 1;
1108 if(ret == 0)
1109 return 0;
1111 return -1;
1113 temp = temp.Left(temp.GetLength()-18);
1116 return -1;
1119 #if 0
1121 int CGitStatus::GetStatus(CString &gitdir, CString &path, git_wc_status_kind *status, BOOL IsFull, BOOL IsRecursive , FIll_STATUS_CALLBACK callback , void *pData)
1123 int result;
1124 __int64 time;
1125 bool dir;
1127 git_wc_status_kind dirstatus = git_wc_status_none;
1128 if(status)
1130 g_Git.GetFileModifyTime(path,&time,&dir);
1131 if( dir)
1133 }else
1137 if(path.IsEmpty())
1138 result = _tstat64( gitdir, &buf );
1139 else
1140 result = _tstat64( gitdir+_T("\\")+path, &buf );
1142 if(result)
1143 return -1;
1145 if(buf.st_mode & _S_IFDIR)
1147 if(!path.IsEmpty())
1149 if( path.Right(1) != _T("\\"))
1150 path+=_T("\\");
1152 int len =path.GetLength();
1154 for(int i=0;i<size();i++)
1156 if( at(i).m_FileName.GetLength() > len )
1158 if(at(i).m_FileName.Left(len) == path)
1160 if( !IsFull )
1162 *status = git_wc_status_normal;
1163 if(callback)
1164 callback(gitdir+_T("\\")+path,*status,pData);
1165 return 0;
1167 }else
1169 result = _tstat64( gitdir+_T("\\")+at(i).m_FileName, &buf );
1170 if(result)
1171 continue;
1173 *status = git_wc_status_none;
1174 GetFileStatus(gitdir,at(i).m_FileName,status,buf,callback,pData);
1175 if( *status != git_wc_status_none )
1177 if( dirstatus == git_wc_status_none)
1179 dirstatus = git_wc_status_normal;
1181 if( *status != git_wc_status_normal )
1183 dirstatus = git_wc_status_modified;
1192 if( dirstatus != git_wc_status_none )
1194 *status = dirstatus;
1196 else
1198 *status = git_wc_status_unversioned;
1200 if(callback)
1201 callback(gitdir+_T("\\")+path,*status,pData);
1203 return 0;
1205 }else
1207 GetFileStatus(gitdir,path,status,buf,callback,pData);
1210 return 0;
1213 #endif