Optimize PATH handling in CEnvironment
[TortoiseGit.git] / src / Git / Git.h
blobe3c76e2401c6f5d69ec3dac66b27b704f4788eef
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2015 - 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_MSYSGIT_EXTRA_PATH _T("Software\\TortoiseGit\\MSysGitExtra")
31 #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)
33 struct git_repository;
35 class CFilterData
37 public:
38 CFilterData()
40 m_From=m_To=-1;
41 m_IsRegex=1;
43 __time64_t m_From;
44 __time64_t m_To;
45 CString m_Author;
46 CString m_Committer;
47 CString m_MessageFilter;
48 BOOL m_IsRegex;
51 class CGitCall
53 public:
54 CGitCall(){}
55 CGitCall(CString cmd):m_Cmd(cmd){}
57 CString GetCmd()const{return m_Cmd;}
58 void SetCmd(CString cmd){m_Cmd=cmd;}
60 //This function is called when command output data is available.
61 //When this function returns 'true' the git command should be aborted.
62 //This behavior is not implemented yet.
63 virtual bool OnOutputData(const BYTE* data, size_t size)=0;
64 virtual bool OnOutputErrData(const BYTE* data, size_t size)=0;
65 virtual void OnEnd(){}
67 private:
68 CString m_Cmd;
71 typedef std::function<void (const CStringA&)> GitReceiverFunc;
73 class CTGitPath;
74 class CEnvironment : protected std::vector<TCHAR>
76 public:
77 void CopyProcessEnvironment();
78 CString GetEnv(const TCHAR *name);
79 void SetEnv(const TCHAR* name, const TCHAR* value);
80 void AddToPath(CString value);
81 void clear();
82 bool empty();
83 operator LPTSTR();
85 class CGit
87 private:
88 CString gitLastErr;
89 protected:
90 GIT_DIFF m_GitDiff;
91 GIT_DIFF m_GitSimpleListDiff;
92 #ifdef GTEST_INCLUDE_GTEST_GTEST_H_
93 public:
94 #endif
95 bool m_IsGitDllInited;
96 public:
97 CComCriticalSection m_critGitDllSec;
98 bool m_IsUseGitDLL;
99 bool m_IsUseLibGit2;
100 DWORD m_IsUseLibGit2_mask;
102 CEnvironment m_Environment;
104 static BOOL GitPathFileExists(const CString &path)
106 if(path[0] == _T('\\') && path[1] == _T('\\'))
107 //it is netshare \\server\sharefoldername
108 // \\server\.git will create smb error log.
110 int length = path.GetLength();
112 if(length<2)
113 return false;
115 int start = path.Find(_T('\\'),2);
116 if(start<0)
117 return false;
119 start = path.Find(_T('\\'),start+1);
120 if(start<0)
121 return false;
123 return PathFileExists(path);
126 else
127 return PathFileExists(path);
129 void CheckAndInitDll()
131 if(!m_IsGitDllInited)
133 git_init();
134 m_IsGitDllInited=true;
138 GIT_DIFF GetGitDiff()
140 if(m_GitDiff)
141 return m_GitDiff;
142 else
144 git_open_diff(&m_GitDiff,"-C -M -r");
145 return m_GitDiff;
149 GIT_DIFF GetGitSimpleListDiff()
151 if(m_GitSimpleListDiff)
152 return m_GitSimpleListDiff;
153 else
155 git_open_diff(&m_GitSimpleListDiff,"-r -r");
156 return m_GitSimpleListDiff;
160 BOOL CheckMsysGitDir(BOOL bFallback = TRUE);
161 BOOL FindAndSetGitExePath(BOOL bFallback);
162 BOOL m_bInitialized;
164 typedef enum
166 GIT_CMD_CLONE,
167 GIT_CMD_FETCH,
168 GIT_CMD_COMMIT_UPDATE_INDEX,
169 GIT_CMD_DIFF,
170 GIT_CMD_RESET,
171 GIT_CMD_REVERT,
172 GIT_CMD_MERGE_BASE,
173 GIT_CMD_DELETETAGBRANCH,
174 GIT_CMD_GETONEFILE,
175 GIT_CMD_ADD,
176 GIT_CMD_PUSH,
177 GIT_CMD_CHECK_CLEAN_WT,
178 GIT_CMD_CHECKCONFLICTS,
179 GIT_CMD_GET_COMMIT,
180 GIT_CMD_LOGLISTDIFF,
181 } LIBGIT2_CMD;
182 bool UsingLibGit2(LIBGIT2_CMD cmd) const;
184 * callback type should be git_cred_acquire_cb
186 static void SetGit2CredentialCallback(void* callback);
187 static void SetGit2CertificateCheckCertificate(void* callback);
189 CString GetHomeDirectory() const;
190 CString GetGitLocalConfig() const;
191 CString GetGitGlobalConfig() const;
192 CString GetGitGlobalXDGConfigPath() const;
193 CString GetGitGlobalXDGConfig() const;
194 CString GetGitSystemConfig() const;
195 git_repository * GetGitRepository() const;
196 static CStringA GetGitPathStringA(const CString &path);
197 static CString ms_LastMsysGitDir; // the last msysgitdir added to the path, blank if none
198 static int ms_LastMsysGitVersion;
199 static bool ms_bCygwinGit;
200 static int m_LogEncode;
201 static bool IsBranchNameValid(const CString& branchname);
202 bool IsBranchTagNameUnique(const CString& name);
204 * Checks if a branch or tag with the given name exists
205 *isBranch is true -> branch, tag otherwise
207 bool BranchTagExists(const CString& name, bool isBranch = true);
208 unsigned int Hash2int(const CGitHash &hash);
210 PROCESS_INFORMATION m_CurrentGitPi;
212 CGit(void);
213 ~CGit(void);
215 int Run(CString cmd, CString* output, int code);
216 int Run(CString cmd, CString* output, CString* outputErr, int code);
217 int Run(CString cmd, BYTE_VECTOR *byte_array, BYTE_VECTOR *byte_arrayErr = NULL);
218 int Run(CGitCall* pcall);
219 int Run(CString cmd, const GitReceiverFunc& recv);
221 private:
222 static DWORD WINAPI AsyncReadStdErrThread(LPVOID lpParam);
223 typedef struct AsyncReadStdErrThreadArguments
225 HANDLE fileHandle;
226 CGitCall* pcall;
227 } ASYNCREADSTDERRTHREADARGS, *PASYNCREADSTDERRTHREADARGS;
228 CString GetUnifiedDiffCmd(const CTGitPath& path, const git_revnum_t& rev1, const git_revnum_t& rev2, bool bMerge, bool bCombine, int diffContext);
230 public:
231 int RunAsync(CString cmd, PROCESS_INFORMATION *pi, HANDLE* hRead, HANDLE *hErrReadOut, CString *StdioFile = NULL);
232 int RunLogFile(CString cmd, const CString &filename, CString *stdErr);
234 int GetDiffPath(CTGitPathList *PathList, CGitHash *hash1, CGitHash *hash2, char *arg=NULL);
236 int GetGitEncode(TCHAR* configkey);
238 bool IsFastForward(const CString &from, const CString &to, CGitHash * commonAncestor = NULL);
239 CString GetConfigValue(const CString& name);
240 bool GetConfigValueBool(const CString& name);
241 int GetConfigValueInt32(const CString& name, int def = 0);
243 int SetConfigValue(const CString& key, const CString& value, CONFIG_TYPE type = CONFIG_LOCAL);
244 int UnsetConfigValue(const CString& key, CONFIG_TYPE type = CONFIG_LOCAL);
246 CString GetUserName(void);
247 CString GetUserEmail(void);
248 CString GetCurrentBranch(bool fallback = false);
249 void GetRemoteTrackedBranch(const CString& localBranch, CString& remote, CString& branch);
250 void GetRemoteTrackedBranchForHEAD(CString& remote, CString& branch);
251 // read current branch name from HEAD file, returns 0 on success, -1 on failure, 1 detached (branch name "HEAD" returned)
252 static int GetCurrentBranchFromFile(const CString &sProjectRoot, CString &sBranchOut, bool fallback = false);
254 Use this method only when the HEAD is exist.
256 BOOL CheckCleanWorkTree(bool stagedOk = false);
257 int Revert(const CString& commit, const CTGitPathList &list, CString& err);
258 int Revert(const CString& commit, const CTGitPath &path, CString& err);
259 int DeleteRef(const CString& reference);
261 Use this method only if m_IsUseLibGit2 is used for fallbacks.
262 If you directly use libgit2 methods, use GetLibGit2LastErr instead.
264 CString GetGitLastErr(const CString& msg);
265 CString GetGitLastErr(const CString& msg, LIBGIT2_CMD cmd);
266 static CString GetLibGit2LastErr();
267 static CString GetLibGit2LastErr(const CString& msg);
268 bool SetCurrentDir(CString path, bool submodule = false)
270 bool b = GitAdminDir::HasAdminDir(path, submodule ? false : !!PathIsDirectory(path), &m_CurrentDir);
271 if (!b && GitAdminDir::IsBareRepo(path))
273 m_CurrentDir = path;
274 b = true;
276 if(m_CurrentDir.GetLength() == 2 && m_CurrentDir[1] == _T(':')) //C: D:
278 m_CurrentDir += _T('\\');
280 return b;
282 CString m_CurrentDir;
284 enum
286 LOG_ORDER_CHRONOLOGIALREVERSED,
287 LOG_ORDER_TOPOORDER,
288 LOG_ORDER_DATEORDER,
291 typedef enum
293 BRANCH_LOCAL = 0x1,
294 BRANCH_REMOTE = 0x2,
295 BRANCH_FETCH_HEAD = 0x4,
296 BRANCH_LOCAL_F = BRANCH_LOCAL | BRANCH_FETCH_HEAD,
297 BRANCH_ALL = BRANCH_LOCAL | BRANCH_REMOTE,
298 BRANCH_ALL_F = BRANCH_ALL | BRANCH_FETCH_HEAD,
299 }BRANCH_TYPE;
301 typedef enum
303 LOG_INFO_STAT=0x1,
304 LOG_INFO_FILESTATE=0x2,
305 LOG_INFO_PATCH=0x4,
306 LOG_INFO_FULLHISTORY=0x8,
307 LOG_INFO_BOUNDARY=0x10,
308 LOG_INFO_ALL_BRANCH=0x20,
309 LOG_INFO_ONLY_HASH=0x40,
310 LOG_INFO_DETECT_RENAME=0x80,
311 LOG_INFO_DETECT_COPYRENAME=0x100,
312 LOG_INFO_FIRST_PARENT = 0x200,
313 LOG_INFO_NO_MERGE = 0x400,
314 LOG_INFO_FOLLOW = 0x800,
315 LOG_INFO_SHOW_MERGEDFILE=0x1000,
316 LOG_INFO_FULL_DIFF = 0x2000,
317 LOG_INFO_SIMPILFY_BY_DECORATION = 0x4000,
318 LOG_INFO_LOCAL_BRANCHES = 0x8000,
319 }LOG_INFO_MASK;
321 typedef enum
323 LOCAL_BRANCH,
324 REMOTE_BRANCH,
325 TAG,
326 STASH,
327 BISECT_GOOD,
328 BISECT_BAD,
329 NOTES,
330 UNKNOWN,
332 }REF_TYPE;
334 int GetRemoteList(STRING_VECTOR &list);
335 int GetBranchList(STRING_VECTOR &list, int *Current,BRANCH_TYPE type=BRANCH_LOCAL);
336 int GetTagList(STRING_VECTOR &list);
337 int GetRemoteTags(const CString& remote, STRING_VECTOR& list);
338 int DeleteRemoteRefs(const CString& remote, const STRING_VECTOR& list);
339 int GetBranchDescriptions(MAP_STRING_STRING& map);
340 int GetMapHashToFriendName(MAP_HASH_NAME &map);
341 static int GetMapHashToFriendName(git_repository* repo, MAP_HASH_NAME &map);
343 CString DerefFetchHead();
345 // FixBranchName():
346 // When branchName == FETCH_HEAD, derefrence it.
347 // A selected branch name got from GetBranchList(), with flag BRANCH_FETCH_HEAD enabled,
348 // should go through this function before it is used.
349 CString FixBranchName_Mod(CString& branchName);
350 CString FixBranchName(const CString& branchName);
352 CString GetLogCmd(const CString &range, const CTGitPath *path = NULL, int count=-1, int InfoMask = LOG_INFO_FULL_DIFF|LOG_INFO_STAT|LOG_INFO_FILESTATE|LOG_INFO_BOUNDARY|LOG_INFO_DETECT_COPYRENAME|LOG_INFO_SHOW_MERGEDFILE, bool paramonly=false, CFilterData * filter =NULL);
354 int GetHash(CGitHash &hash, const CString& friendname);
355 static int GetHash(git_repository * repo, CGitHash &hash, const CString& friendname, bool skipFastCheck = false);
357 int BuildOutputFormat(CString &format,bool IsFull=TRUE);
358 static void StringAppend(CString *str, const BYTE *p, int code = CP_UTF8, int length = -1);
360 BOOL CanParseRev(CString ref);
362 Checks if HEAD points to an unborn branch
363 This method assumes, that we already know that we are in a working tree.
365 BOOL IsInitRepos();
366 /** Returns 0 if no conflict, if a conflict was found and -1 in case of a failure */
367 int HasWorkingTreeConflicts();
368 /** Returns 0 if no conflict, if a conflict was found and -1 in case of a failure */
369 int HasWorkingTreeConflicts(git_repository* repo);
370 int GetRefList(STRING_VECTOR &list);
372 int RefreshGitIndex();
373 int GetOneFile(const CString &Refname, const CTGitPath &path, const CString &outputfile);
375 //Example: master -> refs/heads/master
376 CString GetFullRefName(const CString& shortRefName);
377 //Removes 'refs/heads/' or just 'refs'. Example: refs/heads/master -> master
378 static CString StripRefName(CString refName);
380 int GetCommitDiffList(const CString &rev1, const CString &rev2, CTGitPathList &outpathlist, bool ignoreSpaceAtEol = false, bool ignoreSpaceChange = false, bool ignoreAllSpace = false, bool ignoreBlankLines = false);
381 int GetInitAddList(CTGitPathList &outpathlist);
382 int GetWorkingTreeChanges(CTGitPathList& result, bool amend = false, CTGitPathList* filterlist = nullptr);
384 __int64 filetime_to_time_t(const FILETIME *ft)
386 long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
387 winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */
388 winTime /= 10000000; /* Nano to seconds resolution */
389 return (time_t)winTime;
392 int GetFileModifyTime(LPCTSTR filename, __int64* time, bool* isDir = nullptr, __int64* size = nullptr)
394 WIN32_FILE_ATTRIBUTE_DATA fdata;
395 if (GetFileAttributesEx(filename, GetFileExInfoStandard, &fdata))
397 if(time)
398 *time = filetime_to_time_t(&fdata.ftLastWriteTime);
400 if (size)
401 *size = ((__int64)fdata.nFileSizeHigh << 32) + fdata.nFileSizeLow;
403 if(isDir)
404 *isDir = !!( fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
406 return 0;
408 return -1;
411 int GetShortHASHLength() const;
413 static BOOL GetShortName(const CString &ref, CString &shortname, CString prefix)
415 //TRACE(_T("%s %s\r\n"),ref,prefix);
416 if (ref.Left(prefix.GetLength()) == prefix)
418 shortname = ref.Right(ref.GetLength() - prefix.GetLength());
419 if (shortname.Right(3) == _T("^{}"))
420 shortname=shortname.Left(shortname.GetLength() - 3);
421 return TRUE;
423 return FALSE;
426 static CString GetShortName(const CString& ref, REF_TYPE *type);
428 static bool LoadTextFile(const CString &filename, CString &msg);
430 int GetUnifiedDiff(const CTGitPath& path, const git_revnum_t& rev1, const git_revnum_t& rev2, CString patchfile, bool bMerge, bool bCombine, int diffContext);
431 int GetUnifiedDiff(const CTGitPath& path, const git_revnum_t& rev1, const git_revnum_t& rev2, CStringA * buffer, bool bMerge, bool bCombine, int diffContext);
433 int GitRevert(int parent, const CGitHash &hash);
435 CString CombinePath(const CString &path) const
437 if (path.IsEmpty())
438 return m_CurrentDir;
439 if (m_CurrentDir.IsEmpty())
440 return path;
441 return m_CurrentDir + (m_CurrentDir.Right(1) == _T("\\") ? _T("") : _T("\\")) + path;
444 CString CombinePath(const CTGitPath &path) const
446 return CombinePath(path.GetWinPath());
449 CString CombinePath(const CTGitPath *path) const
451 ATLASSERT(path);
452 return CombinePath(path->GetWinPath());
455 extern void GetTempPath(CString &path);
456 extern CString GetTempFile();
457 extern DWORD GetTortoiseGitTempPath(DWORD nBufferLength, LPTSTR lpBuffer);
459 extern CGit g_Git;