Add virtual destructors
[TortoiseGit.git] / src / Git / Git.h
blob554dcda0241521e4ae38f3738d6fb69bf0b9bba9
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2016 - TortoiseGit
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #pragma once
21 #include "GitType.h"
22 #include "GitRev.h"
23 #include "GitStatus.h"
24 #include "GitAdminDir.h"
25 #include "gitdll.h"
26 #include <functional>
28 #define REG_MSYSGIT_PATH _T("Software\\TortoiseGit\\MSysGit")
29 #define REG_SYSTEM_GITCONFIGPATH _T("Software\\TortoiseGit\\SystemConfig")
30 #define REG_MSYSGIT_EXTRA_PATH _T("Software\\TortoiseGit\\MSysGitExtra")
32 #define DEFAULT_USE_LIBGIT2_MASK (1 << CGit::GIT_CMD_MERGE_BASE) | (1 << CGit::GIT_CMD_DELETETAGBRANCH) | (1 << CGit::GIT_CMD_GETONEFILE) | (1 << CGit::GIT_CMD_ADD) | (1 << CGit::GIT_CMD_CHECKCONFLICTS) | (1 << CGit::GIT_CMD_GET_COMMIT)
34 struct git_repository;
36 class CFilterData
38 public:
40 enum
42 SHOW_NO_LIMIT, // NOTE: no limitation does not mean "without all limitations", it's just without the following limitations. That say, the log still could be limited by auther, committer, etc.
43 SHOW_LAST_SEL_DATE,
44 SHOW_LAST_N_COMMITS,
45 SHOW_LAST_N_YEARS,
46 SHOW_LAST_N_MONTHS,
47 SHOW_LAST_N_WEEKS,
50 CFilterData()
52 m_From=m_To=-1;
53 m_IsRegex=1;
54 m_NumberOfLogsScale = SHOW_NO_LIMIT;
55 m_NumberOfLogs = 1;
58 DWORD m_NumberOfLogsScale;
59 DWORD m_NumberOfLogs;
60 __time64_t m_From;
61 __time64_t m_To;
62 CString m_Author;
63 CString m_Committer;
64 CString m_MessageFilter;
65 BOOL m_IsRegex;
68 class CGitCall
70 public:
71 CGitCall(){}
72 CGitCall(CString cmd):m_Cmd(cmd){}
73 virtual ~CGitCall() {}
75 CString GetCmd()const{return m_Cmd;}
76 void SetCmd(CString cmd){m_Cmd=cmd;}
78 //This function is called when command output data is available.
79 //When this function returns 'true' the git command should be aborted.
80 //This behavior is not implemented yet.
81 virtual bool OnOutputData(const BYTE* data, size_t size)=0;
82 virtual bool OnOutputErrData(const BYTE* data, size_t size)=0;
83 virtual void OnEnd(){}
85 private:
86 CString m_Cmd;
89 typedef std::function<void (const CStringA&)> GitReceiverFunc;
91 class CTGitPath;
92 class CEnvironment : protected std::vector<TCHAR>
94 public:
95 CEnvironment() : baseptr(nullptr) {}
96 CEnvironment(const CEnvironment& env) : std::vector<TCHAR>(env)
98 baseptr = &__super::at(0);
100 CEnvironment& operator =(const CEnvironment& env)
102 __super::operator=(env);
103 baseptr = &__super::at(0);
104 return *this;
106 void CopyProcessEnvironment();
107 CString GetEnv(const TCHAR *name);
108 void SetEnv(const TCHAR* name, const TCHAR* value);
109 void AddToPath(CString value);
110 void clear();
111 bool empty();
112 operator LPTSTR();
113 operator LPWSTR*();
114 LPWSTR baseptr;
115 CEnvironment(CEnvironment&& env) = delete;
116 CEnvironment& operator =(CEnvironment&& env) = delete;
118 class CGit
120 private:
121 CString gitLastErr;
122 protected:
123 GIT_DIFF m_GitDiff;
124 GIT_DIFF m_GitSimpleListDiff;
125 #ifdef GTEST_INCLUDE_GTEST_GTEST_H_
126 public:
127 #endif
128 bool m_IsGitDllInited;
129 public:
130 CComCriticalSection m_critGitDllSec;
131 bool m_IsUseGitDLL;
132 bool m_IsUseLibGit2;
133 DWORD m_IsUseLibGit2_mask;
135 CEnvironment m_Environment;
137 static BOOL GitPathFileExists(const CString &path)
139 if(path[0] == _T('\\') && path[1] == _T('\\'))
140 //it is netshare \\server\sharefoldername
141 // \\server\.git will create smb error log.
143 int length = path.GetLength();
145 if(length<2)
146 return false;
148 int start = path.Find(_T('\\'),2);
149 if(start<0)
150 return false;
152 start = path.Find(_T('\\'),start+1);
153 if(start<0)
154 return false;
156 return PathFileExists(path);
159 else
160 return PathFileExists(path);
162 void CheckAndInitDll()
164 if(!m_IsGitDllInited)
166 git_init();
167 m_IsGitDllInited=true;
171 GIT_DIFF GetGitDiff()
173 if(m_GitDiff)
174 return m_GitDiff;
175 else
177 git_open_diff(&m_GitDiff,"-C -M -r");
178 return m_GitDiff;
182 GIT_DIFF GetGitSimpleListDiff()
184 if(m_GitSimpleListDiff)
185 return m_GitSimpleListDiff;
186 else
188 git_open_diff(&m_GitSimpleListDiff,"-r -r");
189 return m_GitSimpleListDiff;
193 BOOL CheckMsysGitDir(BOOL bFallback = TRUE);
194 BOOL FindAndSetGitExePath(BOOL bFallback);
195 BOOL m_bInitialized;
197 typedef enum
199 GIT_CMD_CLONE,
200 GIT_CMD_FETCH,
201 GIT_CMD_COMMIT_UPDATE_INDEX,
202 GIT_CMD_DIFF,
203 GIT_CMD_RESET,
204 GIT_CMD_REVERT,
205 GIT_CMD_MERGE_BASE,
206 GIT_CMD_DELETETAGBRANCH,
207 GIT_CMD_GETONEFILE,
208 GIT_CMD_ADD,
209 GIT_CMD_PUSH,
210 GIT_CMD_CHECK_CLEAN_WT,
211 GIT_CMD_CHECKCONFLICTS,
212 GIT_CMD_GET_COMMIT,
213 GIT_CMD_LOGLISTDIFF,
214 } LIBGIT2_CMD;
215 bool UsingLibGit2(LIBGIT2_CMD cmd) const;
217 * callback type should be git_cred_acquire_cb
219 static void SetGit2CredentialCallback(void* callback);
220 static void SetGit2CertificateCheckCertificate(void* callback);
222 CString GetHomeDirectory() const;
223 CString GetGitLocalConfig() const;
224 CString GetGitGlobalConfig() const;
225 CString GetGitGlobalXDGConfigPath() const;
226 CString GetGitGlobalXDGConfig() const;
227 CString GetGitSystemConfig() const;
228 CString GetGitProgramDataConfig() const;
229 CAutoRepository GetGitRepository() const;
230 static CStringA GetGitPathStringA(const CString &path);
231 static CString ms_LastMsysGitDir; // the last msysgitdir added to the path, blank if none
232 static CString ms_MsysGitRootDir;
233 static int ms_LastMsysGitVersion;
234 static bool ms_bCygwinGit;
235 static bool ms_bMsys2Git;
236 static int m_LogEncode;
237 static bool IsBranchNameValid(const CString& branchname);
238 bool IsBranchTagNameUnique(const CString& name);
240 * Checks if a branch or tag with the given name exists
241 *isBranch is true -> branch, tag otherwise
243 bool BranchTagExists(const CString& name, bool isBranch = true);
244 unsigned int Hash2int(const CGitHash &hash);
246 PROCESS_INFORMATION m_CurrentGitPi;
248 CGit(void);
249 ~CGit(void);
251 int Run(CString cmd, CString* output, int code);
252 int Run(CString cmd, CString* output, CString* outputErr, int code);
253 int Run(CString cmd, BYTE_VECTOR* byte_array, BYTE_VECTOR* byte_arrayErr = nullptr);
254 int Run(CGitCall* pcall);
255 int Run(CString cmd, const GitReceiverFunc& recv, CString* outputErr = nullptr);
257 private:
258 static DWORD WINAPI AsyncReadStdErrThread(LPVOID lpParam);
259 typedef struct AsyncReadStdErrThreadArguments
261 HANDLE fileHandle;
262 CGitCall* pcall;
263 } ASYNCREADSTDERRTHREADARGS, *PASYNCREADSTDERRTHREADARGS;
264 CString GetUnifiedDiffCmd(const CTGitPath& path, const git_revnum_t& rev1, const git_revnum_t& rev2, bool bMerge, bool bCombine, int diffContext, bool bNoPrefix = false);
266 public:
267 int RunAsync(CString cmd, PROCESS_INFORMATION* pi, HANDLE* hRead, HANDLE* hErrReadOut, CString* StdioFile = nullptr);
268 int RunLogFile(CString cmd, const CString &filename, CString *stdErr);
270 int GetDiffPath(CTGitPathList* PathList, CGitHash* hash1, CGitHash* hash2, char* arg = nullptr);
272 int GetGitEncode(TCHAR* configkey);
274 bool IsFastForward(const CString& from, const CString& to, CGitHash* commonAncestor = nullptr);
275 CString GetConfigValue(const CString& name, const CString& def = CString(), bool wantBool = false);
276 bool GetConfigValueBool(const CString& name, const bool def = false);
277 int GetConfigValueInt32(const CString& name, const int def = 0);
279 int SetConfigValue(const CString& key, const CString& value, CONFIG_TYPE type = CONFIG_LOCAL);
280 int UnsetConfigValue(const CString& key, CONFIG_TYPE type = CONFIG_LOCAL);
282 CString GetUserName(void);
283 CString GetUserEmail(void);
284 CString GetCurrentBranch(bool fallback = false);
285 void GetRemoteTrackedBranch(const CString& localBranch, CString& remote, CString& branch);
286 void GetRemoteTrackedBranchForHEAD(CString& remote, CString& branch);
287 void GetRemotePushBranch(const CString& localBranch, CString& pushRemote, CString& pushBranch);
288 // read current branch name from HEAD file, returns 0 on success, -1 on failure, 1 detached (branch name "HEAD" returned)
289 static int GetCurrentBranchFromFile(const CString &sProjectRoot, CString &sBranchOut, bool fallback = false);
291 Use this method only when the HEAD is exist.
293 BOOL CheckCleanWorkTree(bool stagedOk = false);
294 int Revert(const CString& commit, const CTGitPathList &list, CString& err);
295 int Revert(const CString& commit, const CTGitPath &path, CString& err);
296 int DeleteRef(const CString& reference);
298 Use this method only if m_IsUseLibGit2 is used for fallbacks.
299 If you directly use libgit2 methods, use GetLibGit2LastErr instead.
301 CString GetGitLastErr(const CString& msg);
302 CString GetGitLastErr(const CString& msg, LIBGIT2_CMD cmd);
303 static CString GetLibGit2LastErr();
304 static CString GetLibGit2LastErr(const CString& msg);
305 bool SetCurrentDir(CString path, bool submodule = false)
307 bool b = GitAdminDir::HasAdminDir(path, submodule ? false : !!PathIsDirectory(path), &m_CurrentDir);
308 if (!b && GitAdminDir::IsBareRepo(path))
310 m_CurrentDir = path;
311 b = true;
313 if(m_CurrentDir.GetLength() == 2 && m_CurrentDir[1] == _T(':')) //C: D:
314 m_CurrentDir += _T('\\');
315 return b;
317 CString m_CurrentDir;
319 enum
321 LOG_ORDER_CHRONOLOGIALREVERSED,
322 LOG_ORDER_TOPOORDER,
323 LOG_ORDER_DATEORDER,
326 typedef enum
328 BRANCH_LOCAL = 0x1,
329 BRANCH_REMOTE = 0x2,
330 BRANCH_FETCH_HEAD = 0x4,
331 BRANCH_LOCAL_F = BRANCH_LOCAL | BRANCH_FETCH_HEAD,
332 BRANCH_ALL = BRANCH_LOCAL | BRANCH_REMOTE,
333 BRANCH_ALL_F = BRANCH_ALL | BRANCH_FETCH_HEAD,
334 }BRANCH_TYPE;
336 typedef enum
338 LOG_INFO_STAT=0x1,
339 LOG_INFO_FILESTATE=0x2,
340 LOG_INFO_PATCH=0x4,
341 LOG_INFO_FULLHISTORY=0x8,
342 LOG_INFO_BOUNDARY=0x10,
343 LOG_INFO_ALL_BRANCH=0x20,
344 LOG_INFO_ONLY_HASH=0x40,
345 LOG_INFO_DETECT_RENAME=0x80,
346 LOG_INFO_DETECT_COPYRENAME=0x100,
347 LOG_INFO_FIRST_PARENT = 0x200,
348 LOG_INFO_NO_MERGE = 0x400,
349 LOG_INFO_FOLLOW = 0x800,
350 LOG_INFO_SHOW_MERGEDFILE=0x1000,
351 LOG_INFO_FULL_DIFF = 0x2000,
352 LOG_INFO_SIMPILFY_BY_DECORATION = 0x4000,
353 LOG_INFO_LOCAL_BRANCHES = 0x8000,
354 LOG_INFO_BASIC_REFS = 0x10000,
355 }LOG_INFO_MASK;
357 typedef enum
359 LOCAL_BRANCH,
360 REMOTE_BRANCH,
361 ANNOTATED_TAG,
362 TAG,
363 STASH,
364 BISECT_GOOD,
365 BISECT_BAD,
366 NOTES,
367 UNKNOWN,
369 }REF_TYPE;
371 int GetRemoteList(STRING_VECTOR &list);
372 int GetBranchList(STRING_VECTOR &list, int *Current,BRANCH_TYPE type=BRANCH_LOCAL);
373 int GetTagList(STRING_VECTOR &list);
374 int GetRemoteTags(const CString& remote, STRING_VECTOR& list);
375 int DeleteRemoteRefs(const CString& remote, const STRING_VECTOR& list);
376 int GetBranchDescriptions(MAP_STRING_STRING& map);
377 int GetMapHashToFriendName(MAP_HASH_NAME &map);
378 static int GetMapHashToFriendName(git_repository* repo, MAP_HASH_NAME &map);
380 CString DerefFetchHead();
382 // FixBranchName():
383 // When branchName == FETCH_HEAD, derefrence it.
384 // A selected branch name got from GetBranchList(), with flag BRANCH_FETCH_HEAD enabled,
385 // should go through this function before it is used.
386 CString FixBranchName_Mod(CString& branchName);
387 CString FixBranchName(const CString& branchName);
389 CString GetLogCmd(const CString& range, const CTGitPath* path = nullptr, int InfoMask = LOG_INFO_FULL_DIFF | LOG_INFO_STAT | LOG_INFO_FILESTATE | LOG_INFO_BOUNDARY | LOG_INFO_DETECT_COPYRENAME | LOG_INFO_SHOW_MERGEDFILE, CFilterData* filter = nullptr);
391 int GetHash(CGitHash &hash, const CString& friendname);
392 static int GetHash(git_repository * repo, CGitHash &hash, const CString& friendname, bool skipFastCheck = false);
394 int BuildOutputFormat(CString &format,bool IsFull=TRUE);
395 static void StringAppend(CString *str, const BYTE *p, int code = CP_UTF8, int length = -1);
397 BOOL CanParseRev(CString ref);
399 Checks if HEAD points to an unborn branch
400 This method assumes, that we already know that we are in a working tree.
402 BOOL IsInitRepos();
403 /** Returns 0 if no conflict, if a conflict was found and -1 in case of a failure */
404 int HasWorkingTreeConflicts();
405 /** Returns 0 if no conflict, if a conflict was found and -1 in case of a failure */
406 int HasWorkingTreeConflicts(git_repository* repo);
407 int IsRebaseRunning();
408 void GetBisectTerms(CString* good, CString* bad);
409 int GetRefList(STRING_VECTOR &list);
411 int RefreshGitIndex();
412 int GetOneFile(const CString &Refname, const CTGitPath &path, const CString &outputfile);
414 //Example: master -> refs/heads/master
415 CString GetFullRefName(const CString& shortRefName);
416 //Removes 'refs/heads/' or just 'refs'. Example: refs/heads/master -> master
417 static CString StripRefName(CString refName);
419 int GetCommitDiffList(const CString &rev1, const CString &rev2, CTGitPathList &outpathlist, bool ignoreSpaceAtEol = false, bool ignoreSpaceChange = false, bool ignoreAllSpace = false, bool ignoreBlankLines = false);
420 int GetInitAddList(CTGitPathList &outpathlist);
421 int GetWorkingTreeChanges(CTGitPathList& result, bool amend = false, CTGitPathList* filterlist = nullptr);
423 static __int64 filetime_to_time_t(const FILETIME *ft)
425 long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
426 winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */
427 winTime /= 10000000; /* Nano to seconds resolution */
428 return (time_t)winTime;
431 static int GetFileModifyTime(LPCTSTR filename, __int64* time, bool* isDir = nullptr, __int64* size = nullptr)
433 WIN32_FILE_ATTRIBUTE_DATA fdata;
434 if (GetFileAttributesEx(filename, GetFileExInfoStandard, &fdata))
436 if(time)
437 *time = filetime_to_time_t(&fdata.ftLastWriteTime);
439 if (size)
440 *size = ((__int64)fdata.nFileSizeHigh << 32) + fdata.nFileSizeLow;
442 if(isDir)
443 *isDir = !!( fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
445 return 0;
447 return -1;
450 int GetShortHASHLength() const;
452 static BOOL GetShortName(const CString& ref, CString& shortname, const CString& prefix)
454 //TRACE(_T("%s %s\r\n"),ref,prefix);
455 if (ref.Left(prefix.GetLength()) == prefix)
457 shortname = ref.Right(ref.GetLength() - prefix.GetLength());
458 if (shortname.Right(3) == _T("^{}"))
459 shortname=shortname.Left(shortname.GetLength() - 3);
460 return TRUE;
462 return FALSE;
465 static CString GetShortName(const CString& ref, REF_TYPE *type);
467 static bool LoadTextFile(const CString &filename, CString &msg);
469 int GetUnifiedDiff(const CTGitPath& path, const git_revnum_t& rev1, const git_revnum_t& rev2, CString patchfile, bool bMerge, bool bCombine, int diffContext, bool bNoPrefix = false);
470 int GetUnifiedDiff(const CTGitPath& path, const git_revnum_t& rev1, const git_revnum_t& rev2, CStringA * buffer, bool bMerge, bool bCombine, int diffContext);
472 int GitRevert(int parent, const CGitHash &hash);
474 int GetGitVersion(CString* versiondebug, CString* errStr);
476 CString CombinePath(const CString &path) const
478 if (path.IsEmpty())
479 return m_CurrentDir;
480 if (m_CurrentDir.IsEmpty())
481 return path;
482 return m_CurrentDir + (m_CurrentDir.Right(1) == _T("\\") ? _T("") : _T("\\")) + path;
485 CString CombinePath(const CTGitPath &path) const
487 return CombinePath(path.GetWinPath());
490 CString CombinePath(const CTGitPath *path) const
492 ATLASSERT(path);
493 return CombinePath(path->GetWinPath());
496 extern void GetTempPath(CString &path);
497 extern CString GetTempFile();
498 extern DWORD GetTortoiseGitTempPath(DWORD nBufferLength, LPTSTR lpBuffer);
500 extern CGit g_Git;