allow to detect active bisect session
[TortoiseGit.git] / src / Git / TGitPath.cpp
blobdf07b5c5223209a0406df1a74f2f1eaf6306315e
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2011 - TortoiseGit
4 // Copyright (C) 2010-2011 Sven Strickroth <email@cs-ware.de>
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "StdAfx.h"
21 #include "TGitPath.h"
22 #include "UnicodeUtils.h"
23 #include "GitAdminDir.h"
24 #include "PathUtils.h"
25 #include <regex>
26 #include "git.h"
27 #include "Globals.h"
29 #if defined(_MFC_VER)
30 //#include "MessageBox.h"
31 //#include "AppUtils.h"
32 #endif
34 #ifndef ASSERT
35 #define ASSERT()
36 #endif
37 using namespace std;
38 extern CGit g_Git;
40 CTGitPath::CTGitPath(void)
41 : m_bDirectoryKnown(false)
42 , m_bIsDirectory(false)
43 , m_bIsURL(false)
44 , m_bURLKnown(false)
45 , m_bHasAdminDirKnown(false)
46 , m_bHasAdminDir(false)
47 , m_bIsValidOnWindowsKnown(false)
48 , m_bIsValidOnWindows(false)
49 , m_bIsReadOnly(false)
50 , m_bIsAdminDirKnown(false)
51 , m_bIsAdminDir(false)
52 , m_bExists(false)
53 , m_bExistsKnown(false)
54 , m_bLastWriteTimeKnown(0)
55 , m_lastWriteTime(0)
56 , m_customData(NULL)
57 , m_bIsSpecialDirectoryKnown(false)
58 , m_bIsSpecialDirectory(false)
59 , m_bIsWCRootKnown(false)
60 , m_bIsWCRoot(false)
62 m_Action=0;
63 m_ParentNo=0;
66 CTGitPath::~CTGitPath(void)
69 // Create a TGitPath object from an unknown path type (same as using SetFromUnknown)
70 CTGitPath::CTGitPath(const CString& sUnknownPath) :
71 m_bDirectoryKnown(false)
72 , m_bIsDirectory(false)
73 , m_bIsURL(false)
74 , m_bURLKnown(false)
75 , m_bHasAdminDirKnown(false)
76 , m_bHasAdminDir(false)
77 , m_bIsValidOnWindowsKnown(false)
78 , m_bIsValidOnWindows(false)
79 , m_bIsReadOnly(false)
80 , m_bIsAdminDirKnown(false)
81 , m_bIsAdminDir(false)
82 , m_bExists(false)
83 , m_bExistsKnown(false)
84 , m_bLastWriteTimeKnown(0)
85 , m_lastWriteTime(0)
86 , m_customData(NULL)
87 , m_bIsSpecialDirectoryKnown(false)
88 , m_bIsSpecialDirectory(false)
89 , m_bIsWCRootKnown(false)
90 , m_bIsWCRoot(false)
92 SetFromUnknown(sUnknownPath);
93 m_Action=0;
94 m_Stage=0;
95 m_ParentNo=0;
98 int CTGitPath::ParserAction(BYTE action)
100 //action=action.TrimLeft();
101 //TCHAR c=action.GetAt(0);
102 if(action == 'M')
103 m_Action|= LOGACTIONS_MODIFIED;
104 if(action == 'R')
105 m_Action|= LOGACTIONS_REPLACED;
106 if(action == 'A')
107 m_Action|= LOGACTIONS_ADDED;
108 if(action == 'D')
109 m_Action|= LOGACTIONS_DELETED;
110 if(action == 'U')
111 m_Action|= LOGACTIONS_UNMERGED;
112 if(action == 'K')
113 m_Action|= LOGACTIONS_DELETED;
114 if(action == 'H')
115 m_Action|= LOGACTIONS_CACHE;
116 if(action == 'C' )
117 m_Action|= LOGACTIONS_COPY;
119 return m_Action;
121 void CTGitPath::SetFromGit(const char* pPath)
123 Reset();
124 if (pPath == NULL)
125 return;
126 int len = MultiByteToWideChar(CP_UTF8, 0, pPath, -1, NULL, 0);
127 if (len)
129 len = MultiByteToWideChar(CP_UTF8, 0, pPath, -1, m_sFwdslashPath.GetBuffer(len+1), len+1);
130 m_sFwdslashPath.ReleaseBuffer(len-1);
132 SanitizeRootPath(m_sFwdslashPath, true);
135 void CTGitPath::SetFromGit(const char* pPath, bool bIsDirectory)
137 SetFromGit(pPath);
138 m_bDirectoryKnown = true;
139 m_bIsDirectory = bIsDirectory;
142 void CTGitPath::SetFromGit(const TCHAR* pPath, bool bIsDirectory)
144 Reset();
145 if (pPath)
147 m_sFwdslashPath = pPath;
148 SanitizeRootPath(m_sFwdslashPath, true);
150 m_bDirectoryKnown = true;
151 m_bIsDirectory = bIsDirectory;
154 void CTGitPath::SetFromGit(const CString& sPath,CString *oldpath)
156 Reset();
157 m_sFwdslashPath = sPath;
158 SanitizeRootPath(m_sFwdslashPath, true);
159 if(oldpath)
160 m_sOldFwdslashPath = *oldpath;
163 void CTGitPath::SetFromWin(LPCTSTR pPath)
165 Reset();
166 m_sBackslashPath = pPath;
167 SanitizeRootPath(m_sBackslashPath, false);
168 ATLASSERT(m_sBackslashPath.Find('/')<0);
170 void CTGitPath::SetFromWin(const CString& sPath)
172 Reset();
173 m_sBackslashPath = sPath;
174 SanitizeRootPath(m_sBackslashPath, false);
176 void CTGitPath::SetFromWin(const CString& sPath, bool bIsDirectory)
178 Reset();
179 m_sBackslashPath = sPath;
180 m_bIsDirectory = bIsDirectory;
181 m_bDirectoryKnown = true;
182 SanitizeRootPath(m_sBackslashPath, false);
184 void CTGitPath::SetFromUnknown(const CString& sPath)
186 Reset();
187 // Just set whichever path we think is most likely to be used
188 // GitAdminDir admin;
189 // CString p;
190 // if(admin.HasAdminDir(sPath,&p))
191 // SetFwdslashPath(sPath.Right(sPath.GetLength()-p.GetLength()));
192 // else
193 SetFwdslashPath(sPath);
196 LPCTSTR CTGitPath::GetWinPath() const
198 if(IsEmpty())
200 return _T("");
202 if(m_sBackslashPath.IsEmpty())
204 SetBackslashPath(m_sFwdslashPath);
206 return m_sBackslashPath;
208 // This is a temporary function, to be used during the migration to
209 // the path class. Ultimately, functions consuming paths should take a CTGitPath&, not a CString
210 const CString& CTGitPath::GetWinPathString() const
212 if(m_sBackslashPath.IsEmpty())
214 SetBackslashPath(m_sFwdslashPath);
216 return m_sBackslashPath;
219 const CString& CTGitPath::GetGitPathString() const
221 if(m_sFwdslashPath.IsEmpty())
223 SetFwdslashPath(m_sBackslashPath);
225 return m_sFwdslashPath;
228 const CString &CTGitPath::GetGitOldPathString() const
230 return m_sOldFwdslashPath;
232 #if 0
233 const char* CTGitPath::GetGitApiPath(apr_pool_t *pool) const
235 // This funny-looking 'if' is to avoid a subtle problem with empty paths, whereby
236 // each call to GetGitApiPath returns a different pointer value.
237 // If you made multiple calls to GetGitApiPath on the same string, only the last
238 // one would give you a valid pointer to an empty string, because each
239 // call would invalidate the previous call's return.
240 if(IsEmpty())
242 return "";
244 if(m_sFwdslashPath.IsEmpty())
246 SetFwdslashPath(m_sBackslashPath);
248 if(m_sUTF8FwdslashPath.IsEmpty())
250 SetUTF8FwdslashPath(m_sFwdslashPath);
252 if (svn_path_is_url(m_sUTF8FwdslashPath))
254 m_sUTF8FwdslashPathEscaped = CPathUtils::PathEscape(m_sUTF8FwdslashPath);
255 m_sUTF8FwdslashPathEscaped.Replace("file:////", "file:///\\");
256 m_sUTF8FwdslashPathEscaped = svn_path_canonicalize(m_sUTF8FwdslashPathEscaped, pool);
257 return m_sUTF8FwdslashPathEscaped;
259 m_sUTF8FwdslashPath = svn_path_canonicalize(m_sUTF8FwdslashPath, pool);
261 return m_sUTF8FwdslashPath;
263 #endif
265 const CString& CTGitPath::GetUIPathString() const
267 if (m_sUIPath.IsEmpty())
269 #if defined(_MFC_VER)
270 //BUGBUG HORRIBLE!!! - CPathUtils::IsEscaped doesn't need to be MFC-only
271 if (IsUrl())
273 m_sUIPath = CPathUtils::PathUnescape(GetGitPathString());
274 m_sUIPath.Replace(_T("file:////"), _T("file:///\\"));
277 else
278 #endif
280 m_sUIPath = GetWinPathString();
283 return m_sUIPath;
286 void CTGitPath::SetFwdslashPath(const CString& sPath) const
288 m_sFwdslashPath = sPath;
289 m_sFwdslashPath.Replace('\\', '/');
291 // We don't leave a trailing /
292 m_sFwdslashPath.TrimRight('/');
294 SanitizeRootPath(m_sFwdslashPath, true);
296 m_sFwdslashPath.Replace(_T("file:////"), _T("file:///\\"));
298 m_sUTF8FwdslashPath.Empty();
301 void CTGitPath::SetBackslashPath(const CString& sPath) const
303 m_sBackslashPath = sPath;
304 m_sBackslashPath.Replace('/', '\\');
305 m_sBackslashPath.TrimRight('\\');
306 SanitizeRootPath(m_sBackslashPath, false);
309 void CTGitPath::SetUTF8FwdslashPath(const CString& sPath) const
311 m_sUTF8FwdslashPath = CUnicodeUtils::GetUTF8(sPath);
314 void CTGitPath::SanitizeRootPath(CString& sPath, bool bIsForwardPath) const
316 // Make sure to add the trailing slash to root paths such as 'C:'
317 if (sPath.GetLength() == 2 && sPath[1] == ':')
319 sPath += (bIsForwardPath) ? _T("/") : _T("\\");
323 bool CTGitPath::IsUrl() const
325 #if 0
326 if (!m_bURLKnown)
328 EnsureFwdslashPathSet();
329 if(m_sUTF8FwdslashPath.IsEmpty())
331 SetUTF8FwdslashPath(m_sFwdslashPath);
333 m_bIsURL = !!svn_path_is_url(m_sUTF8FwdslashPath);
334 m_bURLKnown = true;
336 return m_bIsURL;
337 #endif
338 return false;
341 bool CTGitPath::IsDirectory() const
343 if(!m_bDirectoryKnown)
345 UpdateAttributes();
347 return m_bIsDirectory;
350 bool CTGitPath::Exists() const
352 if (!m_bExistsKnown)
354 UpdateAttributes();
356 return m_bExists;
359 bool CTGitPath::Delete(bool bTrash) const
361 EnsureBackslashPathSet();
362 ::SetFileAttributes(m_sBackslashPath, FILE_ATTRIBUTE_NORMAL);
363 bool bRet = false;
364 if (Exists())
366 if ((bTrash)||(IsDirectory()))
368 TCHAR * buf = new TCHAR[m_sBackslashPath.GetLength()+2];
369 _tcscpy_s(buf, m_sBackslashPath.GetLength()+2, m_sBackslashPath);
370 buf[m_sBackslashPath.GetLength()] = 0;
371 buf[m_sBackslashPath.GetLength()+1] = 0;
372 SHFILEOPSTRUCT shop = {0};
373 shop.wFunc = FO_DELETE;
374 shop.pFrom = buf;
375 shop.fFlags = FOF_NOCONFIRMATION|FOF_NOERRORUI|FOF_SILENT;
376 if (bTrash)
377 shop.fFlags |= FOF_ALLOWUNDO;
378 bRet = (SHFileOperation(&shop) == 0);
379 delete [] buf;
381 else
383 bRet = !!::DeleteFile(m_sBackslashPath);
386 m_bExists = false;
387 m_bExistsKnown = true;
388 return bRet;
391 __int64 CTGitPath::GetLastWriteTime() const
393 if(!m_bLastWriteTimeKnown)
395 UpdateAttributes();
397 return m_lastWriteTime;
400 bool CTGitPath::IsReadOnly() const
402 if(!m_bLastWriteTimeKnown)
404 UpdateAttributes();
406 return m_bIsReadOnly;
409 void CTGitPath::UpdateAttributes() const
411 EnsureBackslashPathSet();
412 WIN32_FILE_ATTRIBUTE_DATA attribs;
413 if(GetFileAttributesEx(m_sBackslashPath, GetFileExInfoStandard, &attribs))
415 m_bIsDirectory = !!(attribs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
416 m_lastWriteTime = *(__int64*)&attribs.ftLastWriteTime;
417 m_bIsReadOnly = !!(attribs.dwFileAttributes & FILE_ATTRIBUTE_READONLY);
418 m_bExists = true;
420 else
422 DWORD err = GetLastError();
423 if ((err == ERROR_FILE_NOT_FOUND)||(err == ERROR_PATH_NOT_FOUND)||(err == ERROR_INVALID_NAME))
425 m_bIsDirectory = false;
426 m_lastWriteTime = 0;
427 m_bExists = false;
429 else
431 m_bIsDirectory = false;
432 m_lastWriteTime = 0;
433 m_bExists = true;
434 return;
437 m_bDirectoryKnown = true;
438 m_bLastWriteTimeKnown = true;
439 m_bExistsKnown = true;
442 CTGitPath CTGitPath::GetSubPath(const CTGitPath &root)
444 CTGitPath path;
446 if(GetWinPathString().Left(root.GetWinPathString().GetLength()) == root.GetWinPathString())
448 CString str=GetWinPathString();
449 path.SetFromWin(str.Right(str.GetLength()-root.GetWinPathString().GetLength()-1));
451 return path;
454 void CTGitPath::EnsureBackslashPathSet() const
456 if(m_sBackslashPath.IsEmpty())
458 SetBackslashPath(m_sFwdslashPath);
459 ATLASSERT(IsEmpty() || !m_sBackslashPath.IsEmpty());
462 void CTGitPath::EnsureFwdslashPathSet() const
464 if(m_sFwdslashPath.IsEmpty())
466 SetFwdslashPath(m_sBackslashPath);
467 ATLASSERT(IsEmpty() || !m_sFwdslashPath.IsEmpty());
472 // Reset all the caches
473 void CTGitPath::Reset()
475 m_bDirectoryKnown = false;
476 m_bURLKnown = false;
477 m_bLastWriteTimeKnown = false;
478 m_bHasAdminDirKnown = false;
479 m_bIsValidOnWindowsKnown = false;
480 m_bIsAdminDirKnown = false;
481 m_bExistsKnown = false;
482 m_bIsSpecialDirectoryKnown = false;
483 m_bIsSpecialDirectory = false;
485 m_sBackslashPath.Empty();
486 m_sFwdslashPath.Empty();
487 m_sUTF8FwdslashPath.Empty();
488 this->m_Action=0;
489 this->m_StatAdd=_T("");
490 this->m_StatDel=_T("");
491 m_ParentNo=0;
492 ATLASSERT(IsEmpty());
495 CTGitPath CTGitPath::GetDirectory() const
497 if ((IsDirectory())||(!Exists()))
499 return *this;
501 return GetContainingDirectory();
504 CTGitPath CTGitPath::GetContainingDirectory() const
506 EnsureBackslashPathSet();
508 CString sDirName = m_sBackslashPath.Left(m_sBackslashPath.ReverseFind('\\'));
509 if(sDirName.GetLength() == 2 && sDirName[1] == ':')
511 // This is a root directory, which needs a trailing slash
512 sDirName += '\\';
513 if(sDirName == m_sBackslashPath)
515 // We were clearly provided with a root path to start with - we should return nothing now
516 sDirName.Empty();
519 if(sDirName.GetLength() == 1 && sDirName[0] == '\\')
521 // We have an UNC path and we already are the root
522 sDirName.Empty();
524 CTGitPath retVal;
525 retVal.SetFromWin(sDirName);
526 return retVal;
529 CString CTGitPath::GetRootPathString() const
531 EnsureBackslashPathSet();
532 CString workingPath = m_sBackslashPath;
533 LPTSTR pPath = workingPath.GetBuffer(MAX_PATH); // MAX_PATH ok here.
534 ATLVERIFY(::PathStripToRoot(pPath));
535 workingPath.ReleaseBuffer();
536 return workingPath;
540 CString CTGitPath::GetFilename() const
542 //ATLASSERT(!IsDirectory());
543 return GetFileOrDirectoryName();
546 CString CTGitPath::GetFileOrDirectoryName() const
548 EnsureBackslashPathSet();
549 return m_sBackslashPath.Mid(m_sBackslashPath.ReverseFind('\\')+1);
552 CString CTGitPath::GetUIFileOrDirectoryName() const
554 GetUIPathString();
555 return m_sUIPath.Mid(m_sUIPath.ReverseFind('\\')+1);
558 CString CTGitPath::GetFileExtension() const
560 if(!IsDirectory())
562 EnsureBackslashPathSet();
563 int dotPos = m_sBackslashPath.ReverseFind('.');
564 int slashPos = m_sBackslashPath.ReverseFind('\\');
565 if (dotPos > slashPos)
566 return m_sBackslashPath.Mid(dotPos);
568 return CString();
570 CString CTGitPath::GetBaseFilename() const
572 int dot;
573 CString filename=GetFilename();
574 dot = filename.ReverseFind(_T('.'));
575 if(dot>0)
576 return filename.Left(dot);
577 else
578 return filename;
581 bool CTGitPath::ArePathStringsEqual(const CString& sP1, const CString& sP2)
583 int length = sP1.GetLength();
584 if(length != sP2.GetLength())
586 // Different lengths
587 return false;
589 // We work from the end of the strings, because path differences
590 // are more likely to occur at the far end of a string
591 LPCTSTR pP1Start = sP1;
592 LPCTSTR pP1 = pP1Start+(length-1);
593 LPCTSTR pP2 = ((LPCTSTR)sP2)+(length-1);
594 while(length-- > 0)
596 if(_totlower(*pP1--) != _totlower(*pP2--))
598 return false;
601 return true;
604 bool CTGitPath::ArePathStringsEqualWithCase(const CString& sP1, const CString& sP2)
606 int length = sP1.GetLength();
607 if(length != sP2.GetLength())
609 // Different lengths
610 return false;
612 // We work from the end of the strings, because path differences
613 // are more likely to occur at the far end of a string
614 LPCTSTR pP1Start = sP1;
615 LPCTSTR pP1 = pP1Start+(length-1);
616 LPCTSTR pP2 = ((LPCTSTR)sP2)+(length-1);
617 while(length-- > 0)
619 if((*pP1--) != (*pP2--))
621 return false;
624 return true;
627 bool CTGitPath::IsEmpty() const
629 // Check the backward slash path first, since the chance that this
630 // one is set is higher. In case of a 'false' return value it's a little
631 // bit faster.
632 return m_sBackslashPath.IsEmpty() && m_sFwdslashPath.IsEmpty();
635 // Test if both paths refer to the same item
636 // Ignores case and slash direction
637 bool CTGitPath::IsEquivalentTo(const CTGitPath& rhs) const
639 // Try and find a slash direction which avoids having to convert
640 // both filenames
641 if(!m_sBackslashPath.IsEmpty())
643 // *We've* got a \ path - make sure that the RHS also has a \ path
644 rhs.EnsureBackslashPathSet();
645 return ArePathStringsEqualWithCase(m_sBackslashPath, rhs.m_sBackslashPath);
647 else
649 // Assume we've got a fwdslash path and make sure that the RHS has one
650 rhs.EnsureFwdslashPathSet();
651 return ArePathStringsEqualWithCase(m_sFwdslashPath, rhs.m_sFwdslashPath);
655 bool CTGitPath::IsEquivalentToWithoutCase(const CTGitPath& rhs) const
657 // Try and find a slash direction which avoids having to convert
658 // both filenames
659 if(!m_sBackslashPath.IsEmpty())
661 // *We've* got a \ path - make sure that the RHS also has a \ path
662 rhs.EnsureBackslashPathSet();
663 return ArePathStringsEqual(m_sBackslashPath, rhs.m_sBackslashPath);
665 else
667 // Assume we've got a fwdslash path and make sure that the RHS has one
668 rhs.EnsureFwdslashPathSet();
669 return ArePathStringsEqual(m_sFwdslashPath, rhs.m_sFwdslashPath);
673 bool CTGitPath::IsAncestorOf(const CTGitPath& possibleDescendant) const
675 possibleDescendant.EnsureBackslashPathSet();
676 EnsureBackslashPathSet();
678 bool bPathStringsEqual = ArePathStringsEqual(m_sBackslashPath, possibleDescendant.m_sBackslashPath.Left(m_sBackslashPath.GetLength()));
679 if (m_sBackslashPath.GetLength() >= possibleDescendant.GetWinPathString().GetLength())
681 return bPathStringsEqual;
684 return (bPathStringsEqual &&
685 ((possibleDescendant.m_sBackslashPath[m_sBackslashPath.GetLength()] == '\\')||
686 (m_sBackslashPath.GetLength()==3 && m_sBackslashPath[1]==':')));
689 // Get a string representing the file path, optionally with a base
690 // section stripped off the front.
691 CString CTGitPath::GetDisplayString(const CTGitPath* pOptionalBasePath /* = NULL*/) const
693 EnsureFwdslashPathSet();
694 if(pOptionalBasePath != NULL)
696 // Find the length of the base-path without having to do an 'ensure' on it
697 int baseLength = max(pOptionalBasePath->m_sBackslashPath.GetLength(), pOptionalBasePath->m_sFwdslashPath.GetLength());
699 // Now, chop that baseLength of the front of the path
700 return m_sFwdslashPath.Mid(baseLength).TrimLeft('/');
702 return m_sFwdslashPath;
705 int CTGitPath::Compare(const CTGitPath& left, const CTGitPath& right)
707 left.EnsureBackslashPathSet();
708 right.EnsureBackslashPathSet();
709 return left.m_sBackslashPath.CompareNoCase(right.m_sBackslashPath);
712 bool operator<(const CTGitPath& left, const CTGitPath& right)
714 return CTGitPath::Compare(left, right) < 0;
717 bool CTGitPath::PredLeftEquivalentToRight(const CTGitPath& left, const CTGitPath& right)
719 return left.IsEquivalentTo(right);
722 bool CTGitPath::PredLeftSameWCPathAsRight(const CTGitPath& left, const CTGitPath& right)
724 if (left.IsAdminDir() && right.IsAdminDir())
726 CTGitPath l = left;
727 CTGitPath r = right;
730 l = l.GetContainingDirectory();
731 } while(l.HasAdminDir());
734 r = r.GetContainingDirectory();
735 } while(r.HasAdminDir());
736 return l.GetContainingDirectory().IsEquivalentTo(r.GetContainingDirectory());
738 return left.GetDirectory().IsEquivalentTo(right.GetDirectory());
741 bool CTGitPath::CheckChild(const CTGitPath &parent, const CTGitPath& child)
743 return parent.IsAncestorOf(child);
746 void CTGitPath::AppendRawString(const CString& sAppend)
748 EnsureFwdslashPathSet();
749 CString strCopy = m_sFwdslashPath += sAppend;
750 SetFromUnknown(strCopy);
753 void CTGitPath::AppendPathString(const CString& sAppend)
755 EnsureBackslashPathSet();
756 CString cleanAppend(sAppend);
757 cleanAppend.Replace('/', '\\');
758 cleanAppend.TrimLeft('\\');
759 m_sBackslashPath.TrimRight('\\');
760 CString strCopy = m_sBackslashPath + _T("\\") + cleanAppend;
761 SetFromWin(strCopy);
764 bool CTGitPath::IsWCRoot() const
766 if (m_bIsWCRootKnown)
767 return m_bIsWCRoot;
769 m_bIsWCRootKnown = true;
770 m_bIsWCRoot = false;
772 CString topDirectory;
773 if (!IsDirectory() || !HasAdminDir(&topDirectory))
775 return m_bIsWCRoot;
778 if (IsEquivalentToWithoutCase(topDirectory))
780 m_bIsWCRoot = true;
783 return m_bIsWCRoot;
786 bool CTGitPath::HasAdminDir() const
788 if (m_bHasAdminDirKnown)
789 return m_bHasAdminDir;
791 EnsureBackslashPathSet();
792 m_bHasAdminDir = g_GitAdminDir.HasAdminDir(m_sBackslashPath, IsDirectory(), &m_sProjectRoot);
793 m_bHasAdminDirKnown = true;
794 return m_bHasAdminDir;
797 bool CTGitPath::HasSubmodules() const
799 return !g_GitAdminDir.GetSuperProjectRoot(GetWinPathString()).IsEmpty();
802 int CTGitPath::GetAdminDirMask() const
804 int status = 0;
805 CString topdir,path;
806 if(!g_GitAdminDir.HasAdminDir(GetWinPathString(),&topdir))
808 return status;
811 // ITEMIS_INSVN will be revoked if necessary in TortoiseShell/ContextMenu.cpp
812 status |= ITEMIS_INSVN|ITEMIS_INVERSIONEDFOLDER;
814 if (IsDirectory())
816 status |= ITEMIS_FOLDERINSVN;
817 if (IsWCRoot())
818 status |= ITEMIS_WCROOT;
821 path=topdir;
822 path += _T("\\");
823 path += g_GitAdminDir.GetAdminDirName();
824 path += _T("\\BISECT_START");
825 if (PathFileExists(path))
826 status |= ITEMIS_BISECT;
828 path=topdir;
829 path += _T("\\");
830 path += g_GitAdminDir.GetAdminDirName();
831 path += _T("\\refs\\stash");
832 if( PathFileExists(path) )
833 status |= ITEMIS_STASH;
835 path=topdir;
836 path += _T("\\");
837 path += g_GitAdminDir.GetAdminDirName();
838 path += _T("\\svn");
839 if( PathFileExists(path) )
840 status |= ITEMIS_GITSVN;
842 path=topdir;
843 path += _T("\\.gitmodules");
844 if( PathFileExists(path) )
845 status |= ITEMIS_SUBMODULECONTAINER;
847 return status;
850 bool CTGitPath::HasStashDir() const
852 CString topdir;
853 if(!g_GitAdminDir.HasAdminDir(GetWinPathString(),&topdir))
855 return false;
857 topdir += _T("\\");
858 topdir += g_GitAdminDir.GetAdminDirName();
859 topdir += _T("\\refs\\stash");
860 return !!PathFileExists(topdir);
862 bool CTGitPath::HasGitSVNDir() const
864 CString topdir;
865 if(!g_GitAdminDir.HasAdminDir(GetWinPathString(),&topdir))
867 return false;
869 topdir += _T("\\");
870 topdir += g_GitAdminDir.GetAdminDirName();
871 topdir += _T("\\svn");
872 return !!PathFileExists(topdir);
874 bool CTGitPath::IsBisectActive() const
876 CString topdir;
877 if(!g_GitAdminDir.HasAdminDir(GetWinPathString(),&topdir))
879 return false;
881 topdir += _T("\\");
882 topdir += g_GitAdminDir.GetAdminDirName();
883 topdir += _T("\\BISECT_START");
884 return !!PathFileExists(topdir);
886 bool CTGitPath::HasRebaseApply() const
888 CString topdir;
889 if(!g_GitAdminDir.HasAdminDir(GetWinPathString(),&topdir))
891 return false;
893 topdir += _T("\\");
894 topdir += g_GitAdminDir.GetAdminDirName();
895 topdir += _T("\\rebase-apply");
896 return !!PathFileExists(topdir);
899 bool CTGitPath::HasAdminDir(CString *ProjectTopDir) const
901 if (m_bHasAdminDirKnown)
903 if (ProjectTopDir)
904 *ProjectTopDir = m_sProjectRoot;
905 return m_bHasAdminDir;
908 EnsureBackslashPathSet();
909 m_bHasAdminDir = g_GitAdminDir.HasAdminDir(m_sBackslashPath, IsDirectory(), &m_sProjectRoot);
910 m_bHasAdminDirKnown = true;
911 if (ProjectTopDir)
912 *ProjectTopDir = m_sProjectRoot;
913 return m_bHasAdminDir;
916 bool CTGitPath::IsAdminDir() const
918 if (m_bIsAdminDirKnown)
919 return m_bIsAdminDir;
921 EnsureBackslashPathSet();
922 m_bIsAdminDir = g_GitAdminDir.IsAdminDirPath(m_sBackslashPath);
923 m_bIsAdminDirKnown = true;
924 return m_bIsAdminDir;
927 bool CTGitPath::IsValidOnWindows() const
929 if (m_bIsValidOnWindowsKnown)
930 return m_bIsValidOnWindows;
932 m_bIsValidOnWindows = false;
933 EnsureBackslashPathSet();
934 CString sMatch = m_sBackslashPath + _T("\r\n");
935 wstring sPattern;
936 // the 'file://' URL is just a normal windows path:
937 if (sMatch.Left(7).CompareNoCase(_T("file:\\\\"))==0)
939 sMatch = sMatch.Mid(7);
940 sMatch.TrimLeft(_T("\\"));
941 sPattern = _T("^(\\\\\\\\\\?\\\\)?(([a-zA-Z]:|\\\\)\\\\)?(((\\.)|(\\.\\.)|([^\\\\/:\\*\\?\"\\|<> ](([^\\\\/:\\*\\?\"\\|<>\\. ])|([^\\\\/:\\*\\?\"\\|<>]*[^\\\\/:\\*\\?\"\\|<>\\. ]))?))\\\\)*[^\\\\/:\\*\\?\"\\|<> ](([^\\\\/:\\*\\?\"\\|<>\\. ])|([^\\\\/:\\*\\?\"\\|<>]*[^\\\\/:\\*\\?\"\\|<>\\. ]))?$");
943 else if (IsUrl())
945 sPattern = _T("^((http|https|svn|svn\\+ssh|file)\\:\\\\+([^\\\\@\\:]+\\:[^\\\\@\\:]+@)?\\\\[^\\\\]+(\\:\\d+)?)?(((\\.)|(\\.\\.)|([^\\\\/:\\*\\?\"\\|<>\\. ](([^\\\\/:\\*\\?\"\\|<>\\. ])|([^\\\\/:\\*\\?\"\\|<>]*[^\\\\/:\\*\\?\"\\|<>\\. ]))?))\\\\)*[^\\\\/:\\*\\?\"\\|<>\\. ](([^\\\\/:\\*\\?\"\\|<>\\. ])|([^\\\\/:\\*\\?\"\\|<>]*[^\\\\/:\\*\\?\"\\|<>\\. ]))?$");
947 else
949 sPattern = _T("^(\\\\\\\\\\?\\\\)?(([a-zA-Z]:|\\\\)\\\\)?(((\\.)|(\\.\\.)|([^\\\\/:\\*\\?\"\\|<> ](([^\\\\/:\\*\\?\"\\|<>\\. ])|([^\\\\/:\\*\\?\"\\|<>]*[^\\\\/:\\*\\?\"\\|<>\\. ]))?))\\\\)*[^\\\\/:\\*\\?\"\\|<> ](([^\\\\/:\\*\\?\"\\|<>\\. ])|([^\\\\/:\\*\\?\"\\|<>]*[^\\\\/:\\*\\?\"\\|<>\\. ]))?$");
954 tr1::wregex rx(sPattern, tr1::regex_constants::icase | tr1::regex_constants::ECMAScript);
955 tr1::wsmatch match;
957 wstring rmatch = wstring((LPCTSTR)sMatch);
958 if (tr1::regex_match(rmatch, match, rx))
960 if (wstring(match[0]).compare(sMatch)==0)
961 m_bIsValidOnWindows = true;
963 if (m_bIsValidOnWindows)
965 // now check for illegal filenames
966 tr1::wregex rx2(_T("\\\\(lpt\\d|com\\d|aux|nul|prn|con)(\\\\|$)"), tr1::regex_constants::icase | tr1::regex_constants::ECMAScript);
967 rmatch = m_sBackslashPath;
968 if (tr1::regex_search(rmatch, rx2, tr1::regex_constants::match_default))
969 m_bIsValidOnWindows = false;
972 catch (exception) {}
974 m_bIsValidOnWindowsKnown = true;
975 return m_bIsValidOnWindows;
978 bool CTGitPath::IsSpecialDirectory() const
980 if (m_bIsSpecialDirectoryKnown)
981 return m_bIsSpecialDirectory;
983 static LPCTSTR specialDirectories[]
984 = { _T("trunk"), _T("tags"), _T("branches") };
986 for (int i = 0; i < _countof(specialDirectories); ++i)
988 CString name = GetFileOrDirectoryName();
989 if (0 == name.CompareNoCase(specialDirectories[i]))
991 m_bIsSpecialDirectory = true;
992 break;
996 m_bIsSpecialDirectoryKnown = true;
998 return m_bIsSpecialDirectory;
1001 //////////////////////////////////////////////////////////////////////////
1003 CTGitPathList::CTGitPathList()
1008 // A constructor which allows a path list to be easily built which one initial entry in
1009 CTGitPathList::CTGitPathList(const CTGitPath& firstEntry)
1011 AddPath(firstEntry);
1013 int CTGitPathList::ParserFromLsFile(BYTE_VECTOR &out,bool /*staged*/)
1015 unsigned int pos=0;
1016 CString one;
1017 CTGitPath path;
1018 CString part;
1019 this->Clear();
1021 while(pos>=0 && pos<out.size())
1023 one.Empty();
1024 path.Reset();
1026 g_Git.StringAppend(&one,&out[pos],CP_ACP);
1027 int tabstart=0;
1028 path.m_Action=path.ParserAction(out[pos]);
1029 one.Tokenize(_T("\t"),tabstart);
1031 if(tabstart>=0)
1032 path.SetFromGit(one.Right(one.GetLength()-tabstart));
1034 tabstart=0;
1036 part=one.Tokenize(_T(" "),tabstart); //Tag
1038 part=one.Tokenize(_T(" "),tabstart); //Mode
1040 part=one.Tokenize(_T(" "),tabstart); //Hash
1042 part=one.Tokenize(_T("\t"),tabstart); //Stage
1044 path.m_Stage=_ttol(part);
1046 this->AddPath(path);
1048 pos=out.findNextString(pos);
1050 return pos;
1052 int CTGitPathList::FillUnRev(unsigned int action,CTGitPathList *list)
1054 int pos=0;
1055 this->Clear();
1056 CTGitPath path;
1058 int count;
1059 if(list==NULL)
1060 count=1;
1061 else
1062 count=list->GetCount();
1063 for(int i=0;i<count;i++)
1065 CString cmd;
1066 pos=0;
1068 CString ignored;
1069 if(action & CTGitPath::LOGACTIONS_IGNORE)
1070 ignored= _T(" -i");
1072 if(list==NULL)
1074 cmd=_T("git.exe ls-files --exclude-standard --full-name --others -z");
1075 cmd+=ignored;
1078 else
1079 { cmd.Format(_T("git.exe ls-files --exclude-standard --full-name --others -z%s -- \"%s\""),
1080 ignored,
1081 (*list)[i].GetWinPathString());
1084 BYTE_VECTOR out;
1085 out.clear();
1086 g_Git.Run(cmd,&out);
1088 pos=0;
1089 CString one;
1090 while( pos>=0 && pos<out.size())
1092 one.Empty();
1093 g_Git.StringAppend(&one,&out[pos],CP_ACP);
1094 if(!one.IsEmpty())
1096 //SetFromGit will clear all status
1097 path.SetFromGit(one);
1098 path.m_Action=action;
1099 AddPath(path);
1101 pos=out.findNextString(pos);
1105 return 0;
1107 int CTGitPathList::ParserFromLog(BYTE_VECTOR &log, bool parseDeletes /*false*/)
1109 this->Clear();
1110 int pos=0;
1111 //BYTE *p=&log[0];
1112 //CString one;
1113 CTGitPath path;
1114 m_Action=0;
1115 while( pos>=0 && pos<log.size())
1117 //one=log.Tokenize(_T("\n"),pos);
1118 path.Reset();
1119 if(log[pos]=='\n')
1120 pos++;
1122 if(log[pos]==':')
1124 bool merged=false;
1125 if(log[pos+1] ==':')
1127 merged=true;
1129 int end=log.find(0,pos);
1130 int actionstart=-1;
1131 int numfile=1;
1132 int file1=-1,file2=-1;
1133 if( end>0 )
1135 actionstart=log.find(' ',end-6);
1136 pos=actionstart;
1138 if( actionstart>0 )
1140 actionstart++;
1142 file1 = log.find(0,actionstart);
1143 if( file1>=0 )
1145 file1++;
1146 pos=file1;
1148 if( log[actionstart] == 'C' || log[actionstart] == 'R' )
1150 file2=file1;
1151 numfile=2;
1152 file1 = log.find(0,file1);
1153 if(file1>=0 )
1155 file1++;
1156 pos=file1;
1162 CString pathname1;
1163 CString pathname2;
1165 if( file1>=0 )
1166 g_Git.StringAppend(&pathname1,&log[file1],CP_ACP);
1167 if( file2>=0 )
1168 g_Git.StringAppend(&pathname2,&log[file2],CP_ACP);
1170 CTGitPath *GitPath=LookForGitPath(pathname1);
1172 if(GitPath)
1174 GitPath->ParserAction( log[actionstart] );
1176 if(merged)
1178 GitPath->m_Action |= CTGitPath::LOGACTIONS_MERGED;
1179 GitPath->m_Action &= ~CTGitPath::LOGACTIONS_FORWORD;
1181 m_Action |=GitPath->m_Action;
1184 else
1186 int ac=path.ParserAction(log[actionstart] );
1187 ac |= merged?CTGitPath::LOGACTIONS_MERGED:0;
1189 path.SetFromGit(pathname1,&pathname2);
1190 path.m_Action=ac;
1191 //action must be set after setfromgit. SetFromGit will clear all status.
1192 this->m_Action|=ac;
1194 AddPath(path);
1199 else
1201 int tabstart=0;
1202 path.Reset();
1203 CString StatAdd;
1204 CString StatDel;
1205 CString file1;
1206 CString file2;
1208 tabstart=log.find('\t',pos);
1209 if(tabstart >=0)
1211 log[tabstart]=0;
1212 g_Git.StringAppend(&StatAdd,&log[pos],CP_UTF8);
1213 pos=tabstart+1;
1216 tabstart=log.find('\t',pos);
1217 if(tabstart >=0)
1219 log[tabstart]=0;
1221 g_Git.StringAppend(&StatDel,&log[pos],CP_UTF8);
1222 pos=tabstart+1;
1225 if(log[pos] == 0) //rename
1227 pos++;
1228 g_Git.StringAppend(&file2,&log[pos],CP_ACP);
1229 int sec=log.find(0,pos);
1230 if(sec>=0)
1232 sec++;
1233 g_Git.StringAppend(&file1,&log[sec],CP_ACP);
1235 pos=sec;
1238 else
1240 g_Git.StringAppend(&file1,&log[pos],CP_ACP);
1242 path.SetFromGit(file1,&file2);
1244 CTGitPath *GitPath=LookForGitPath(path.GetGitPathString());
1245 if(GitPath)
1247 GitPath->m_StatAdd=StatAdd;
1248 GitPath->m_StatDel=StatDel;
1250 else
1252 //path.SetFromGit(pathname);
1253 if (parseDeletes)
1255 path.m_StatAdd=_T("0");
1256 path.m_StatDel=_T("0");
1257 path.m_Action |= CTGitPath::LOGACTIONS_DELETED;
1259 else
1261 path.m_StatAdd=StatAdd;
1262 path.m_StatDel=StatDel;
1263 path.m_Action |= CTGitPath::LOGACTIONS_FORWORD;
1265 AddPath(path);
1269 pos=log.findNextString(pos);
1271 return pos;
1274 void CTGitPathList::AddPath(const CTGitPath& newPath)
1276 m_paths.push_back(newPath);
1277 m_commonBaseDirectory.Reset();
1279 int CTGitPathList::GetCount() const
1281 return (int)m_paths.size();
1283 void CTGitPathList::Clear()
1285 m_paths.clear();
1286 m_commonBaseDirectory.Reset();
1289 const CTGitPath& CTGitPathList::operator[](INT_PTR index) const
1291 ATLASSERT(index >= 0 && index < (INT_PTR)m_paths.size());
1292 return m_paths[index];
1295 bool CTGitPathList::AreAllPathsFiles() const
1297 // Look through the vector for any directories - if we find them, return false
1298 return std::find_if(m_paths.begin(), m_paths.end(), std::mem_fun_ref(&CTGitPath::IsDirectory)) == m_paths.end();
1302 #if defined(_MFC_VER)
1304 bool CTGitPathList::LoadFromFile(const CTGitPath& filename)
1306 Clear();
1309 CString strLine;
1310 CStdioFile file(filename.GetWinPath(), CFile::typeBinary | CFile::modeRead | CFile::shareDenyWrite);
1312 // for every selected file/folder
1313 CTGitPath path;
1314 while (file.ReadString(strLine))
1316 path.SetFromUnknown(strLine);
1317 AddPath(path);
1319 file.Close();
1321 catch (CFileException* pE)
1323 TRACE("CFileException loading target file list\n");
1324 TCHAR error[10000] = {0};
1325 pE->GetErrorMessage(error, 10000);
1326 // CMessageBox::Show(NULL, error, _T("TortoiseGit"), MB_ICONERROR);
1327 pE->Delete();
1328 return false;
1330 return true;
1333 bool CTGitPathList::WriteToFile(const CString& sFilename, bool bANSI /* = false */) const
1337 if (bANSI)
1339 CStdioFile file(sFilename, CFile::typeText | CFile::modeReadWrite | CFile::modeCreate);
1340 PathVector::const_iterator it;
1341 for(it = m_paths.begin(); it != m_paths.end(); ++it)
1343 CStringA line = CStringA(it->GetGitPathString()) + '\n';
1344 file.Write(line, line.GetLength());
1346 file.Close();
1348 else
1350 CStdioFile file(sFilename, CFile::typeBinary | CFile::modeReadWrite | CFile::modeCreate);
1351 PathVector::const_iterator it;
1352 for(it = m_paths.begin(); it != m_paths.end(); ++it)
1354 file.WriteString(it->GetGitPathString()+_T("\n"));
1356 file.Close();
1359 catch (CFileException* pE)
1361 TRACE("CFileException in writing temp file\n");
1362 pE->Delete();
1363 return false;
1365 return true;
1369 void CTGitPathList::LoadFromAsteriskSeparatedString(const CString& sPathString)
1371 int pos = 0;
1372 CString temp;
1373 for(;;)
1375 temp = sPathString.Tokenize(_T("*"),pos);
1376 if(temp.IsEmpty())
1378 break;
1380 AddPath(CTGitPath(CPathUtils::GetLongPathname(temp)));
1384 CString CTGitPathList::CreateAsteriskSeparatedString() const
1386 CString sRet;
1387 PathVector::const_iterator it;
1388 for(it = m_paths.begin(); it != m_paths.end(); ++it)
1390 if (!sRet.IsEmpty())
1391 sRet += _T("*");
1392 sRet += it->GetWinPathString();
1394 return sRet;
1396 #endif // _MFC_VER
1398 bool
1399 CTGitPathList::AreAllPathsFilesInOneDirectory() const
1401 // Check if all the paths are files and in the same directory
1402 PathVector::const_iterator it;
1403 m_commonBaseDirectory.Reset();
1404 for(it = m_paths.begin(); it != m_paths.end(); ++it)
1406 if(it->IsDirectory())
1408 return false;
1410 const CTGitPath& baseDirectory = it->GetDirectory();
1411 if(m_commonBaseDirectory.IsEmpty())
1413 m_commonBaseDirectory = baseDirectory;
1415 else if(!m_commonBaseDirectory.IsEquivalentTo(baseDirectory))
1417 // Different path
1418 m_commonBaseDirectory.Reset();
1419 return false;
1422 return true;
1425 CTGitPath CTGitPathList::GetCommonDirectory() const
1427 if (m_commonBaseDirectory.IsEmpty())
1429 PathVector::const_iterator it;
1430 for(it = m_paths.begin(); it != m_paths.end(); ++it)
1432 const CTGitPath& baseDirectory = it->GetDirectory();
1433 if(m_commonBaseDirectory.IsEmpty())
1435 m_commonBaseDirectory = baseDirectory;
1437 else if(!m_commonBaseDirectory.IsEquivalentTo(baseDirectory))
1439 // Different path
1440 m_commonBaseDirectory.Reset();
1441 break;
1445 // since we only checked strings, not paths,
1446 // we have to make sure now that we really return a *path* here
1447 PathVector::const_iterator iter;
1448 for(iter = m_paths.begin(); iter != m_paths.end(); ++iter)
1450 if (!m_commonBaseDirectory.IsAncestorOf(*iter))
1452 m_commonBaseDirectory = m_commonBaseDirectory.GetContainingDirectory();
1453 break;
1456 return m_commonBaseDirectory;
1459 CTGitPath CTGitPathList::GetCommonRoot() const
1461 PathVector::const_iterator it;
1462 CString sRoot, sTempRoot;
1463 bool bEqual = true;
1465 if (GetCount() == 1)
1466 return m_paths[0];
1468 int backSlashPos = 0;
1469 int searchStartPos = 0;
1470 while (bEqual)
1472 if(m_paths.empty())
1473 break;
1475 for (it = m_paths.begin(); it != m_paths.end(); ++it)
1477 if (backSlashPos == 0)
1479 backSlashPos = it->GetWinPathString().Find('\\', searchStartPos+1);
1480 if ((backSlashPos < 0)&&(searchStartPos != it->GetWinPathString().GetLength()))
1481 backSlashPos = it->GetWinPathString().GetLength();
1482 sTempRoot = it->GetWinPathString().Left(backSlashPos+1);
1484 else if (it->GetWinPathString().Find('\\', searchStartPos+1) != backSlashPos || it->GetWinPathString().Left(backSlashPos+1) != sTempRoot.Left(backSlashPos+1))
1486 if (it->GetWinPathString().Find('\\', searchStartPos+1) < 0)
1488 if (it->GetWinPathString().GetLength() != backSlashPos || it->GetWinPathString().Left(backSlashPos+1) != sTempRoot.Left(backSlashPos+1))
1490 bEqual = false;
1491 break;
1494 else
1496 bEqual = false;
1497 break;
1500 if (backSlashPos < 0)
1502 bEqual = false;
1503 break;
1506 if (bEqual == false)
1508 if (searchStartPos)
1509 sRoot = m_paths[0].GetWinPathString().Left(searchStartPos+1);
1511 else
1513 searchStartPos = backSlashPos;
1515 backSlashPos = 0;
1518 return CTGitPath(sRoot.TrimRight('\\'));
1521 void CTGitPathList::SortByPathname(bool bReverse /*= false*/)
1523 std::sort(m_paths.begin(), m_paths.end());
1524 if (bReverse)
1525 std::reverse(m_paths.begin(), m_paths.end());
1528 void CTGitPathList::DeleteAllFiles(bool bTrash)
1530 PathVector::const_iterator it;
1531 if (bTrash)
1533 SortByPathname();
1534 CString sPaths;
1535 for (it = m_paths.begin(); it != m_paths.end(); ++it)
1537 if ((it->Exists())&&(!it->IsDirectory()))
1539 ::SetFileAttributes(it->GetWinPath(), FILE_ATTRIBUTE_NORMAL);
1540 sPaths += it->GetWinPath();
1541 sPaths += '\0';
1544 sPaths += '\0';
1545 sPaths += '\0';
1546 SHFILEOPSTRUCT shop = {0};
1547 shop.wFunc = FO_DELETE;
1548 shop.pFrom = (LPCTSTR)sPaths;
1549 shop.fFlags = FOF_ALLOWUNDO|FOF_NOCONFIRMATION|FOF_NOERRORUI|FOF_SILENT;
1550 SHFileOperation(&shop);
1552 else
1554 for (it = m_paths.begin(); it != m_paths.end(); ++it)
1556 if (!it->IsDirectory())
1558 ::SetFileAttributes(it->GetWinPath(), FILE_ATTRIBUTE_NORMAL);
1559 ::DeleteFile(it->GetWinPath());
1563 Clear();
1566 void CTGitPathList::RemoveDuplicates()
1568 SortByPathname();
1569 // Remove the duplicates
1570 // (Unique moves them to the end of the vector, then erase chops them off)
1571 m_paths.erase(std::unique(m_paths.begin(), m_paths.end(), &CTGitPath::PredLeftEquivalentToRight), m_paths.end());
1574 void CTGitPathList::RemoveAdminPaths()
1576 PathVector::iterator it;
1577 for(it = m_paths.begin(); it != m_paths.end(); )
1579 if (it->IsAdminDir())
1581 m_paths.erase(it);
1582 it = m_paths.begin();
1584 else
1585 ++it;
1589 void CTGitPathList::RemovePath(const CTGitPath& path)
1591 PathVector::iterator it;
1592 for(it = m_paths.begin(); it != m_paths.end(); ++it)
1594 if (it->IsEquivalentTo(path))
1596 m_paths.erase(it);
1597 return;
1602 void CTGitPathList::RemoveItem(CTGitPath & path)
1604 PathVector::iterator it;
1605 for(it = m_paths.begin(); it != m_paths.end(); ++it)
1607 if (it->GetGitPathString()==path.GetGitPathString())
1609 m_paths.erase(it);
1610 return;
1614 void CTGitPathList::RemoveChildren()
1616 SortByPathname();
1617 m_paths.erase(std::unique(m_paths.begin(), m_paths.end(), &CTGitPath::CheckChild), m_paths.end());
1620 bool CTGitPathList::IsEqual(const CTGitPathList& list)
1622 if (list.GetCount() != GetCount())
1623 return false;
1624 for (int i=0; i<list.GetCount(); ++i)
1626 if (!list[i].IsEquivalentTo(m_paths[i]))
1627 return false;
1629 return true;
1632 //////////////////////////////////////////////////////////////////////////
1633 #if 0
1634 apr_array_header_t * CTGitPathList::MakePathArray (apr_pool_t *pool) const
1636 apr_array_header_t *targets = apr_array_make (pool, GetCount(), sizeof(const char *));
1638 for(int nItem = 0; nItem < GetCount(); nItem++)
1640 const char * target = m_paths[nItem].GetGitApiPath(pool);
1641 (*((const char **) apr_array_push (targets))) = target;
1644 return targets;
1646 #endif
1647 //////////////////////////////////////////////////////////////////////////
1649 #if 0
1650 #if defined(_DEBUG)
1651 // Some test cases for these classes
1652 static class CTGitPathTests
1654 public:
1655 CTGitPathTests()
1657 apr_initialize();
1658 pool = svn_pool_create(NULL);
1659 GetDirectoryTest();
1660 AdminDirTest();
1661 SortTest();
1662 RawAppendTest();
1663 PathAppendTest();
1664 RemoveDuplicatesTest();
1665 RemoveChildrenTest();
1666 ContainingDirectoryTest();
1667 AncestorTest();
1668 SubversionPathTest();
1669 GetCommonRootTest();
1670 #if defined(_MFC_VER)
1671 ValidPathAndUrlTest();
1672 ListLoadingTest();
1673 #endif
1674 apr_terminate();
1677 private:
1678 // apr_pool_t * pool;
1679 void GetDirectoryTest()
1681 // Bit tricky, this test, because we need to know something about the file
1682 // layout on the machine which is running the test
1683 TCHAR winDir[MAX_PATH+1];
1684 GetWindowsDirectory(winDir, MAX_PATH);
1685 CString sWinDir(winDir);
1687 CTGitPath testPath;
1688 // This is a file which we know will always be there
1689 testPath.SetFromUnknown(sWinDir + _T("\\win.ini"));
1690 ATLASSERT(!testPath.IsDirectory());
1691 ATLASSERT(testPath.GetDirectory().GetWinPathString() == sWinDir);
1692 ATLASSERT(testPath.GetContainingDirectory().GetWinPathString() == sWinDir);
1694 // Now do the test on the win directory itself - It's hard to be sure about the containing directory
1695 // but we know it must be different to the directory itself
1696 testPath.SetFromUnknown(sWinDir);
1697 ATLASSERT(testPath.IsDirectory());
1698 ATLASSERT(testPath.GetDirectory().GetWinPathString() == sWinDir);
1699 ATLASSERT(testPath.GetContainingDirectory().GetWinPathString() != sWinDir);
1700 ATLASSERT(testPath.GetContainingDirectory().GetWinPathString().GetLength() < sWinDir.GetLength());
1702 // Try a root path
1703 testPath.SetFromUnknown(_T("C:\\"));
1704 ATLASSERT(testPath.IsDirectory());
1705 ATLASSERT(testPath.GetDirectory().GetWinPathString().CompareNoCase(_T("C:\\"))==0);
1706 ATLASSERT(testPath.GetContainingDirectory().IsEmpty());
1707 // Try a root UNC path
1708 testPath.SetFromUnknown(_T("\\MYSTATION"));
1709 ATLASSERT(testPath.GetContainingDirectory().IsEmpty());
1712 void AdminDirTest()
1714 CTGitPath testPath;
1715 testPath.SetFromUnknown(_T("c:\\.svndir"));
1716 ATLASSERT(!testPath.IsAdminDir());
1717 testPath.SetFromUnknown(_T("c:\\test.svn"));
1718 ATLASSERT(!testPath.IsAdminDir());
1719 testPath.SetFromUnknown(_T("c:\\.svn"));
1720 ATLASSERT(testPath.IsAdminDir());
1721 testPath.SetFromUnknown(_T("c:\\.svndir\\test"));
1722 ATLASSERT(!testPath.IsAdminDir());
1723 testPath.SetFromUnknown(_T("c:\\.svn\\test"));
1724 ATLASSERT(testPath.IsAdminDir());
1726 CTGitPathList pathList;
1727 pathList.AddPath(CTGitPath(_T("c:\\.svndir")));
1728 pathList.AddPath(CTGitPath(_T("c:\\.svn")));
1729 pathList.AddPath(CTGitPath(_T("c:\\.svn\\test")));
1730 pathList.AddPath(CTGitPath(_T("c:\\test")));
1731 pathList.RemoveAdminPaths();
1732 ATLASSERT(pathList.GetCount()==2);
1733 pathList.Clear();
1734 pathList.AddPath(CTGitPath(_T("c:\\test")));
1735 pathList.RemoveAdminPaths();
1736 ATLASSERT(pathList.GetCount()==1);
1739 void SortTest()
1741 CTGitPathList testList;
1742 CTGitPath testPath;
1743 testPath.SetFromUnknown(_T("c:/Z"));
1744 testList.AddPath(testPath);
1745 testPath.SetFromUnknown(_T("c:/B"));
1746 testList.AddPath(testPath);
1747 testPath.SetFromUnknown(_T("c:\\a"));
1748 testList.AddPath(testPath);
1749 testPath.SetFromUnknown(_T("c:/Test"));
1750 testList.AddPath(testPath);
1752 testList.SortByPathname();
1754 ATLASSERT(testList[0].GetWinPathString() == _T("c:\\a"));
1755 ATLASSERT(testList[1].GetWinPathString() == _T("c:\\B"));
1756 ATLASSERT(testList[2].GetWinPathString() == _T("c:\\Test"));
1757 ATLASSERT(testList[3].GetWinPathString() == _T("c:\\Z"));
1760 void RawAppendTest()
1762 CTGitPath testPath(_T("c:/test/"));
1763 testPath.AppendRawString(_T("/Hello"));
1764 ATLASSERT(testPath.GetWinPathString() == _T("c:\\test\\Hello"));
1766 testPath.AppendRawString(_T("\\T2"));
1767 ATLASSERT(testPath.GetWinPathString() == _T("c:\\test\\Hello\\T2"));
1769 CTGitPath testFilePath(_T("C:\\windows\\win.ini"));
1770 CTGitPath testBasePath(_T("c:/temp/myfile.txt"));
1771 testBasePath.AppendRawString(testFilePath.GetFileExtension());
1772 ATLASSERT(testBasePath.GetWinPathString() == _T("c:\\temp\\myfile.txt.ini"));
1775 void PathAppendTest()
1777 CTGitPath testPath(_T("c:/test/"));
1778 testPath.AppendPathString(_T("/Hello"));
1779 ATLASSERT(testPath.GetWinPathString() == _T("c:\\test\\Hello"));
1781 testPath.AppendPathString(_T("T2"));
1782 ATLASSERT(testPath.GetWinPathString() == _T("c:\\test\\Hello\\T2"));
1784 CTGitPath testFilePath(_T("C:\\windows\\win.ini"));
1785 CTGitPath testBasePath(_T("c:/temp/myfile.txt"));
1786 // You wouldn't want to do this in real life - you'd use append-raw
1787 testBasePath.AppendPathString(testFilePath.GetFileExtension());
1788 ATLASSERT(testBasePath.GetWinPathString() == _T("c:\\temp\\myfile.txt\\.ini"));
1791 void RemoveDuplicatesTest()
1793 CTGitPathList list;
1794 list.AddPath(CTGitPath(_T("Z")));
1795 list.AddPath(CTGitPath(_T("A")));
1796 list.AddPath(CTGitPath(_T("E")));
1797 list.AddPath(CTGitPath(_T("E")));
1799 ATLASSERT(list[2].IsEquivalentTo(list[3]));
1800 ATLASSERT(list[2]==list[3]);
1802 ATLASSERT(list.GetCount() == 4);
1804 list.RemoveDuplicates();
1806 ATLASSERT(list.GetCount() == 3);
1808 ATLASSERT(list[0].GetWinPathString() == _T("A"));
1809 ATLASSERT(list[1].GetWinPathString().Compare(_T("E")) == 0);
1810 ATLASSERT(list[2].GetWinPathString() == _T("Z"));
1813 void RemoveChildrenTest()
1815 CTGitPathList list;
1816 list.AddPath(CTGitPath(_T("c:\\test")));
1817 list.AddPath(CTGitPath(_T("c:\\test\\file")));
1818 list.AddPath(CTGitPath(_T("c:\\testfile")));
1819 list.AddPath(CTGitPath(_T("c:\\parent")));
1820 list.AddPath(CTGitPath(_T("c:\\parent\\child")));
1821 list.AddPath(CTGitPath(_T("c:\\parent\\child1")));
1822 list.AddPath(CTGitPath(_T("c:\\parent\\child2")));
1824 ATLASSERT(list.GetCount() == 7);
1826 list.RemoveChildren();
1828 ATLTRACE("count = %d\n", list.GetCount());
1829 ATLASSERT(list.GetCount() == 3);
1831 list.SortByPathname();
1833 ATLASSERT(list[0].GetWinPathString().Compare(_T("c:\\parent")) == 0);
1834 ATLASSERT(list[1].GetWinPathString().Compare(_T("c:\\test")) == 0);
1835 ATLASSERT(list[2].GetWinPathString().Compare(_T("c:\\testfile")) == 0);
1838 #if defined(_MFC_VER)
1839 void ListLoadingTest()
1841 TCHAR buf[MAX_PATH];
1842 GetCurrentDirectory(MAX_PATH, buf);
1843 CString sPathList(_T("Path1*c:\\path2 with spaces and stuff*\\funnypath\\*"));
1844 CTGitPathList testList;
1845 testList.LoadFromAsteriskSeparatedString(sPathList);
1847 ATLASSERT(testList.GetCount() == 3);
1848 ATLASSERT(testList[0].GetWinPathString() == CString(buf) + _T("\\Path1"));
1849 ATLASSERT(testList[1].GetWinPathString() == _T("c:\\path2 with spaces and stuff"));
1850 ATLASSERT(testList[2].GetWinPathString() == _T("\\funnypath"));
1852 ATLASSERT(testList.GetCommonRoot().GetWinPathString() == _T(""));
1853 testList.Clear();
1854 sPathList = _T("c:\\path2 with spaces and stuff*c:\\funnypath\\*");
1855 testList.LoadFromAsteriskSeparatedString(sPathList);
1856 ATLASSERT(testList.GetCommonRoot().GetWinPathString() == _T("c:\\"));
1858 #endif
1860 void ContainingDirectoryTest()
1863 CTGitPath testPath;
1864 testPath.SetFromWin(_T("c:\\a\\b\\c\\d\\e"));
1865 CTGitPath dir;
1866 dir = testPath.GetContainingDirectory();
1867 ATLASSERT(dir.GetWinPathString() == _T("c:\\a\\b\\c\\d"));
1868 dir = dir.GetContainingDirectory();
1869 ATLASSERT(dir.GetWinPathString() == _T("c:\\a\\b\\c"));
1870 dir = dir.GetContainingDirectory();
1871 ATLASSERT(dir.GetWinPathString() == _T("c:\\a\\b"));
1872 dir = dir.GetContainingDirectory();
1873 ATLASSERT(dir.GetWinPathString() == _T("c:\\a"));
1874 dir = dir.GetContainingDirectory();
1875 ATLASSERT(dir.GetWinPathString() == _T("c:\\"));
1876 dir = dir.GetContainingDirectory();
1877 ATLASSERT(dir.IsEmpty());
1878 ATLASSERT(dir.GetWinPathString() == _T(""));
1881 void AncestorTest()
1883 CTGitPath testPath;
1884 testPath.SetFromWin(_T("c:\\windows"));
1885 ATLASSERT(testPath.IsAncestorOf(CTGitPath(_T("c:\\")))==false);
1886 ATLASSERT(testPath.IsAncestorOf(CTGitPath(_T("c:\\windows"))));
1887 ATLASSERT(testPath.IsAncestorOf(CTGitPath(_T("c:\\windowsdummy")))==false);
1888 ATLASSERT(testPath.IsAncestorOf(CTGitPath(_T("c:\\windows\\test.txt"))));
1889 ATLASSERT(testPath.IsAncestorOf(CTGitPath(_T("c:\\windows\\system32\\test.txt"))));
1892 void SubversionPathTest()
1894 CTGitPath testPath;
1895 testPath.SetFromWin(_T("c:\\"));
1896 ATLASSERT(strcmp(testPath.GetGitApiPath(pool), "c:") == 0);
1897 testPath.SetFromWin(_T("c:\\folder"));
1898 ATLASSERT(strcmp(testPath.GetGitApiPath(pool), "c:/folder") == 0);
1899 testPath.SetFromWin(_T("c:\\a\\b\\c\\d\\e"));
1900 ATLASSERT(strcmp(testPath.GetGitApiPath(pool), "c:/a/b/c/d/e") == 0);
1901 testPath.SetFromUnknown(_T("http://testing/"));
1902 ATLASSERT(strcmp(testPath.GetGitApiPath(pool), "http://testing") == 0);
1903 testPath.SetFromGit(NULL);
1904 ATLASSERT(strlen(testPath.GetGitApiPath(pool))==0);
1905 #if defined(_MFC_VER)
1906 testPath.SetFromUnknown(_T("http://testing again"));
1907 ATLASSERT(strcmp(testPath.GetGitApiPath(pool), "http://testing%20again") == 0);
1908 testPath.SetFromUnknown(_T("http://testing%20again"));
1909 ATLASSERT(strcmp(testPath.GetGitApiPath(pool), "http://testing%20again") == 0);
1910 testPath.SetFromUnknown(_T("http://testing special chars \344\366\374"));
1911 ATLASSERT(strcmp(testPath.GetGitApiPath(pool), "http://testing%20special%20chars%20%c3%a4%c3%b6%c3%bc") == 0);
1912 #endif
1915 void GetCommonRootTest()
1917 CTGitPath pathA (_T("C:\\Development\\LogDlg.cpp"));
1918 CTGitPath pathB (_T("C:\\Development\\LogDlg.h"));
1919 CTGitPath pathC (_T("C:\\Development\\SomeDir\\LogDlg.h"));
1921 CTGitPathList list;
1922 list.AddPath(pathA);
1923 ATLASSERT(list.GetCommonRoot().GetWinPathString().CompareNoCase(_T("C:\\Development\\LogDlg.cpp"))==0);
1924 list.AddPath(pathB);
1925 ATLASSERT(list.GetCommonRoot().GetWinPathString().CompareNoCase(_T("C:\\Development"))==0);
1926 list.AddPath(pathC);
1927 ATLASSERT(list.GetCommonRoot().GetWinPathString().CompareNoCase(_T("C:\\Development"))==0);
1928 #ifdef _MFC_VER
1929 list.Clear();
1930 CString sPathList = _T("D:\\Development\\StExBar\\StExBar\\src\\setup\\Setup64.wxs*D:\\Development\\StExBar\\StExBar\\src\\setup\\Setup.wxs*D:\\Development\\StExBar\\SKTimeStamp\\src\\setup\\Setup.wxs*D:\\Development\\StExBar\\SKTimeStamp\\src\\setup\\Setup64.wxs");
1931 list.LoadFromAsteriskSeparatedString(sPathList);
1932 ATLASSERT(list.GetCommonRoot().GetWinPathString().CompareNoCase(_T("D:\\Development\\StExBar"))==0);
1934 list.Clear();
1935 sPathList = _T("c:\\windows\\explorer.exe*c:\\windows");
1936 list.LoadFromAsteriskSeparatedString(sPathList);
1937 ATLASSERT(list.GetCommonRoot().GetWinPathString().CompareNoCase(_T("c:\\windows"))==0);
1939 list.Clear();
1940 sPathList = _T("c:\\windows\\*c:\\windows");
1941 list.LoadFromAsteriskSeparatedString(sPathList);
1942 ATLASSERT(list.GetCommonRoot().GetWinPathString().CompareNoCase(_T("c:\\windows"))==0);
1944 list.Clear();
1945 sPathList = _T("c:\\windows\\system32*c:\\windows\\system");
1946 list.LoadFromAsteriskSeparatedString(sPathList);
1947 ATLASSERT(list.GetCommonRoot().GetWinPathString().CompareNoCase(_T("c:\\windows"))==0);
1949 list.Clear();
1950 sPathList = _T("c:\\windowsdummy*c:\\windows");
1951 list.LoadFromAsteriskSeparatedString(sPathList);
1952 ATLASSERT(list.GetCommonRoot().GetWinPathString().CompareNoCase(_T("c:\\"))==0);
1953 #endif
1956 void ValidPathAndUrlTest()
1958 CTGitPath testPath;
1959 testPath.SetFromWin(_T("c:\\a\\b\\c.test.txt"));
1960 ATLASSERT(testPath.IsValidOnWindows());
1961 testPath.SetFromWin(_T("c:\\"));
1962 ATLASSERT(testPath.IsValidOnWindows());
1963 testPath.SetFromWin(_T("D:\\.Net\\SpindleSearch\\"));
1964 ATLASSERT(testPath.IsValidOnWindows());
1965 testPath.SetFromWin(_T("c"));
1966 ATLASSERT(testPath.IsValidOnWindows());
1967 testPath.SetFromWin(_T("c:\\test folder\\file"));
1968 ATLASSERT(testPath.IsValidOnWindows());
1969 testPath.SetFromWin(_T("c:\\folder\\"));
1970 ATLASSERT(testPath.IsValidOnWindows());
1971 testPath.SetFromWin(_T("c:\\ext.ext.ext\\ext.ext.ext.ext"));
1972 ATLASSERT(testPath.IsValidOnWindows());
1973 testPath.SetFromWin(_T("c:\\.svn"));
1974 ATLASSERT(testPath.IsValidOnWindows());
1975 testPath.SetFromWin(_T("c:\\com\\file"));
1976 ATLASSERT(testPath.IsValidOnWindows());
1977 testPath.SetFromWin(_T("c:\\test\\conf"));
1978 ATLASSERT(testPath.IsValidOnWindows());
1979 testPath.SetFromWin(_T("c:\\LPT"));
1980 ATLASSERT(testPath.IsValidOnWindows());
1981 testPath.SetFromWin(_T("c:\\test\\LPT"));
1982 ATLASSERT(testPath.IsValidOnWindows());
1983 testPath.SetFromWin(_T("c:\\com1test"));
1984 ATLASSERT(testPath.IsValidOnWindows());
1985 testPath.SetFromWin(_T("\\\\?\\c:\\test\\com1test"));
1986 ATLASSERT(testPath.IsValidOnWindows());
1988 testPath.SetFromWin(_T("\\\\Share\\filename"));
1989 ATLASSERT(testPath.IsValidOnWindows());
1990 testPath.SetFromWin(_T("\\\\Share\\filename.extension"));
1991 ATLASSERT(testPath.IsValidOnWindows());
1992 testPath.SetFromWin(_T("\\\\Share\\.svn"));
1993 ATLASSERT(testPath.IsValidOnWindows());
1995 // now the negative tests
1996 testPath.SetFromWin(_T("c:\\test:folder"));
1997 ATLASSERT(!testPath.IsValidOnWindows());
1998 testPath.SetFromWin(_T("c:\\file<name"));
1999 ATLASSERT(!testPath.IsValidOnWindows());
2000 testPath.SetFromWin(_T("c:\\something*else"));
2001 ATLASSERT(!testPath.IsValidOnWindows());
2002 testPath.SetFromWin(_T("c:\\folder\\file?nofile"));
2003 ATLASSERT(!testPath.IsValidOnWindows());
2004 testPath.SetFromWin(_T("c:\\ext.>ension"));
2005 ATLASSERT(!testPath.IsValidOnWindows());
2006 testPath.SetFromWin(_T("c:\\com1\\filename"));
2007 ATLASSERT(!testPath.IsValidOnWindows());
2008 testPath.SetFromWin(_T("c:\\com1"));
2009 ATLASSERT(!testPath.IsValidOnWindows());
2010 testPath.SetFromWin(_T("c:\\com1\\AuX"));
2011 ATLASSERT(!testPath.IsValidOnWindows());
2013 testPath.SetFromWin(_T("\\\\Share\\lpt9\\filename"));
2014 ATLASSERT(!testPath.IsValidOnWindows());
2015 testPath.SetFromWin(_T("\\\\Share\\prn"));
2016 ATLASSERT(!testPath.IsValidOnWindows());
2017 testPath.SetFromWin(_T("\\\\Share\\NUL"));
2018 ATLASSERT(!testPath.IsValidOnWindows());
2020 // now come some URL tests
2021 testPath.SetFromGit(_T("http://myserver.com/repos/trunk"));
2022 ATLASSERT(testPath.IsValidOnWindows());
2023 testPath.SetFromGit(_T("https://myserver.com/repos/trunk/file%20with%20spaces"));
2024 ATLASSERT(testPath.IsValidOnWindows());
2025 testPath.SetFromGit(_T("svn://myserver.com/repos/trunk/file with spaces"));
2026 ATLASSERT(testPath.IsValidOnWindows());
2027 testPath.SetFromGit(_T("svn+ssh://www.myserver.com/repos/trunk"));
2028 ATLASSERT(testPath.IsValidOnWindows());
2029 testPath.SetFromGit(_T("http://localhost:90/repos/trunk"));
2030 ATLASSERT(testPath.IsValidOnWindows());
2031 testPath.SetFromGit(_T("file:///C:/GitRepos/Tester/Proj1/tags/t2"));
2032 ATLASSERT(testPath.IsValidOnWindows());
2033 // and some negative URL tests
2034 testPath.SetFromGit(_T("httpp://myserver.com/repos/trunk"));
2035 ATLASSERT(!testPath.IsValidOnWindows());
2036 testPath.SetFromGit(_T("https://myserver.com/rep:os/trunk/file%20with%20spaces"));
2037 ATLASSERT(!testPath.IsValidOnWindows());
2038 testPath.SetFromGit(_T("svn://myserver.com/rep<os/trunk/file with spaces"));
2039 ATLASSERT(!testPath.IsValidOnWindows());
2040 testPath.SetFromGit(_T("svn+ssh://www.myserver.com/repos/trunk/prn/"));
2041 ATLASSERT(!testPath.IsValidOnWindows());
2042 testPath.SetFromGit(_T("http://localhost:90/repos/trunk/com1"));
2043 ATLASSERT(!testPath.IsValidOnWindows());
2047 } TGitPathTestobject;
2048 #endif
2049 #endif
2051 CTGitPath * CTGitPathList::LookForGitPath(CString path)
2053 int i=0;
2054 for(i=0;i<this->GetCount();i++)
2056 if((*this)[i].GetGitPathString() == path )
2057 return (CTGitPath*)&(*this)[i];
2059 return NULL;
2061 CString CTGitPath::GetActionName(int action)
2063 if(action & CTGitPath::LOGACTIONS_UNMERGED)
2064 return _T("Conflict");
2065 if(action & CTGitPath::LOGACTIONS_ADDED)
2066 return _T("Added");
2067 if(action & CTGitPath::LOGACTIONS_DELETED)
2068 return _T("Deleted");
2069 if(action & CTGitPath::LOGACTIONS_MERGED )
2070 return _T("Merged");
2072 if(action & CTGitPath::LOGACTIONS_MODIFIED)
2073 return _T("Modified");
2074 if(action & CTGitPath::LOGACTIONS_REPLACED)
2075 return _T("Rename");
2076 if(action & CTGitPath::LOGACTIONS_COPY)
2077 return _T("Copy");
2079 if(action & CTGitPath::LOGACTIONS_FORWORD )
2080 return _T("Forward");
2082 if(action & CTGitPath::LOGACTIONS_REBASE_EDIT)
2083 return _T("Edit");
2084 if(action & CTGitPath::LOGACTIONS_REBASE_SQUASH)
2085 return _T("Squash");
2086 if(action & CTGitPath::LOGACTIONS_REBASE_PICK)
2087 return _T("Pick");
2088 if(action & CTGitPath::LOGACTIONS_REBASE_SKIP)
2089 return _T("Skip");
2091 return _T("Unknown");
2093 CString CTGitPath::GetActionName()
2095 return GetActionName(m_Action);
2098 int CTGitPathList::GetAction()
2100 return m_Action;