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
;
87 BYTE
*buffer
= NULL
, *p
;
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
);
156 this->at(i
).FillData(entry
);
157 p
+= ondisk_ce_size(entry
);
161 std::sort(this->begin(), this->end(), SortIndex
);
162 g_Git
.GetFileModifyTime(IndexFile
, &this->m_LastModifyTime
);
171 UnmapViewOfFile(buffer
);
173 if (hmap
!= INVALID_HANDLE_VALUE
)
176 if (hfile
!= INVALID_HANDLE_VALUE
)
182 int CGitIndexList::GetFileStatus(const CString
&gitdir
,const CString
&pathorg
,git_wc_status_kind
*status
,__int64 time
,FIll_STATUS_CALLBACK callback
,void *pData
, CGitHash
*pHash
)
186 CString path
= pathorg
;
189 int start
= SearchInSortVector(*this, ((CString
&)path
).GetBuffer(), -1);
190 ((CString
&)path
).ReleaseBuffer();
194 *status
= git_wc_status_unversioned
;
204 if (index
>= size() )
207 if (time
== at(index
).m_ModifyTime
)
209 *status
= git_wc_status_normal
;
213 *status
= git_wc_status_modified
;
216 if (at(index
).m_Flags
& CE_STAGEMASK
)
217 *status
= git_wc_status_conflicted
;
218 else if (at(index
).m_Flags
& CE_INTENT_TO_ADD
)
219 *status
= git_wc_status_added
;
222 *pHash
= at(index
).m_IndexHash
;
227 if(callback
&& status
)
228 callback(gitdir
+ _T("\\") + pathorg
, *status
, false, pData
);
232 int CGitIndexList::GetStatus(const CString
&gitdir
,const CString
&pathParam
, git_wc_status_kind
*status
,
233 BOOL IsFull
, BOOL IsRecursive
,
234 FIll_STATUS_CALLBACK callback
,void *pData
,
238 git_wc_status_kind dirstatus
= git_wc_status_none
;
241 CString path
= pathParam
;
246 result
= g_Git
.GetFileModifyTime(gitdir
, &time
, &isDir
);
248 result
= g_Git
.GetFileModifyTime(gitdir
+ _T("\\") + path
, &time
, &isDir
);
252 *status
= git_wc_status_deleted
;
254 callback(gitdir
+ _T("\\") + path
, git_wc_status_deleted
, false, pData
);
262 if (path
.Right(1) != _T("\\"))
265 int len
= path
.GetLength();
267 for (int i
= 0; i
< size(); i
++)
269 if (at(i
).m_FileName
.GetLength() > len
)
271 if (at(i
).m_FileName
.Left(len
) == path
)
275 *status
= git_wc_status_normal
;
277 callback(gitdir
+ _T("\\") + path
, *status
, false, pData
);
283 result
= g_Git
.GetFileModifyTime(gitdir
+_T("\\") + at(i
).m_FileName
, &time
);
287 *status
= git_wc_status_none
;
288 GetFileStatus(gitdir
, at(i
).m_FileName
, status
, time
, callback
, pData
);
289 if (*status
!= git_wc_status_none
)
291 if (dirstatus
== git_wc_status_none
)
293 dirstatus
= git_wc_status_normal
;
295 if (*status
!= git_wc_status_normal
)
297 dirstatus
= git_wc_status_modified
;
306 if (dirstatus
!= git_wc_status_none
)
312 *status
= git_wc_status_unversioned
;
315 callback(gitdir
+ _T("\\") + path
, *status
, false, pData
);
322 GetFileStatus(gitdir
, path
, status
, time
, callback
, pData
, pHash
);
328 int CGitIndexFileMap::Check(const CString
&gitdir
, bool *isChanged
)
334 IndexFile
= gitdir
+ _T("\\.git\\index");
335 /* Get data associated with "crt_stat.c": */
336 result
= g_Git
.GetFileModifyTime(IndexFile
, &time
);
341 SHARED_INDEX_PTR pIndex
;
342 pIndex
= this->SafeGet(gitdir
);
344 if (pIndex
.get() == NULL
)
351 if (pIndex
->m_LastModifyTime
== time
)
364 int CGitIndexFileMap::LoadIndex(const CString
&gitdir
)
368 SHARED_INDEX_PTR
pIndex(new CGitIndexList
);
370 if(pIndex
->ReadIndex(gitdir
+ _T("\\.git\\index")))
373 this->SafeSet(gitdir
, pIndex
);
382 int CGitIndexFileMap::GetFileStatus(const CString
&gitdir
, const CString
&path
, git_wc_status_kind
*status
,BOOL IsFull
, BOOL IsRecursive
,
383 FIll_STATUS_CALLBACK callback
,void *pData
,
385 bool isLoadUpdatedIndex
)
389 CheckAndUpdate(gitdir
, isLoadUpdatedIndex
);
391 SHARED_INDEX_PTR pIndex
= this->SafeGet(gitdir
);
392 if (pIndex
.get() != NULL
)
394 pIndex
->GetStatus(gitdir
, path
, status
, IsFull
, IsRecursive
, callback
, pData
, pHash
);
405 int CGitIndexFileMap::IsUnderVersionControl(const CString
&gitdir
, const CString
&path
, bool isDir
,bool *isVersion
, bool isLoadUpdateIndex
)
415 CString subpath
= path
;
416 subpath
.Replace(_T('\\'), _T('/'));
422 CheckAndUpdate(gitdir
, isLoadUpdateIndex
);
424 SHARED_INDEX_PTR pIndex
= this->SafeGet(gitdir
);
429 *isVersion
= (SearchInSortVector(*pIndex
, subpath
.GetBuffer(), subpath
.GetLength()) >= 0);
431 *isVersion
= (SearchInSortVector(*pIndex
, subpath
.GetBuffer(), -1) >= 0);
441 int CGitHeadFileList::GetPackRef(const CString
&gitdir
)
443 CString PackRef
= gitdir
;
444 PackRef
+= _T("\\.git\\packed-refs");
447 if (g_Git
.GetFileModifyTime(PackRef
, &mtime
))
449 //packed refs is not existed
450 this->m_PackRefFile
.Empty();
451 this->m_PackRefMap
.clear();
455 else if(mtime
== m_LastModifyTimePackRef
)
462 this->m_PackRefFile
= PackRef
;
463 this->m_LastModifyTimePackRef
= mtime
;
468 this->m_PackRefMap
.clear();
470 HANDLE hfile
= CreateFile(PackRef
,
472 FILE_SHARE_READ
|FILE_SHARE_DELETE
|FILE_SHARE_WRITE
,
475 FILE_ATTRIBUTE_NORMAL
,
479 if(hfile
== INVALID_HANDLE_VALUE
)
485 DWORD filesize
= GetFileSize(hfile
, NULL
);
488 buff
= new char[filesize
];
490 ReadFile(hfile
, buff
, filesize
, &size
, NULL
);
492 if (size
!= filesize
)
501 for(DWORD i
=0;i
<filesize
;)
505 if (buff
[i
] == '#' || buff
[i
] == '^')
507 while (buff
[i
] != '\n')
519 while (buff
[i
] != ' ')
521 hash
.AppendChar(buff
[i
]);
531 while (buff
[i
] != '\n')
533 ref
.AppendChar(buff
[i
]);
541 this->m_PackRefMap
[ref
] = hash
;
544 while (buff
[i
] == '\n')
556 if(hfile
!= INVALID_HANDLE_VALUE
)
562 int CGitHeadFileList::ReadHeadHash(CString gitdir
)
564 CString HeadFile
= gitdir
;
565 HeadFile
+= _T("\\.git\\HEAD");
568 HANDLE hfile
=INVALID_HANDLE_VALUE
;
569 HANDLE href
= INVALID_HANDLE_VALUE
;
574 m_HeadFile
= HeadFile
;
576 if( g_Git
.GetFileModifyTime(m_HeadFile
, &m_LastModifyTimeHead
))
583 hfile
= CreateFile(HeadFile
,
585 FILE_SHARE_READ
|FILE_SHARE_DELETE
|FILE_SHARE_WRITE
,
588 FILE_ATTRIBUTE_NORMAL
,
591 if(hfile
== INVALID_HANDLE_VALUE
)
597 DWORD size
= 0,filesize
= 0;
598 unsigned char buffer
[40] ;
599 ReadFile(hfile
, buffer
, 4, &size
, NULL
);
606 if (strcmp((const char*)buffer
,"ref:") == 0)
608 filesize
= GetFileSize(hfile
, NULL
);
610 unsigned char *p
= (unsigned char*)malloc(filesize
-4);
612 ReadFile(hfile
, p
, filesize
- 4, &size
, NULL
);
614 m_HeadRefFile
.Empty();
615 g_Git
.StringAppend(&this->m_HeadRefFile
, p
, CP_ACP
, filesize
- 4);
616 CString ref
= this->m_HeadRefFile
;
619 ref
= ref
.Tokenize(_T("\n"), start
);
621 m_HeadRefFile
=gitdir
+_T("\\.git\\") + m_HeadRefFile
.Trim();
622 m_HeadRefFile
.Replace(_T('/'),_T('\\'));
625 if (g_Git
.GetFileModifyTime(m_HeadRefFile
, &time
, NULL
))
627 m_HeadRefFile
.Empty();
628 if (GetPackRef(gitdir
))
633 if (this->m_PackRefMap
.find(ref
) == m_PackRefMap
.end())
638 this ->m_Head
= m_PackRefMap
[ref
];
643 href
= CreateFile(m_HeadRefFile
,
645 FILE_SHARE_READ
|FILE_SHARE_DELETE
|FILE_SHARE_WRITE
,
648 FILE_ATTRIBUTE_NORMAL
,
651 if (href
== INVALID_HANDLE_VALUE
)
653 m_HeadRefFile
.Empty();
655 if (GetPackRef(gitdir
))
661 if (this->m_PackRefMap
.find(ref
) == m_PackRefMap
.end())
666 this ->m_Head
= m_PackRefMap
[ref
];
670 ReadFile(href
, buffer
, 40, &size
, NULL
);
676 this->m_Head
.ConvertFromStrA((char*)buffer
);
678 this->m_LastModifyTimeRef
= time
;
683 ReadFile(hfile
, buffer
+ 4, 40 - 4, &size
, NULL
);
689 m_HeadRefFile
.Empty();
691 this->m_Head
.ConvertFromStrA((char*)buffer
);
700 if (hfile
!= INVALID_HANDLE_VALUE
)
702 if (href
!= INVALID_HANDLE_VALUE
)
708 bool CGitHeadFileList::CheckHeadUpdate()
710 if (this->m_HeadFile
.IsEmpty())
715 if (g_Git
.GetFileModifyTime(m_HeadFile
, &mtime
))
718 if (mtime
!= this->m_LastModifyTimeHead
)
721 if (!this->m_HeadRefFile
.IsEmpty())
723 if (g_Git
.GetFileModifyTime(m_HeadRefFile
, &mtime
))
726 if (mtime
!= this->m_LastModifyTimeRef
)
730 if(!this->m_PackRefFile
.IsEmpty())
732 if (g_Git
.GetFileModifyTime(m_PackRefFile
, &mtime
))
735 if (mtime
!= this->m_LastModifyTimePackRef
)
741 int CGitHeadFileList::ReadTree()
744 if (this->m_Head
.IsEmpty())
749 CAutoLocker
lock(g_Git
.m_critGitDllSec
);
750 CAutoWriteLock
lock1(&this->m_SharedMutex
);
752 if (m_Gitdir
!= g_Git
.m_CurrentDir
)
754 g_Git
.SetCurrentDir(m_Gitdir
);
755 SetCurrentDirectory(g_Git
.m_CurrentDir
);
762 ret
= git_read_tree(this->m_Head
.m_hash
, CGitHeadFileList::CallBack
, this);
774 int CGitHeadFileList::CallBack(const unsigned char *sha1
, const char *base
, int baselen
,
775 const char *pathname
, unsigned mode
, int /*stage*/, void *context
)
777 #define S_IFGITLINK 0160000
779 CGitHeadFileList
*p
= (CGitHeadFileList
*)context
;
782 if( (mode
&S_IFMT
) != S_IFGITLINK
)
783 return READ_TREE_RECURSIVE
;
786 unsigned int cur
= p
->size();
787 p
->resize(p
->size() + 1);
788 p
->at(cur
).m_Hash
= (char*)sha1
;
789 p
->at(cur
).m_FileName
.Empty();
792 g_Git
.StringAppend(&p
->at(cur
).m_FileName
, (BYTE
*)base
, CP_ACP
, baselen
);
794 g_Git
.StringAppend(&p
->at(cur
).m_FileName
,(BYTE
*)pathname
, CP_ACP
);
796 p
->at(cur
).m_FileName
.MakeLower();
798 //p->at(cur).m_FileName.Replace(_T('/'), _T('\\'));
800 //p->m_Map[p->at(cur).m_FileName] = cur;
802 if( (mode
&S_IFMT
) == S_IFGITLINK
)
805 return READ_TREE_RECURSIVE
;
808 int ReadTreeRecursive(git_repository
&repo
, git_tree
* tree
, CStringA base
, int (*CallBack
) (const unsigned char *, const char *, int, const char *, unsigned int, int, void *),void *data
)
810 size_t count
= git_tree_entrycount(tree
);
811 for (int i
= 0; i
< count
; i
++)
813 const git_tree_entry
*entry
= git_tree_entry_byindex(tree
, i
);
816 int mode
= git_tree_entry_attributes(entry
);
817 if( CallBack(git_tree_entry_id(entry
)->id
,
820 git_tree_entry_name(entry
),
823 data
) == READ_TREE_RECURSIVE
828 git_object
*object
= NULL
;
829 git_tree_entry_2object(&object
, &repo
, entry
);
832 CStringA parent
= base
;
833 parent
+= git_tree_entry_name(entry
);
835 ReadTreeRecursive(repo
, (git_tree
*)object
, parent
, CallBack
, data
);
844 int CGitHeadFileList::ReadTree()
846 CStringA gitdir
= CUnicodeUtils::GetMulti(m_Gitdir
,CP_ACP
) ;
848 git_repository
*repository
= NULL
;
849 git_commit
*commit
= NULL
;
850 git_tree
* tree
= NULL
;
854 ret
= git_repository_open(&repository
, gitdir
.GetBuffer());
857 ret
= git_commit_lookup(&commit
, repository
, (const git_oid
*)m_Head
.m_hash
);
861 ret
= git_commit_tree(&tree
, commit
);
865 ret
= ReadTreeRecursive(*repository
, tree
,"", CGitHeadFileList::CallBack
,this);
869 std::sort(this->begin(), this->end(), SortTree
);
870 this->m_TreeHash
= (char*)(git_commit_id(commit
)->id
);
875 git_repository_free(repository
);
880 int CGitIgnoreItem::FetchIgnoreList(const CString
&projectroot
, const CString
&file
)
882 CAutoWriteLock
lock(&this->m_SharedMutex
);
884 if (this->m_pExcludeList
)
886 free(m_pExcludeList
);
890 this->m_BaseDir
.Empty();
891 if (projectroot
.GetLength() < file
.GetLength())
893 CString base
= file
.Mid(projectroot
.GetLength() + 1);
894 base
.Replace(_T('\\'), _T('/'));
895 if (base
!= _T(".git/info/exclude"))
897 int start
= base
.ReverseFind(_T('/'));
900 base
= base
.Left(start
);
901 this->m_BaseDir
= CUnicodeUtils::GetMulti(base
,CP_ACP
) ;
907 if(g_Git
.GetFileModifyTime(file
, &m_LastModifyTime
))
910 if(git_create_exclude_list(&this->m_pExcludeList
))
914 HANDLE hfile
= CreateFile(file
,
916 FILE_SHARE_READ
|FILE_SHARE_DELETE
|FILE_SHARE_WRITE
,
919 FILE_ATTRIBUTE_NORMAL
,
923 if(hfile
== INVALID_HANDLE_VALUE
)
928 DWORD size
=0,filesize
=0;
930 filesize
=GetFileSize(hfile
, NULL
);
932 if(filesize
== INVALID_FILE_SIZE
)
938 BYTE
*buffer
= new BYTE
[filesize
+ 1];
946 if(! ReadFile(hfile
, buffer
,filesize
,&size
,NULL
))
949 return GetLastError();
955 for (int i
= 0; i
< size
; i
++)
957 if (buffer
[i
] == '\n' || buffer
[i
] == '\r' || i
== (size
- 1))
959 if (buffer
[i
] == '\n' || buffer
[i
] == '\r')
964 if(p
[0] != '#' && p
[0] != 0)
965 git_add_exclude((const char*)p
,
966 this->m_BaseDir
.GetBuffer(),
967 m_BaseDir
.GetLength(),
968 this->m_pExcludeList
);
973 /* Can't free buffer, exluced list will use this buffer*/
980 bool CGitIgnoreList::CheckFileChanged(const CString
&path
)
984 int ret
= g_Git
.GetFileModifyTime(path
, &time
);
986 this->m_SharedMutex
.AcquireShared();
987 bool cacheExist
= (m_Map
.find(path
) != m_Map
.end());
988 this->m_SharedMutex
.ReleaseShared();
990 if (!cacheExist
&& ret
== 0)
992 CAutoWriteLock
lock(&this->m_SharedMutex
);
993 m_Map
[path
].m_LastModifyTime
= 0;
994 m_Map
[path
].m_SharedMutex
.Init();
996 // both cache and file is not exist
997 if ((ret
!= 0) && (!cacheExist
))
1000 // file exist but cache miss
1001 if ((ret
== 0) && (!cacheExist
))
1004 // file not exist but cache exist
1005 if ((ret
!= 0) && (cacheExist
))
1009 // file exist and cache exist
1012 CAutoReadLock
lock(&this->m_SharedMutex
);
1013 if (m_Map
[path
].m_LastModifyTime
== time
)
1019 bool CGitIgnoreList::CheckIgnoreChanged(const CString
&gitdir
,const CString
&path
)
1026 temp
.Replace(_T('/'), _T('\\'));
1028 while(!temp
.IsEmpty())
1030 temp
+= _T("\\.git");
1032 if (CGit::GitPathFileExists(temp
))
1034 CString gitignore
=temp
;
1035 gitignore
+= _T("ignore");
1036 if (CheckFileChanged(gitignore
))
1039 temp
+= _T("\\info\\exclude");
1041 if (CheckFileChanged(temp
))
1048 temp
+= _T("ignore");
1049 if (CheckFileChanged(temp
))
1055 for (i
= temp
.GetLength() - 1; i
>= 0; i
--)
1057 if(temp
[i
] == _T('\\'))
1064 temp
= temp
.Left(i
);
1069 int CGitIgnoreList::FetchIgnoreFile(const CString
&gitdir
, const CString
&gitignore
)
1071 if (CGit::GitPathFileExists(gitignore
)) //if .gitignore remove, we need remote cache
1073 CAutoWriteLock
lock(&this->m_SharedMutex
);
1074 if (m_Map
.find(gitignore
) == m_Map
.end())
1075 m_Map
[gitignore
].m_SharedMutex
.Init();
1077 m_Map
[gitignore
].FetchIgnoreList(gitdir
,gitignore
);
1081 CAutoWriteLock
lock(&this->m_SharedMutex
);
1082 if (m_Map
.find(gitignore
) != m_Map
.end())
1083 m_Map
[gitignore
].m_SharedMutex
.Release();
1085 m_Map
.erase(gitignore
);
1090 int CGitIgnoreList::LoadAllIgnoreFile(const CString
&gitdir
,const CString
&path
)
1098 temp
.Replace(_T('/'), _T('\\'));
1100 while (!temp
.IsEmpty())
1102 temp
+= _T("\\.git");
1104 if (CGit::GitPathFileExists(temp
))
1106 CString gitignore
= temp
;
1107 gitignore
+= _T("ignore");
1108 if (CheckFileChanged(gitignore
))
1110 FetchIgnoreFile(gitdir
, gitignore
);
1113 temp
+= _T("\\info\\exclude");
1115 if (CheckFileChanged(temp
))
1117 return FetchIgnoreFile(gitdir
, temp
);
1124 temp
+= _T("ignore");
1125 if (CheckFileChanged(temp
))
1127 FetchIgnoreFile(gitdir
, temp
);
1133 for (i
= temp
.GetLength() - 1; i
>= 0; i
--)
1135 if(temp
[i
] == _T('\\'))
1142 temp
= temp
.Left(i
);
1146 int CGitIgnoreList::GetIgnoreFileChangeTimeList(const CString
&path
, std::vector
<__int64
> &timelist
)
1148 CString temp
= path
;
1149 CString ignore
= temp
;
1153 CAutoReadLock
lock(&this->m_SharedMutex
);
1156 ignore
+= _T("\\.gitignore");
1157 std::map
<CString
, CGitIgnoreItem
>::iterator itMap
;
1158 itMap
= m_Map
.find(ignore
);
1159 if (itMap
== m_Map
.end())
1161 timelist
.push_back(0);
1165 timelist
.push_back(itMap
->second
.m_LastModifyTime
);
1169 ignore
+= _T("\\.git\\info\\exclude");
1171 itMap
= m_Map
.find(ignore
);
1172 if (itMap
== m_Map
.end())
1178 timelist
.push_back(itMap
->second
.m_LastModifyTime
);
1183 ignore
+= _T("\\.git");
1185 if (CGit::GitPathFileExists(ignore
))
1188 start
= temp
.ReverseFind(_T('\\'));
1190 temp
=temp
.Left(start
);
1197 bool CGitIgnoreList::IsIgnore(const CString
&path
,const CString
&projectroot
)
1201 str
.Replace(_T('\\'),_T('/'));
1203 if (str
.GetLength()>0)
1204 if (str
[str
.GetLength()-1] == _T('/'))
1205 str
= str
.Left(str
.GetLength() - 1);
1208 ret
= CheckIgnore(str
, projectroot
);
1211 int start
= str
.ReverseFind(_T('/'));
1215 str
= str
.Left(start
);
1216 ret
= CheckIgnore(str
, projectroot
);
1221 int CGitIgnoreList::CheckIgnore(const CString
&path
,const CString
&projectroot
)
1225 CString temp
= projectroot
+ _T("\\") + path
;
1226 temp
.Replace(_T('/'), _T('\\'));
1230 patha
= CUnicodeUtils::GetMulti(path
, CP_ACP
) ;
1231 patha
.Replace('\\', '/');
1233 if(g_Git
.GetFileModifyTime(temp
, &time
, &dir
))
1242 while (!temp
.IsEmpty())
1245 x
= temp
.ReverseFind(_T('\\'));
1250 temp
+= _T("\\.gitignore");
1254 patha
.Replace('\\', '/');
1255 int pos
= patha
.ReverseFind('/');
1256 base
= pos
>= 0 ? patha
.GetBuffer() + pos
+ 1 : patha
.GetBuffer();
1258 CAutoReadLock
lock(&this->m_SharedMutex
);
1260 if(this->m_Map
.find(temp
) != m_Map
.end())
1264 if(m_Map
[temp
].m_pExcludeList
)
1265 ret
= git_check_excluded_1( patha
, patha
.GetLength(), base
, &type
, m_Map
[temp
].m_pExcludeList
);
1273 temp
= temp
.Left(temp
.GetLength()-11);
1274 temp
+=_T("\\.git\\info\\exclude");
1276 if(this->m_Map
.find(temp
) != m_Map
.end())
1280 if(m_Map
[temp
].m_pExcludeList
)
1281 ret
= git_check_excluded_1(patha
, patha
.GetLength(), base
, &type
, m_Map
[temp
].m_pExcludeList
);
1290 temp
= temp
.Left(temp
.GetLength() - 18);
1296 bool CGitHeadFileMap::CheckHeadUpdate(const CString
&gitdir
)
1298 SHARED_TREE_PTR ptr
;
1299 ptr
= this->SafeGet(gitdir
);
1303 return ptr
->CheckHeadUpdate();
1307 SHARED_TREE_PTR
ptr1(new CGitHeadFileList
);
1308 if(ptr1
->CheckHeadUpdate())
1309 ptr1
->ReadHeadHash(gitdir
);
1311 this->SafeSet(gitdir
, ptr1
);
1317 int CGitHeadFileMap::GetHeadHash(const CString
&gitdir
, CGitHash
&hash
)
1319 SHARED_TREE_PTR ptr
;
1320 ptr
= this->SafeGet(gitdir
);
1322 if(ptr
.get() == NULL
)
1324 SHARED_TREE_PTR
ptr1(new CGitHeadFileList());
1325 if(ptr1
->CheckHeadUpdate())
1326 ptr1
->ReadHeadHash(gitdir
);
1328 hash
= ptr1
->m_Head
;
1330 this->SafeSet(gitdir
, ptr1
);
1335 if(ptr
->CheckHeadUpdate())
1337 SHARED_TREE_PTR
ptr1(new CGitHeadFileList());
1338 if(ptr1
->CheckHeadUpdate())
1339 ptr1
->ReadHeadHash(gitdir
);
1341 hash
= ptr1
->m_Head
;
1342 this->SafeSet(gitdir
, ptr1
);
1351 int CGitStatus::GetStatus(const CString
&gitdir
, const CString
&path
, git_wc_status_kind
*status
, BOOL IsFull
, BOOL IsRecursive
, FIll_STATUS_CALLBACK callback
, void *pData
)
1357 git_wc_status_kind dirstatus
= git_wc_status_none
;
1360 g_Git
.GetFileModifyTime(path
, &time
, &dir
);
1362 result
= _tstat64( gitdir
, &buf
);
1364 result
= _tstat64( gitdir
+_T("\\")+path
, &buf
);
1369 if(buf
.st_mode
& _S_IFDIR
)
1373 if( path
.Right(1) != _T("\\"))
1376 int len
= path
.GetLength();
1378 for (int i
= 0; i
< size(); i
++)
1380 if (at(i
).m_FileName
.GetLength() > len
)
1382 if (at(i
).m_FileName
.Left(len
) == path
)
1386 *status
= git_wc_status_normal
;
1388 callback(gitdir
+ _T("\\") + path
, *status
, pData
);
1394 result
= _tstat64(gitdir
+ _T("\\") + at(i
).m_FileName
, &buf
);
1398 *status
= git_wc_status_none
;
1399 GetFileStatus(gitdir
, at(i
).m_FileName
, status
, buf
, callback
, pData
);
1400 if (*status
!= git_wc_status_none
)
1402 if (dirstatus
== git_wc_status_none
)
1404 dirstatus
= git_wc_status_normal
;
1406 if (*status
!= git_wc_status_normal
)
1408 dirstatus
= git_wc_status_modified
;
1417 if (dirstatus
!= git_wc_status_none
)
1419 *status
= dirstatus
;
1423 *status
= git_wc_status_unversioned
;
1426 callback(gitdir
+ _T("\\") + path
, *status
, pData
);
1433 GetFileStatus(gitdir
, path
, status
, buf
, callback
, pData
);