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.
25 #include "GitConfig.h"
27 #include "UnicodeUtils.h"
30 #include <sys/types.h>
37 g_Git.StringAppend(&m_FileName,(BYTE*)entry->name,CP_ACP,Big2lit(entry->flags)&CE_NAMEMASK);\
38 m_FileName.MakeLower(); \
39 this->m_Flags=Big2lit(entry->flags);\
40 this->m_ModifyTime=Big2lit(entry->mtime.sec);\
41 this->m_IndexHash=(char*)(entry->sha1);
43 int CGitIndex::FillData(ondisk_cache_entry
* entry
)
49 int CGitIndex::FillData(ondisk_cache_entry_extended
* entry
)
52 this->m_Flags
|= ((int)Big2lit(entry
->flags2
))<<16;
56 int CGitIndex::Print()
58 _tprintf(_T("0x%08X 0x%08X %s %s\n"),
59 (int)this->m_ModifyTime
,
61 this->m_IndexHash
.ToString(),
67 CGitIndexList::CGitIndexList()
69 this->m_LastModifyTime
=0;
72 static bool SortIndex(CGitIndex
&Item1
, CGitIndex
&Item2
)
74 return Item1
.m_FileName
.Compare(Item2
.m_FileName
)<0;
77 static bool SortTree(CGitTreeItem
&Item1
, CGitTreeItem
&Item2
)
79 return Item1
.m_FileName
.Compare(Item2
.m_FileName
)<0;
82 int CGitIndexList::ReadIndex(CString IndexFile
)
84 HANDLE hfile
=INVALID_HANDLE_VALUE
;
85 HANDLE hmap
= INVALID_HANDLE_VALUE
;
91 m_GitFile
= IndexFile
;
100 hfile
= CreateFile(IndexFile
,
102 FILE_SHARE_READ
|FILE_SHARE_DELETE
|FILE_SHARE_WRITE
,
105 FILE_ATTRIBUTE_NORMAL
,
109 if(hfile
== INVALID_HANDLE_VALUE
)
115 hmap
= CreateFileMapping(hfile
, NULL
, PAGE_READONLY
,0,0,NULL
);
116 if(hmap
== INVALID_HANDLE_VALUE
)
122 p
= buffer
= (BYTE
*)MapViewOfFile(hmap
,FILE_MAP_READ
,0,0,0);
129 cache_header
*header
;
130 header
= (cache_header
*) buffer
;
132 if( Big2lit(header
->hdr_signature
) != CACHE_SIGNATURE
)
137 p
+= sizeof(cache_header
);
139 int entries
= Big2lit(header
->hdr_entries
);
142 for(int i
=0;i
<entries
;i
++)
144 ondisk_cache_entry
*entry
;
145 ondisk_cache_entry_extended
*entryex
;
146 entry
=(ondisk_cache_entry
*)p
;
147 entryex
=(ondisk_cache_entry_extended
*)p
;
148 int flags
=Big2lit(entry
->flags
);
149 if( flags
& CE_EXTENDED
)
151 this->at(i
).FillData(entryex
);
152 p
+=ondisk_ce_size(entryex
);
155 this->at(i
).FillData(entry
);
156 p
+=ondisk_ce_size(entry
);
160 std::sort(this->begin(), this->end(), SortIndex
);
161 g_Git
.GetFileModifyTime(IndexFile
, &this->m_LastModifyTime
);
169 UnmapViewOfFile(buffer
);
171 if(hmap
!= INVALID_HANDLE_VALUE
)
174 if(hfile
!= INVALID_HANDLE_VALUE
)
180 int CGitIndexList::GetFileStatus(const CString
&gitdir
,const CString
&pathorg
,git_wc_status_kind
*status
,__int64 time
,FIll_STATUS_CALLBACK callback
,void *pData
, CGitHash
*pHash
)
184 CString path
= pathorg
;
187 int start
=SearchInSortVector(*this, ((CString
&)path
).GetBuffer(),-1);
188 ((CString
&)path
).ReleaseBuffer();
192 *status
= git_wc_status_unversioned
;
204 if( time
== at(index
).m_ModifyTime
)
206 *status
= git_wc_status_normal
;
209 *status
= git_wc_status_modified
;
212 if(at(index
).m_Flags
& CE_STAGEMASK
)
213 *status
= git_wc_status_conflicted
;
214 else if(at(index
).m_Flags
& CE_INTENT_TO_ADD
)
215 *status
= git_wc_status_added
;
218 *pHash
= at(index
).m_IndexHash
;
223 if(callback
&& status
)
224 callback(gitdir
+_T("\\")+pathorg
,*status
,false, pData
);
228 int CGitIndexList::GetStatus(const CString
&gitdir
,const CString
&pathParam
, git_wc_status_kind
*status
,
229 BOOL IsFull
, BOOL IsRecursive
,
230 FIll_STATUS_CALLBACK callback
,void *pData
,
234 git_wc_status_kind dirstatus
= git_wc_status_none
;
237 CString path
= pathParam
;
242 result
= g_Git
.GetFileModifyTime(gitdir
,&time
,&isDir
);
244 result
= g_Git
.GetFileModifyTime( gitdir
+_T("\\")+path
, &time
, &isDir
);
248 *status
= git_wc_status_deleted
;
250 callback(gitdir
+_T("\\")+path
,git_wc_status_deleted
,false, pData
);
258 if( path
.Right(1) != _T("\\"))
261 int len
=path
.GetLength();
263 for(int i
=0;i
<size();i
++)
265 if( at(i
).m_FileName
.GetLength() > len
)
267 if(at(i
).m_FileName
.Left(len
) == path
)
271 *status
= git_wc_status_normal
;
273 callback(gitdir
+_T("\\")+path
,*status
,false, pData
);
278 result
= g_Git
.GetFileModifyTime( gitdir
+_T("\\")+at(i
).m_FileName
, &time
);
282 *status
= git_wc_status_none
;
283 GetFileStatus(gitdir
,at(i
).m_FileName
,status
,time
,callback
,pData
);
284 if( *status
!= git_wc_status_none
)
286 if( dirstatus
== git_wc_status_none
)
288 dirstatus
= git_wc_status_normal
;
290 if( *status
!= git_wc_status_normal
)
292 dirstatus
= git_wc_status_modified
;
301 if( dirstatus
!= git_wc_status_none
)
307 *status
= git_wc_status_unversioned
;
310 callback(gitdir
+_T("\\")+path
,*status
,false, pData
);
316 GetFileStatus(gitdir
,path
,status
,time
,callback
,pData
,pHash
);
322 int CGitIndexFileMap::Check(const CString
&gitdir
, bool *isChanged
)
328 IndexFile
=gitdir
+_T("\\.git\\index");
329 /* Get data associated with "crt_stat.c": */
330 result
= g_Git
.GetFileModifyTime( IndexFile
, &time
);
335 SHARED_INDEX_PTR pIndex
;
336 pIndex
= this->SafeGet(gitdir
);
338 if(pIndex
.get() == NULL
)
345 if(pIndex
->m_LastModifyTime
== time
)
358 int CGitIndexFileMap::LoadIndex(const CString
&gitdir
)
362 SHARED_INDEX_PTR
pIndex(new CGitIndexList
);
364 if(pIndex
->ReadIndex(gitdir
+_T("\\.git\\index")))
367 this->SafeSet(gitdir
,pIndex
);
376 int CGitIndexFileMap::GetFileStatus(const CString
&gitdir
, const CString
&path
, git_wc_status_kind
*status
,BOOL IsFull
, BOOL IsRecursive
,
377 FIll_STATUS_CALLBACK callback
,void *pData
,
379 bool isLoadUpdatedIndex
)
383 CheckAndUpdate(gitdir
, isLoadUpdatedIndex
);
385 SHARED_INDEX_PTR pIndex
= this->SafeGet(gitdir
);
386 if(pIndex
.get() != NULL
)
388 pIndex
->GetStatus(gitdir
,path
,status
,IsFull
,IsRecursive
,callback
,pData
,pHash
);
398 int CGitIndexFileMap::IsUnderVersionControl(const CString
&gitdir
, const CString
&path
, bool isDir
,bool *isVersion
, bool isLoadUpdateIndex
)
408 CString subpath
=path
;
409 subpath
.Replace(_T('\\'), _T('/'));
415 CheckAndUpdate(gitdir
, isLoadUpdateIndex
);
417 SHARED_INDEX_PTR pIndex
= this->SafeGet(gitdir
);
422 *isVersion
= (SearchInSortVector(*pIndex
, subpath
.GetBuffer(), subpath
.GetLength()) >= 0);
424 *isVersion
= (SearchInSortVector(*pIndex
, subpath
.GetBuffer(), -1) >= 0);
434 int CGitHeadFileList::GetPackRef(const CString
&gitdir
)
436 CString PackRef
= gitdir
;
437 PackRef
+= _T("\\.git\\packed-refs");
440 if( g_Git
.GetFileModifyTime(PackRef
, &mtime
))
442 //packed refs is not existed
443 this->m_PackRefFile
.Empty();
444 this->m_PackRefMap
.clear();
447 }else if(mtime
== m_LastModifyTimePackRef
)
453 this->m_PackRefFile
= PackRef
;
454 this->m_LastModifyTimePackRef
= mtime
;
459 this->m_PackRefMap
.clear();
461 HANDLE hfile
= CreateFile(PackRef
,
463 FILE_SHARE_READ
|FILE_SHARE_DELETE
|FILE_SHARE_WRITE
,
466 FILE_ATTRIBUTE_NORMAL
,
470 if(hfile
== INVALID_HANDLE_VALUE
)
476 DWORD filesize
= GetFileSize(hfile
,NULL
);
479 buff
= new char[filesize
];
481 ReadFile(hfile
,buff
,filesize
,&size
,NULL
);
492 for(DWORD i
=0;i
<filesize
;i
++)
498 while(buff
[i
] != '\n')
509 while(buff
[i
] != ' ')
511 hash
.AppendChar(buff
[i
]);
521 while(buff
[i
] != '\n')
523 ref
.AppendChar(buff
[i
]);
533 this->m_PackRefMap
[ref
] = hash
;
543 if( hfile
!= INVALID_HANDLE_VALUE
)
549 int CGitHeadFileList::ReadHeadHash(CString gitdir
)
551 CString HeadFile
= gitdir
;
552 HeadFile
+= _T("\\.git\\HEAD");
555 HANDLE hfile
=INVALID_HANDLE_VALUE
;
556 HANDLE href
= INVALID_HANDLE_VALUE
;
561 m_HeadFile
= HeadFile
;
563 if( g_Git
.GetFileModifyTime(m_HeadFile
,&m_LastModifyTimeHead
))
570 hfile
= CreateFile(HeadFile
,
572 FILE_SHARE_READ
|FILE_SHARE_DELETE
|FILE_SHARE_WRITE
,
575 FILE_ATTRIBUTE_NORMAL
,
578 if(hfile
== INVALID_HANDLE_VALUE
)
584 DWORD size
=0,filesize
=0;
585 unsigned char buffer
[40] ;
586 ReadFile(hfile
,buffer
,4,&size
,NULL
);
593 if(strcmp((const char*)buffer
,"ref:") == 0)
595 filesize
= GetFileSize(hfile
,NULL
);
597 unsigned char *p
= (unsigned char*)malloc(filesize
-4);
599 ReadFile(hfile
,p
,filesize
-4,&size
,NULL
);
601 m_HeadRefFile
.Empty();
602 g_Git
.StringAppend(&this->m_HeadRefFile
,p
,CP_ACP
,filesize
-4);
603 CString ref
= this->m_HeadRefFile
;
606 ref
=ref
.Tokenize(_T("\n"),start
);
608 m_HeadRefFile
=gitdir
+_T("\\.git\\")+m_HeadRefFile
.Trim();
609 m_HeadRefFile
.Replace(_T('/'),_T('\\'));
612 if(g_Git
.GetFileModifyTime(m_HeadRefFile
,&time
,NULL
))
614 m_HeadRefFile
.Empty();
615 if( GetPackRef(gitdir
))
620 if(this->m_PackRefMap
.find(ref
) == m_PackRefMap
.end())
625 this ->m_Head
= m_PackRefMap
[ref
];
630 href
= CreateFile(m_HeadRefFile
,
632 FILE_SHARE_READ
|FILE_SHARE_DELETE
|FILE_SHARE_WRITE
,
635 FILE_ATTRIBUTE_NORMAL
,
638 if(href
== INVALID_HANDLE_VALUE
)
640 m_HeadRefFile
.Empty();
642 if( GetPackRef(gitdir
))
648 if(this->m_PackRefMap
.find(ref
) == m_PackRefMap
.end())
653 this ->m_Head
= m_PackRefMap
[ref
];
657 ReadFile(href
,buffer
,40,&size
,NULL
);
663 this->m_Head
.ConvertFromStrA((char*)buffer
);
665 this->m_LastModifyTimeRef
= time
;
669 ReadFile(hfile
,buffer
+4,40-4,&size
,NULL
);
675 m_HeadRefFile
.Empty();
677 this->m_Head
.ConvertFromStrA((char*)buffer
);
685 if(hfile
!= INVALID_HANDLE_VALUE
)
687 if(href
!= INVALID_HANDLE_VALUE
)
693 bool CGitHeadFileList::CheckHeadUpdate()
695 if(this->m_HeadFile
.IsEmpty())
700 if( g_Git
.GetFileModifyTime(m_HeadFile
,&mtime
))
703 if(mtime
!= this->m_LastModifyTimeHead
)
706 if(!this->m_HeadRefFile
.IsEmpty())
708 if(g_Git
.GetFileModifyTime(m_HeadRefFile
,&mtime
))
711 if(mtime
!= this->m_LastModifyTimeRef
)
715 if(!this->m_PackRefFile
.IsEmpty())
717 if(g_Git
.GetFileModifyTime(m_PackRefFile
,&mtime
))
720 if(mtime
!= this->m_LastModifyTimePackRef
)
726 int CGitHeadFileList::ReadTree()
729 if( this->m_Head
.IsEmpty())
734 CAutoLocker
lock(g_Git
.m_critGitDllSec
);
735 CAutoWriteLock
lock1(&this->m_SharedMutex
);
737 if(m_Gitdir
!= g_Git
.m_CurrentDir
)
739 g_Git
.SetCurrentDir(m_Gitdir
);
740 SetCurrentDirectory(g_Git
.m_CurrentDir
);
747 ret
= git_read_tree(this->m_Head
.m_hash
,CGitHeadFileList::CallBack
,this);
759 int CGitHeadFileList::CallBack(const unsigned char *sha1
, const char *base
, int baselen
,
760 const char *pathname
, unsigned mode
, int /*stage*/, void *context
)
762 #define S_IFGITLINK 0160000
764 CGitHeadFileList
*p
= (CGitHeadFileList
*)context
;
767 if( (mode
&S_IFMT
) != S_IFGITLINK
)
768 return READ_TREE_RECURSIVE
;
771 unsigned int cur
= p
->size();
772 p
->resize(p
->size()+1);
773 p
->at(cur
).m_Hash
= (char*)sha1
;
774 p
->at(cur
).m_FileName
.Empty();
777 g_Git
.StringAppend(&p
->at(cur
).m_FileName
,(BYTE
*)base
,CP_ACP
,baselen
);
779 g_Git
.StringAppend(&p
->at(cur
).m_FileName
,(BYTE
*)pathname
,CP_ACP
);
781 p
->at(cur
).m_FileName
.MakeLower();
783 //p->at(cur).m_FileName.Replace(_T('/'),_T('\\'));
785 //p->m_Map[p->at(cur).m_FileName]=cur;
787 if( (mode
&S_IFMT
) == S_IFGITLINK
)
790 return READ_TREE_RECURSIVE
;
793 int ReadTreeRecurive(git_tree
* tree
, CStringA base
, int (*CallBack
) (const unsigned char *, const char *, int, const char *, unsigned int, int, void *),void *data
)
795 size_t count
= git_tree_entrycount(tree
);
796 for(int i
=0; i
<count
; i
++)
798 git_tree_entry
*entry
= git_tree_entry_byindex(tree
, i
);
799 int mode
= git_tree_entry_attributes(entry
);
800 if( CallBack(git_tree_entry_id(entry
)->id
,
803 git_tree_entry_name(entry
),
806 data
) == READ_TREE_RECURSIVE
812 git_tree_entry_2object(&object
, entry
);
813 CStringA parent
= base
;
814 parent
+= git_tree_entry_name(entry
);
816 ReadTreeRecurive((git_tree
*)object
,parent
, CallBack
,data
);
825 int CGitHeadFileList::ReadTree()
827 CStringA gitdir
= CUnicodeUtils::GetMulti(m_Gitdir
,CP_ACP
) ;
829 git_repository
*repository
= NULL
;
830 git_commit
*commit
= NULL
;
831 git_tree
* tree
= NULL
;
835 ret
= git_repository_open(&repository
, gitdir
.GetBuffer());
838 ret
= git_commit_lookup(&commit
, repository
, (const git_oid
*)m_Head
.m_hash
);
842 tree
= (git_tree
*)git_commit_tree(commit
);
844 ret
= ReadTreeRecurive(tree
,"", CGitHeadFileList::CallBack
,this);
848 std::sort(this->begin(), this->end(), SortTree
);
849 this->m_TreeHash
= (char*)(git_commit_id(commit
)->id
);
854 git_repository_free(repository
);
859 int CGitIgnoreItem::FetchIgnoreList(const CString
&projectroot
, const CString
&file
)
861 CAutoWriteLock
lock(&this->m_SharedMutex
);
863 if(this->m_pExcludeList
)
865 free(m_pExcludeList
);
869 this->m_BaseDir
.Empty();
870 if( projectroot
.GetLength() < file
.GetLength())
872 CString base
= file
.Mid(projectroot
.GetLength()+1);
873 base
.Replace(_T('\\'), _T('/'));
874 if(base
!= _T(".git/info/exclude"))
876 int start
=base
.ReverseFind(_T('/'));
879 base
=base
.Left(start
);
880 this->m_BaseDir
= CUnicodeUtils::GetMulti(base
,CP_ACP
) ;
886 if(g_Git
.GetFileModifyTime(file
,&m_LastModifyTime
))
889 if(git_create_exclude_list(&this->m_pExcludeList
))
893 HANDLE hfile
= CreateFile(file
,
895 FILE_SHARE_READ
|FILE_SHARE_DELETE
|FILE_SHARE_WRITE
,
898 FILE_ATTRIBUTE_NORMAL
,
902 if(hfile
== INVALID_HANDLE_VALUE
)
907 DWORD size
=0,filesize
=0;
909 filesize
=GetFileSize(hfile
,NULL
);
911 if(filesize
== INVALID_FILE_SIZE
)
917 BYTE
*buffer
= new BYTE
[filesize
+1];
925 if(! ReadFile( hfile
, buffer
,filesize
,&size
,NULL
) )
928 return GetLastError();
934 for(int i
=0;i
<size
;i
++)
936 if( buffer
[i
] == '\n' || buffer
[i
] =='\r' || i
==(size
-1) )
938 if (buffer
[i
] == '\n' || buffer
[i
] =='\r')
943 if(p
[0] != '#' && p
[0] != 0)
944 git_add_exclude((const char*)p
,
945 this->m_BaseDir
.GetBuffer(),
946 m_BaseDir
.GetLength(),
947 this->m_pExcludeList
);
952 /* Can't free buffer, exluced list will use this buffer*/
959 bool CGitIgnoreList::CheckFileChanged(const CString
&path
)
963 int ret
=g_Git
.GetFileModifyTime(path
, &time
);
965 this->m_SharedMutex
.AcquireShared();
966 bool cacheExist
= (m_Map
.find(path
) != m_Map
.end());
967 this->m_SharedMutex
.ReleaseShared();
969 if (!cacheExist
&& ret
== 0)
971 CAutoWriteLock
lock(&this->m_SharedMutex
);
972 m_Map
[path
].m_LastModifyTime
= 0;
973 m_Map
[path
].m_SharedMutex
.Init();
975 // both cache and file is not exist
976 if( (ret
!= 0) && (!cacheExist
))
979 // file exist but cache miss
980 if( (ret
== 0) && (!cacheExist
))
983 // file not exist but cache exist
984 if( (ret
!= 0) && (cacheExist
))
988 // file exist and cache exist
991 CAutoReadLock
lock(&this->m_SharedMutex
);
992 if( m_Map
[path
].m_LastModifyTime
== time
)
999 bool CGitIgnoreList::CheckIgnoreChanged(const CString
&gitdir
,const CString
&path
)
1006 temp
.Replace(_T('/'), _T('\\'));
1008 while(!temp
.IsEmpty())
1012 if(CGit::GitPathFileExists(temp
))
1014 CString gitignore
=temp
;
1015 gitignore
+= _T("ignore");
1016 if( CheckFileChanged(gitignore
) )
1019 temp
+=_T("\\info\\exclude");
1021 if( CheckFileChanged(temp
) )
1028 if( CheckFileChanged(temp
) )
1034 for( i
=temp
.GetLength() -1;i
>=0;i
--)
1036 if(temp
[i
] == _T('\\'))
1043 temp
= temp
.Left(i
);
1048 int CGitIgnoreList::FetchIgnoreFile(const CString
&gitdir
, const CString
&gitignore
)
1050 if(CGit::GitPathFileExists(gitignore
)) //if .gitignore remove, we need remote cache
1052 CAutoWriteLock
lock(&this->m_SharedMutex
);
1053 if(m_Map
.find(gitignore
) == m_Map
.end())
1054 m_Map
[gitignore
].m_SharedMutex
.Init();
1056 m_Map
[gitignore
].FetchIgnoreList(gitdir
,gitignore
);
1060 CAutoWriteLock
lock(&this->m_SharedMutex
);
1061 if(m_Map
.find(gitignore
) != m_Map
.end())
1062 m_Map
[gitignore
].m_SharedMutex
.Release();
1064 m_Map
.erase(gitignore
);
1069 int CGitIgnoreList::LoadAllIgnoreFile(const CString
&gitdir
,const CString
&path
)
1077 temp
.Replace(_T('/'), _T('\\'));
1079 while(!temp
.IsEmpty())
1083 if(CGit::GitPathFileExists(temp
))
1085 CString gitignore
= temp
;
1086 gitignore
+= _T("ignore");
1087 if( CheckFileChanged(gitignore
) )
1089 FetchIgnoreFile(gitdir
,gitignore
);
1092 temp
+=_T("\\info\\exclude");
1094 if( CheckFileChanged(temp
) )
1096 return FetchIgnoreFile(gitdir
,temp
);
1104 if( CheckFileChanged(temp
) )
1106 FetchIgnoreFile(gitdir
,temp
);
1112 for( i
=temp
.GetLength() -1;i
>=0;i
--)
1114 if(temp
[i
] == _T('\\'))
1121 temp
= temp
.Left(i
);
1125 int CGitIgnoreList::GetIgnoreFileChangeTimeList(const CString
&path
, std::vector
<__int64
> &timelist
)
1128 CString ignore
=temp
;
1132 CAutoReadLock
lock(&this->m_SharedMutex
);
1135 ignore
+=_T("\\.gitignore");
1136 std::map
<CString
, CGitIgnoreItem
>::iterator itMap
;
1137 itMap
= m_Map
.find(ignore
);
1138 if(itMap
== m_Map
.end())
1140 timelist
.push_back(0);
1144 timelist
.push_back(itMap
->second
.m_LastModifyTime
);
1148 ignore
+= _T("\\.git\\info\\exclude");
1150 itMap
= m_Map
.find(ignore
);
1151 if(itMap
== m_Map
.end())
1156 timelist
.push_back(itMap
->second
.m_LastModifyTime
);
1161 ignore
+=_T("\\.git");
1163 if(CGit::GitPathFileExists(ignore
))
1166 start
= temp
.ReverseFind(_T('\\'));
1168 temp
=temp
.Left(start
);
1175 bool CGitIgnoreList::IsIgnore(const CString
&path
,const CString
&projectroot
)
1179 str
.Replace(_T('\\'),_T('/'));
1182 ret
= CheckIgnore(path
, projectroot
);
1185 int start
=str
.ReverseFind(_T('/'));
1189 str
=str
.Left(start
);
1190 ret
= CheckIgnore(str
, projectroot
);
1195 int CGitIgnoreList::CheckIgnore(const CString
&path
,const CString
&projectroot
)
1199 CString temp
=projectroot
+_T("\\")+path
;
1200 temp
.Replace(_T('/'), _T('\\'));
1204 patha
= CUnicodeUtils::GetMulti(path
,CP_ACP
) ;
1205 patha
.Replace('\\','/');
1207 if(g_Git
.GetFileModifyTime(temp
,&time
,&dir
))
1216 while(!temp
.IsEmpty())
1219 x
=temp
.ReverseFind(_T('\\'));
1223 temp
+=_T("\\.gitignore");
1227 patha
.Replace('\\', '/');
1228 int pos
=patha
.ReverseFind('/');
1229 base
= pos
>=0? patha
.GetBuffer()+pos
+1:patha
.GetBuffer();
1231 CAutoReadLock
lock(&this->m_SharedMutex
);
1233 if(this->m_Map
.find(temp
) == m_Map
.end() )
1240 if(m_Map
[temp
].m_pExcludeList
)
1241 ret
= git_check_excluded_1( patha
, patha
.GetLength(), base
, &type
, m_Map
[temp
].m_pExcludeList
);
1249 temp
= temp
.Left(temp
.GetLength()-11);
1250 temp
+=_T("\\.git\\info\\exclude");
1252 if(this->m_Map
.find(temp
) == m_Map
.end() )
1259 if(m_Map
[temp
].m_pExcludeList
)
1260 ret
= git_check_excluded_1( patha
, patha
.GetLength(), base
, &type
, m_Map
[temp
].m_pExcludeList
);
1269 temp
= temp
.Left(temp
.GetLength()-18);
1275 int CGitHeadFileMap::CheckHeadUpdate(const CString
&gitdir
)
1277 SHARED_TREE_PTR ptr
;
1278 ptr
= this->SafeGet(gitdir
);
1282 ptr
->CheckHeadUpdate();
1286 SHARED_TREE_PTR
ptr1(new CGitHeadFileList
);
1287 this->SafeSet(gitdir
, ptr1
);
1292 int CGitHeadFileMap::GetHeadHash(const CString
&gitdir
, CGitHash
&hash
)
1294 SHARED_TREE_PTR ptr
;
1295 ptr
= this->SafeGet(gitdir
);
1297 if(ptr
.get() == NULL
)
1299 SHARED_TREE_PTR
ptr1(new CGitHeadFileList());
1300 if(ptr1
->CheckHeadUpdate())
1301 ptr1
->ReadHeadHash(gitdir
);
1303 hash
= ptr1
->m_Head
;
1305 this->SafeSet(gitdir
, ptr1
);
1309 if(ptr
->CheckHeadUpdate())
1311 SHARED_TREE_PTR
ptr1(new CGitHeadFileList());
1312 if(ptr1
->CheckHeadUpdate())
1313 ptr1
->ReadHeadHash(gitdir
);
1315 hash
= ptr1
->m_Head
;
1316 this->SafeSet(gitdir
, ptr1
);
1325 int CGitStatus::GetStatus(const CString
&gitdir
, const CString
&path
, git_wc_status_kind
*status
, BOOL IsFull
, BOOL IsRecursive
, FIll_STATUS_CALLBACK callback
, void *pData
)
1331 git_wc_status_kind dirstatus
= git_wc_status_none
;
1334 g_Git
.GetFileModifyTime(path
,&time
,&dir
);
1342 result
= _tstat64( gitdir
, &buf
);
1344 result
= _tstat64( gitdir
+_T("\\")+path
, &buf
);
1349 if(buf
.st_mode
& _S_IFDIR
)
1353 if( path
.Right(1) != _T("\\"))
1356 int len
=path
.GetLength();
1358 for(int i
=0;i
<size();i
++)
1360 if( at(i
).m_FileName
.GetLength() > len
)
1362 if(at(i
).m_FileName
.Left(len
) == path
)
1366 *status
= git_wc_status_normal
;
1368 callback(gitdir
+_T("\\")+path
,*status
,pData
);
1373 result
= _tstat64( gitdir
+_T("\\")+at(i
).m_FileName
, &buf
);
1377 *status
= git_wc_status_none
;
1378 GetFileStatus(gitdir
,at(i
).m_FileName
,status
,buf
,callback
,pData
);
1379 if( *status
!= git_wc_status_none
)
1381 if( dirstatus
== git_wc_status_none
)
1383 dirstatus
= git_wc_status_normal
;
1385 if( *status
!= git_wc_status_normal
)
1387 dirstatus
= git_wc_status_modified
;
1396 if( dirstatus
!= git_wc_status_none
)
1398 *status
= dirstatus
;
1402 *status
= git_wc_status_unversioned
;
1405 callback(gitdir
+_T("\\")+path
,*status
,pData
);
1411 GetFileStatus(gitdir
,path
,status
,buf
,callback
,pData
);