Do not always include staged files
[TortoiseGit.git] / src / Git / Git.h
blob5b985b279e579b47bed13bf0711ede1fc694122d
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2018 - 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 "TGitPath.h"
22 #include "gittype.h"
23 #include "GitAdminDir.h"
24 #include "gitdll.h"
25 #include <functional>
26 #include "StringUtils.h"
27 #include "PathUtils.h"
29 #define REG_MSYSGIT_PATH L"Software\\TortoiseGit\\MSysGit"
30 #define REG_SYSTEM_GITCONFIGPATH L"Software\\TortoiseGit\\SystemConfig"
31 #define REG_MSYSGIT_EXTRA_PATH L"Software\\TortoiseGit\\MSysGitExtra"
33 #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)
35 struct git_repository;
37 constexpr static inline int ConvertVersionToInt(unsigned __int8 major, unsigned __int8 minor, unsigned __int8 patchlevel, unsigned __int8 build = 0)
39 return (major << 24) + (minor << 16) + (patchlevel << 8) + build;
42 class CFilterData
44 public:
46 enum
48 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 author, committer, etc.
49 SHOW_LAST_SEL_DATE,
50 SHOW_LAST_N_COMMITS,
51 SHOW_LAST_N_YEARS,
52 SHOW_LAST_N_MONTHS,
53 SHOW_LAST_N_WEEKS,
56 CFilterData()
58 m_From=m_To=-1;
59 m_NumberOfLogsScale = SHOW_NO_LIMIT;
60 m_NumberOfLogs = 1;
63 DWORD m_NumberOfLogsScale;
64 DWORD m_NumberOfLogs;
65 __time64_t m_From;
66 __time64_t m_To;
69 class CGitCall
71 public:
72 CGitCall(){}
73 CGitCall(CString cmd):m_Cmd(cmd){}
74 virtual ~CGitCall() {}
76 CString GetCmd()const{return m_Cmd;}
77 void SetCmd(CString cmd){m_Cmd=cmd;}
79 //This function is called when command output data is available.
80 //When this function returns 'true' the git command should be aborted.
81 //This behavior is not implemented yet.
82 virtual bool OnOutputData(const BYTE* data, size_t size)=0;
83 virtual bool OnOutputErrData(const BYTE* data, size_t size)=0;
84 virtual void OnEnd(){}
86 private:
87 CString m_Cmd;
90 typedef std::function<void (const CStringA&)> GitReceiverFunc;
92 class CEnvironment : protected std::vector<TCHAR>
94 public:
95 CEnvironment() : baseptr(nullptr) {}
96 CEnvironment(const CEnvironment& env) : std::vector<TCHAR>(env)
98 baseptr = data();
100 CEnvironment& operator =(const CEnvironment& env)
102 __super::operator=(env);
103 if (empty())
104 baseptr = nullptr;
105 else
106 baseptr = data();
107 return *this;
109 void CopyProcessEnvironment();
110 CString GetEnv(const TCHAR *name);
111 void SetEnv(const TCHAR* name, const TCHAR* value);
112 void AddToPath(CString value);
113 void clear();
114 bool empty();
115 operator LPTSTR();
116 operator LPWSTR*();
117 LPWSTR baseptr;
118 CEnvironment(CEnvironment&& env) = delete;
119 CEnvironment& operator =(CEnvironment&& env) = delete;
121 class CGit
123 private:
124 CString gitLastErr;
125 protected:
126 GIT_DIFF m_GitDiff;
127 GIT_DIFF m_GitSimpleListDiff;
128 #ifdef GTEST_INCLUDE_GTEST_GTEST_H_
129 public:
130 #endif
131 bool m_IsGitDllInited;
132 public:
133 CComCriticalSection m_critGitDllSec;
134 bool m_IsUseGitDLL;
135 bool m_IsUseLibGit2;
136 DWORD m_IsUseLibGit2_mask;
138 CEnvironment m_Environment;
140 static BOOL GitPathFileExists(const CString &path)
142 if (path[0] == L'\\' && path[1] == L'\\')
143 //it is netshare \\server\sharefoldername
144 // \\server\.git will create smb error log.
146 int length = path.GetLength();
148 if(length<2)
149 return false;
151 int start = path.Find(L'\\', 2);
152 if(start<0)
153 return false;
155 start = path.Find(L'\\', start + 1);
156 if(start<0)
157 return false;
159 return PathFileExists(path);
162 else
163 return PathFileExists(path);
165 void CheckAndInitDll()
167 if(!m_IsGitDllInited)
169 git_init();
170 m_IsGitDllInited=true;
174 GIT_DIFF GetGitDiff()
176 if(m_GitDiff)
177 return m_GitDiff;
178 else
180 // cf. GitRevLoglist::SafeFetchFullInfo
181 CStringA params;
182 params.Format("-C%d%% -M%d%% -r", ms_iSimilarityIndexThreshold, ms_iSimilarityIndexThreshold);
183 git_open_diff(&m_GitDiff, params);
184 return m_GitDiff;
188 GIT_DIFF GetGitSimpleListDiff()
190 if(m_GitSimpleListDiff)
191 return m_GitSimpleListDiff;
192 else
194 git_open_diff(&m_GitSimpleListDiff, "-r");
195 return m_GitSimpleListDiff;
199 BOOL CheckMsysGitDir(BOOL bFallback = TRUE);
200 BOOL FindAndSetGitExePath(BOOL bFallback);
201 BOOL m_bInitialized;
203 typedef enum
205 GIT_CMD_CLONE,
206 GIT_CMD_FETCH,
207 GIT_CMD_COMMIT_UPDATE_INDEX,
208 GIT_CMD_DIFF,
209 GIT_CMD_RESET,
210 GIT_CMD_REVERT,
211 GIT_CMD_MERGE_BASE,
212 GIT_CMD_DELETETAGBRANCH,
213 GIT_CMD_GETONEFILE,
214 GIT_CMD_ADD,
215 GIT_CMD_PUSH,
216 GIT_CMD_CHECK_CLEAN_WT,
217 GIT_CMD_CHECKCONFLICTS,
218 GIT_CMD_GET_COMMIT,
219 GIT_CMD_LOGLISTDIFF,
220 } LIBGIT2_CMD;
221 bool UsingLibGit2(LIBGIT2_CMD cmd) const;
223 * callback type should be git_cred_acquire_cb
225 static void SetGit2CredentialCallback(void* callback);
226 static void SetGit2CertificateCheckCertificate(void* callback);
228 CString GetHomeDirectory() const;
229 CString GetGitLocalConfig() const;
230 CString GetGitGlobalConfig() const;
231 CString GetGitGlobalXDGConfigPath() const;
232 CString GetGitGlobalXDGConfig() const;
233 CString GetGitSystemConfig() const;
234 CString GetGitProgramDataConfig() const;
235 CAutoRepository GetGitRepository() const;
236 static CStringA GetGitPathStringA(const CString &path);
237 static CString ms_LastMsysGitDir; // the last msysgitdir added to the path, blank if none
238 static CString ms_MsysGitRootDir;
239 static int ms_LastMsysGitVersion;
240 static bool ms_bCygwinGit;
241 static bool ms_bMsys2Git;
242 static int ms_iSimilarityIndexThreshold;
243 static int m_LogEncode;
244 static bool IsBranchNameValid(const CString& branchname);
245 bool IsLocalBranch(const CString& shortName);
246 bool IsBranchTagNameUnique(const CString& name);
248 * Checks if a branch or tag with the given name exists
249 *isBranch is true -> branch, tag otherwise
251 bool BranchTagExists(const CString& name, bool isBranch = true);
252 unsigned int Hash2int(const CGitHash &hash);
254 PROCESS_INFORMATION m_CurrentGitPi;
256 CGit(void);
257 ~CGit(void);
259 int Run(CString cmd, CString* output, int code);
260 int Run(CString cmd, CString* output, CString* outputErr, int code);
261 int Run(CString cmd, BYTE_VECTOR* byte_array, BYTE_VECTOR* byte_arrayErr = nullptr);
262 int Run(CGitCall* pcall);
263 int Run(CString cmd, const GitReceiverFunc& recv, CString* outputErr = nullptr);
265 private:
266 CComCriticalSection m_critSecThreadMap;
267 std::map<DWORD, HANDLE> m_AsyncReadStdErrThreadMap;
268 static DWORD WINAPI AsyncReadStdErrThread(LPVOID lpParam);
269 typedef struct AsyncReadStdErrThreadArguments
271 HANDLE fileHandle;
272 CGitCall* pcall;
273 } ASYNCREADSTDERRTHREADARGS, *PASYNCREADSTDERRTHREADARGS;
274 CString GetUnifiedDiffCmd(const CTGitPath& path, const CString& rev1, const CString& rev2, bool bMerge, bool bCombine, int diffContext, bool bNoPrefix = false);
276 public:
277 #ifdef _MFC_VER
278 void KillRelatedThreads(CWinThread* thread);
279 #endif
280 int RunAsync(CString cmd, PROCESS_INFORMATION* pi, HANDLE* hRead, HANDLE* hErrReadOut, const CString* StdioFile = nullptr);
281 int RunLogFile(CString cmd, const CString &filename, CString *stdErr);
283 int GetGitEncode(TCHAR* configkey);
285 bool IsFastForward(const CString& from, const CString& to, CGitHash* commonAncestor = nullptr);
286 CString GetConfigValue(const CString& name, const CString& def = CString(), bool wantBool = false);
287 bool GetConfigValueBool(const CString& name, const bool def = false);
288 int GetConfigValueInt32(const CString& name, const int def = 0);
290 int SetConfigValue(const CString& key, const CString& value, CONFIG_TYPE type = CONFIG_LOCAL);
291 int UnsetConfigValue(const CString& key, CONFIG_TYPE type = CONFIG_LOCAL);
293 CString GetUserName(void);
294 CString GetUserEmail(void);
295 CString GetCurrentBranch(bool fallback = false);
296 void GetRemoteTrackedBranch(const CString& localBranch, CString& remote, CString& branch);
297 void GetRemoteTrackedBranchForHEAD(CString& remote, CString& branch);
298 void GetRemotePushBranch(const CString& localBranch, CString& pushRemote, CString& pushBranch);
299 // read current branch name from HEAD file, returns 0 on success, -1 on failure, 1 detached (branch name "HEAD" returned)
300 static int GetCurrentBranchFromFile(const CString &sProjectRoot, CString &sBranchOut, bool fallback = false);
302 Use this method only when the HEAD is exist.
304 BOOL CheckCleanWorkTree(bool stagedOk = false);
305 int Revert(const CString& commit, const CTGitPathList &list, CString& err);
306 int Revert(const CString& commit, const CTGitPath &path, CString& err);
307 int DeleteRef(const CString& reference);
309 Use this method only if m_IsUseLibGit2 is used for fallbacks.
310 If you directly use libgit2 methods, use GetLibGit2LastErr instead.
312 CString GetGitLastErr(const CString& msg);
313 CString GetGitLastErr(const CString& msg, LIBGIT2_CMD cmd);
314 static CString GetLibGit2LastErr();
315 static CString GetLibGit2LastErr(const CString& msg);
316 bool SetCurrentDir(CString path, bool submodule = false)
318 bool b = GitAdminDir::HasAdminDir(path, submodule ? false : !!PathIsDirectory(path), &m_CurrentDir);
319 if (!b && GitAdminDir::IsBareRepo(path))
321 m_CurrentDir = path;
322 b = true;
324 if (m_CurrentDir.GetLength() == 2 && m_CurrentDir[1] == L':') //C: D:
325 m_CurrentDir += L'\\';
327 return b;
329 CString m_CurrentDir;
331 enum
333 LOG_ORDER_CHRONOLOGIALREVERSED,
334 LOG_ORDER_TOPOORDER,
335 LOG_ORDER_DATEORDER,
338 typedef enum
340 BRANCH_LOCAL = 0x1,
341 BRANCH_REMOTE = 0x2,
342 BRANCH_FETCH_HEAD = 0x4,
343 BRANCH_LOCAL_F = BRANCH_LOCAL | BRANCH_FETCH_HEAD,
344 BRANCH_ALL = BRANCH_LOCAL | BRANCH_REMOTE,
345 BRANCH_ALL_F = BRANCH_ALL | BRANCH_FETCH_HEAD,
346 }BRANCH_TYPE;
348 typedef enum
350 LOG_INFO_STAT=0x1,
351 LOG_INFO_FILESTATE=0x2,
352 LOG_INFO_BOUNDARY=0x10,
353 LOG_INFO_ALL_BRANCH=0x20,
354 LOG_INFO_ONLY_HASH=0x40,
355 LOG_INFO_DETECT_RENAME=0x80,
356 LOG_INFO_DETECT_COPYRENAME=0x100,
357 LOG_INFO_FIRST_PARENT = 0x200,
358 LOG_INFO_NO_MERGE = 0x400,
359 LOG_INFO_FOLLOW = 0x800,
360 LOG_INFO_SHOW_MERGEDFILE=0x1000,
361 LOG_INFO_FULL_DIFF = 0x2000,
362 LOG_INFO_SIMPILFY_BY_DECORATION = 0x4000,
363 LOG_INFO_LOCAL_BRANCHES = 0x8000,
364 LOG_INFO_BASIC_REFS = 0x10000,
365 }LOG_INFO_MASK;
367 typedef enum
369 LOCAL_BRANCH,
370 REMOTE_BRANCH,
371 ANNOTATED_TAG,
372 TAG,
373 STASH,
374 BISECT_GOOD,
375 BISECT_BAD,
376 BISECT_SKIP,
377 NOTES,
378 UNKNOWN,
380 }REF_TYPE;
382 int GetRemoteList(STRING_VECTOR &list);
383 int GetBranchList(STRING_VECTOR& list, int* current, BRANCH_TYPE type = BRANCH_LOCAL, bool skipCurrent = false);
384 int GetTagList(STRING_VECTOR &list);
385 int GetRefsCommitIsOn(STRING_VECTOR& list, const CGitHash& hash, bool includeTags, bool includeBranches, BRANCH_TYPE type = BRANCH_LOCAL);
386 int GetRemoteTags(const CString& remote, REF_VECTOR& list);
387 int DeleteRemoteRefs(const CString& remote, const STRING_VECTOR& list);
388 int GetBranchDescriptions(MAP_STRING_STRING& map);
389 int GuessRefForHash(CString& ref, const CGitHash& hash);
390 int GetMapHashToFriendName(MAP_HASH_NAME &map);
391 static int GetMapHashToFriendName(git_repository* repo, MAP_HASH_NAME &map);
393 CString DerefFetchHead();
395 // FixBranchName():
396 // When branchName == FETCH_HEAD, dereference it.
397 // A selected branch name got from GetBranchList(), with flag BRANCH_FETCH_HEAD enabled,
398 // should go through this function before it is used.
399 CString FixBranchName_Mod(CString& branchName);
400 CString FixBranchName(const CString& branchName);
402 CString GetLogCmd(CString range, const CTGitPath* path, int InfoMask, CFilterData* filter, int logOrderBy);
404 int GetHash(CGitHash &hash, const CString& friendname);
405 static int GetHash(git_repository * repo, CGitHash &hash, const CString& friendname, bool skipFastCheck = false);
407 int BuildOutputFormat(CString &format,bool IsFull=TRUE);
408 static void StringAppend(CString *str, const BYTE *p, int code = CP_UTF8, int length = -1);
410 BOOL CanParseRev(CString ref);
412 Checks if HEAD points to an unborn branch
413 This method assumes, that we already know that we are in a working tree.
415 BOOL IsInitRepos();
416 /** Returns 0 if no conflict, if a conflict was found and -1 in case of a failure */
417 int HasWorkingTreeConflicts();
418 /** Returns 0 if no conflict, if a conflict was found and -1 in case of a failure */
419 int HasWorkingTreeConflicts(git_repository* repo);
420 int IsRebaseRunning();
421 void GetBisectTerms(CString* good, CString* bad);
422 int GetRefList(STRING_VECTOR &list);
424 int RefreshGitIndex();
425 int GetOneFile(const CString &Refname, const CTGitPath &path, const CString &outputfile);
427 //Example: master -> refs/heads/master
428 CString GetFullRefName(const CString& shortRefName);
429 //Removes 'refs/heads/' or just 'refs'. Example: refs/heads/master -> master
430 static CString StripRefName(CString refName);
432 int GetCommitDiffList(const CString &rev1, const CString &rev2, CTGitPathList &outpathlist, bool ignoreSpaceAtEol = false, bool ignoreSpaceChange = false, bool ignoreAllSpace = false, bool ignoreBlankLines = false);
433 int GetInitAddList(CTGitPathList &outpathlist);
434 int GetWorkingTreeChanges(CTGitPathList& result, bool amend = false, const CTGitPathList* filterlist = nullptr, bool includedStaged = false);
436 static __int64 filetime_to_time_t(__int64 winTime)
438 winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */
439 winTime /= 10000000; /* Nano to seconds resolution */
440 return (time_t)winTime;
443 static inline __int64 filetime_to_time_t(const FILETIME *ft)
445 return filetime_to_time_t(((__int64)ft->dwHighDateTime << 32) + ft->dwLowDateTime);
448 static int GetFileModifyTime(LPCTSTR filename, __int64* time, bool* isDir = nullptr, __int64* size = nullptr, bool* isSymlink = nullptr)
450 WIN32_FILE_ATTRIBUTE_DATA fdata;
451 if (GetFileAttributesEx(filename, GetFileExInfoStandard, &fdata))
453 if(time)
454 *time = ((__int64)fdata.ftLastWriteTime.dwHighDateTime << 32) + fdata.ftLastWriteTime.dwLowDateTime;
456 if (size)
457 *size = ((__int64)fdata.nFileSizeHigh << 32) + fdata.nFileSizeLow;
459 if(isDir)
460 *isDir = !!( fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
462 if (isSymlink)
463 *isSymlink = (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && !CPathUtils::ReadLink(filename);
465 return 0;
467 return -1;
470 int GetShortHASHLength() const;
472 static BOOL GetShortName(const CString& ref, CString& shortname, const CString& prefix)
474 //TRACE(L"%s %s\r\n", ref, prefix);
475 if (CStringUtils::StartsWith(ref, prefix))
477 shortname = ref.Right(ref.GetLength() - prefix.GetLength());
478 if (CStringUtils::EndsWith(shortname, L"^{}"))
479 shortname.Truncate(shortname.GetLength() - 3);
480 return TRUE;
482 return FALSE;
485 static CString GetShortName(const CString& ref, REF_TYPE *type);
487 static bool LoadTextFile(const CString &filename, CString &msg);
489 int GetGitNotes(const CGitHash& hash, CString& notes);
490 int SetGitNotes(const CGitHash& hash, const CString& notes);
492 int GetUnifiedDiff(const CTGitPath& path, const CString& rev1, const CString& rev2, CString patchfile, bool bMerge, bool bCombine, int diffContext, bool bNoPrefix = false);
493 int GetUnifiedDiff(const CTGitPath& path, const CString& rev1, const CString& rev2, CStringA* buffer, bool bMerge, bool bCombine, int diffContext);
495 int GitRevert(int parent, const CGitHash &hash);
497 int GetGitVersion(CString* versiondebug, CString* errStr);
499 CString CombinePath(const CString &path) const
501 if (path.IsEmpty())
502 return m_CurrentDir;
503 if (m_CurrentDir.IsEmpty())
504 return path;
505 return m_CurrentDir + (CStringUtils::EndsWith(m_CurrentDir, L'\\') ? L"" : L"\\") + path;
508 CString CombinePath(const CTGitPath &path) const
510 return CombinePath(path.GetWinPath());
513 CString CombinePath(const CTGitPath *path) const
515 ATLASSERT(path);
516 return CombinePath(path->GetWinPath());
519 extern void GetTempPath(CString &path);
520 extern CString GetTempFile();
521 extern DWORD GetTortoiseGitTempPath(DWORD nBufferLength, LPTSTR lpBuffer);
523 extern CGit g_Git;