int CGit::Revert(CTGitPath &path,bool keep) { CString cmd, out; if(path.m_Action & CTGitPath::LOGACTIONS_ADDED) { //To init git repository, there are not HEAD, so we can use git reset command cmd.Format(_T("git.exe rm --cache -- \"%s\""),path.GetGitPathString()); if(g_Git.Run(cmd,&out,CP_OEMCP)) return -1; } else if(path.m_Action & CTGitPath::LOGACTIONS_REPLACED ) { cmd.Format(_T("git.exe mv \"%s\" \"%s\""),path.GetGitPathString(),path.GetGitOldPathString()); if(g_Git.Run(cmd,&out,CP_OEMCP)) return -1; cmd.Format(_T("git.exe checkout -f -- \"%s\""),path.GetGitOldPathString()); if(g_Git.Run(cmd,&out,CP_OEMCP)) return -1; } else { cmd.Format(_T("git.exe checkout -f -- \"%s\""),path.GetGitPathString()); if(g_Git.Run(cmd,&out,CP_OEMCP)) return -1; } return 0; }
int CGitDiff::SubmoduleDiffNull(const CTGitPath * pPath, const git_revnum_t &rev1) { CString oldhash = GIT_REV_ZERO; CString oldsub ; CString newsub; CString newhash; CString cmd; if (rev1 != GIT_REV_ZERO) cmd.Format(_T("git.exe ls-tree \"%s\" -- \"%s\""), rev1, pPath->GetGitPathString()); else cmd.Format(_T("git.exe ls-files -s -- \"%s\""), pPath->GetGitPathString()); CString output, err; if (g_Git.Run(cmd, &output, &err, CP_UTF8)) { CMessageBox::Show(NULL, output + L"\n" + err, _T("TortoiseGit"), MB_OK|MB_ICONERROR); return -1; } int start=0; start=output.Find(_T(' '),start); if(start>0) { if (rev1 != GIT_REV_ZERO) // in ls-files the hash is in the second column; in ls-tree it's in the third one start = output.Find(_T(' '), start + 1); if(start>0) newhash=output.Mid(start+1, 40); CGit subgit; subgit.m_CurrentDir=g_Git.m_CurrentDir+_T("\\")+pPath->GetWinPathString(); int encode=CAppUtils::GetLogOutputEncode(&subgit); cmd.Format(_T("git.exe log -n1 --pretty=format:\"%%s\" %s --"), newhash); bool toOK = !subgit.Run(cmd,&newsub,encode); bool dirty = false; if (rev1 == GIT_REV_ZERO) { CString dirtyList; subgit.Run(_T("git.exe status --porcelain"), &dirtyList, encode); dirty = !dirtyList.IsEmpty(); } CSubmoduleDiffDlg submoduleDiffDlg; submoduleDiffDlg.SetDiff(pPath->GetWinPath(), false, oldhash, oldsub, true, newhash, newsub, toOK, dirty, CSubmoduleDiffDlg::NewSubmodule); submoduleDiffDlg.DoModal(); if (submoduleDiffDlg.IsRefresh()) return 1; return 0; } if (rev1 != GIT_REV_ZERO) CMessageBox::Show(NULL, _T("ls-tree output format error"), _T("TortoiseGit"), MB_OK | MB_ICONERROR); else CMessageBox::Show(NULL, _T("ls-files output format error"), _T("TortoiseGit"), MB_OK | MB_ICONERROR); return -1; }
bool SubmoduleAddCommand::Execute() { bool bRet = false; CSubmoduleAddDlg dlg; dlg.m_strPath = cmdLinePath.GetDirectory().GetWinPathString(); dlg.m_strProject = g_Git.m_CurrentDir; if( dlg.DoModal() == IDOK ) { if (dlg.m_bAutoloadPuttyKeyFile) CAppUtils::LaunchPAgent(&dlg.m_strPuttyKeyFile); CString cmd; if(dlg.m_strPath.Left(g_Git.m_CurrentDir.GetLength()) == g_Git.m_CurrentDir) dlg.m_strPath = dlg.m_strPath.Right(dlg.m_strPath.GetLength()-g_Git.m_CurrentDir.GetLength()-1); CString branch; if(dlg.m_bBranch) branch.Format(_T(" -b %s "), (LPCTSTR)dlg.m_strBranch); CString force; if (dlg.m_bForce) force = _T("--force"); dlg.m_strPath.Replace(_T('\\'),_T('/')); dlg.m_strRepos.Replace(_T('\\'),_T('/')); cmd.Format(_T("git.exe submodule add %s %s -- \"%s\" \"%s\""), (LPCTSTR)branch, (LPCTSTR)force, (LPCTSTR)dlg.m_strRepos, (LPCTSTR)dlg.m_strPath); CProgressDlg progress; progress.m_GitCmd=cmd; progress.DoModal(); if (progress.m_GitStatus == 0) { if (dlg.m_bAutoloadPuttyKeyFile) { SetCurrentDirectory(g_Git.m_CurrentDir); CGit subgit; dlg.m_strPath.Replace(_T('/'), _T('\\')); subgit.m_CurrentDir = PathIsRelative(dlg.m_strPath) ? g_Git.CombinePath(dlg.m_strPath) : dlg.m_strPath; if (subgit.SetConfigValue(_T("remote.origin.puttykeyfile"), dlg.m_strPuttyKeyFile, CONFIG_LOCAL)) { CMessageBox::Show(NULL, _T("Fail set config remote.origin.puttykeyfile"), _T("TortoiseGit"), MB_OK| MB_ICONERROR); return FALSE; } } } bRet = TRUE; } return bRet; }
int CGit::GetRemoteList(STRING_VECTOR &list) { int ret; CString cmd,output; cmd=_T("git.exe config --get-regexp remote.*.url"); ret=g_Git.Run(cmd,&output,CP_UTF8); if(!ret) { int pos=0; CString one; while( pos>=0 ) { one=output.Tokenize(_T("\n"),pos); int start=one.Find(_T("."),0); if(start>0) { CString url; url=one.Right(one.GetLength()-start-1); one=url; one=one.Left(one.Find(_T("."),0)); list.push_back(one); } } } return ret; }
int CGit::GetBranchList(STRING_VECTOR &list,int *current,BRANCH_TYPE type) { int ret; CString cmd,output; cmd=_T("git.exe branch"); if(type==(BRANCH_LOCAL|BRANCH_REMOTE)) cmd+=_T(" -a"); else if(type==BRANCH_REMOTE) cmd+=_T(" -r"); int i=0; ret=g_Git.Run(cmd,&output,CP_UTF8); if(!ret) { int pos=0; CString one; while( pos>=0 ) { one=output.Tokenize(_T("\n"),pos); list.push_back(one.Right(one.GetLength()-2)); if(one[0] == _T('*')) if(current) *current=i; i++; } } return ret; }
int addto_map_each_ref_fn(const char *refname, const unsigned char *sha1, int /*flags*/, void *cb_data) { MAP_HASH_NAME *map = (MAP_HASH_NAME*)cb_data; CString str; g_Git.StringAppend(&str, (BYTE*)refname, CP_UTF8); CGitHash hash((char*)sha1); (*map)[hash].push_back(str); if(strncmp(refname, "refs/tags", 9) == 0) { try { GIT_HASH refhash; if(!git_deref_tag(sha1, refhash)) { (*map)[(char*)refhash].push_back(str+_T("^{}")); } } catch (char* msg) { CString err(msg); ::MessageBox(NULL, _T("Could not get (readable) reference for hash ") + hash.ToString() + _T(".\nlibgit reports:\n") + err, _T("TortoiseGit"), MB_ICONERROR); } } return 0; }
int CGit::GetOneFile(CString Refname, CTGitPath &path, const CString &outputfile) { if(g_Git.m_IsUseGitDLL) { CAutoLocker lock(g_Git.m_critGitDllSec); try { g_Git.CheckAndInitDll(); CStringA ref, patha, outa; ref = CUnicodeUtils::GetMulti(Refname, CP_UTF8); patha = CUnicodeUtils::GetMulti(path.GetGitPathString(), CP_UTF8); outa = CUnicodeUtils::GetMulti(outputfile, CP_UTF8); ::DeleteFile(outputfile); return git_checkout_file((const char*)ref.GetBuffer(),(const char*)patha.GetBuffer(),(const char*)outa.GetBuffer()); }catch(...) { return -1; } } else { CString cmd; cmd.Format(_T("git.exe cat-file -p %s:\"%s\""), Refname, path.GetGitPathString()); return RunLogFile(cmd,outputfile); } }
int CGit::GetMapHashToFriendName(MAP_HASH_NAME &map) { int ret; CString cmd,output; cmd=_T("git show-ref -d"); ret=g_Git.Run(cmd,&output,CP_UTF8); if(!ret) { int pos=0; CString one; while( pos>=0 ) { one=output.Tokenize(_T("\n"),pos); int start=one.Find(_T(" "),0); if(start>0) { CString name; name=one.Right(one.GetLength()-start-1); CString hash; hash=one.Left(start); map[hash].push_back(name); } } } return ret; }
int CTGitPathList::FillUnRev(unsigned int action, CTGitPathList *list, CString *err) { this->Clear(); CTGitPath path; int count; if(list==NULL) count=1; else count=list->GetCount(); for (int i = 0; i < count; ++i) { CString cmd; int pos = 0; CString ignored; if(action & CTGitPath::LOGACTIONS_IGNORE) ignored= _T(" -i"); if(list==NULL) { cmd=_T("git.exe ls-files --exclude-standard --full-name --others -z"); cmd+=ignored; } else { cmd.Format(_T("git.exe ls-files --exclude-standard --full-name --others -z%s -- \"%s\""), (LPCTSTR)ignored, (*list)[i].GetWinPath()); } BYTE_VECTOR out, errb; out.clear(); if (g_Git.Run(cmd, &out, &errb)) { if (err != nullptr) CGit::StringAppend(err, &errb[0], CP_UTF8, (int)errb.size()); return -1; } pos=0; CString one; while (pos >= 0 && pos < (int)out.size()) { one.Empty(); CGit::StringAppend(&one, &out[pos], CP_UTF8); if(!one.IsEmpty()) { //SetFromGit will clear all status path.SetFromGit(one); path.m_Action=action; AddPath(path); } pos=out.findNextString(pos); } } return 0; }
int addto_list_each_ref_fn(const char *refname, const unsigned char * /*sha1*/, int /*flags*/, void *cb_data) { STRING_VECTOR *list = (STRING_VECTOR*)cb_data; CString str; g_Git.StringAppend(&str, (BYTE*)refname, CP_UTF8); list->push_back(str); return 0; }
int CGitDiff::SubmoduleDiffNull(CTGitPath *pPath, git_revnum_t &/*rev1*/) { CString oldhash = GIT_REV_ZERO; CString oldsub ; CString newsub; CString newhash; CString cmd; cmd.Format(_T("git.exe ls-tree HEAD -- \"%s\""), pPath->GetGitPathString()); CString output, err; if(g_Git.Run(cmd, &output, &err, CP_ACP)) { CMessageBox::Show(NULL, output + L"\n" + err, _T("TortoiseGit"), MB_OK|MB_ICONERROR); return -1; } int start=0; start=output.Find(_T(' '),start); if(start>0) { start=output.Find(_T(' '),start+1); if(start>0) newhash=output.Mid(start+1, 40); CGit subgit; subgit.m_CurrentDir=g_Git.m_CurrentDir+_T("\\")+pPath->GetWinPathString(); int encode=CAppUtils::GetLogOutputEncode(&subgit); cmd.Format(_T("git.exe log -n1 --pretty=format:\"%%s\" %s"),newhash); subgit.Run(cmd,&newsub,encode); CSubmoduleDiffDlg submoduleDiffDlg; submoduleDiffDlg.SetDiff(pPath->GetWinPath(), false, oldhash, oldsub, newhash, newsub); submoduleDiffDlg.DoModal(); return 0; } CMessageBox::Show(NULL,_T("ls-tree output format error"),_T("TortoiseGit"),MB_OK|MB_ICONERROR); return -1; }
bool CreateRepositoryCommand::Execute() { CString folder = this->orgCmdLinePath.GetWinPath(); CCreateRepoDlg dlg; dlg.m_folder = folder; if(dlg.DoModal() == IDOK) { CString message; message.Format(IDS_WARN_GITINIT_FOLDERNOTEMPTY, folder); if (!PathIsDirectoryEmpty(folder) && CMessageBox::Show(hwndExplorer, message, _T("TortoiseGit"), 1, IDI_ERROR, CString(MAKEINTRESOURCE(IDS_ABORTBUTTON)), CString(MAKEINTRESOURCE(IDS_PROCEEDBUTTON))) == 1) { return false; } CGit git; git.m_CurrentDir = this->orgCmdLinePath.GetWinPath(); CString output; int ret; if (dlg.m_bBare) ret = git.Run(_T("git.exe init-db --bare"), &output, CP_UTF8); else ret = git.Run(_T("git.exe init-db"), &output, CP_UTF8); if (output.IsEmpty()) output = _T("git.Run() had no output"); if (ret) { CMessageBox::Show(hwndExplorer, output, _T("TortoiseGit"), MB_ICONERROR); return false; } else { if (!dlg.m_bBare) CShellUpdater::Instance().AddPathForUpdate(orgCmdLinePath); CMessageBox::Show(hwndExplorer, output, _T("TortoiseGit"), MB_OK | MB_ICONINFORMATION); } return true; } return false; }
BOOL CGit::CheckCleanWorkTree() { CString out; CString cmd; cmd=_T("git.exe rev-parse --verify HEAD"); if(g_Git.Run(cmd,&out,CP_UTF8)) return FALSE; cmd=_T("git.exe update-index --ignore-submodules --refresh"); if(g_Git.Run(cmd,&out,CP_UTF8)) return FALSE; cmd=_T("git.exe diff-files --quiet --ignore-submodules"); if(g_Git.Run(cmd,&out,CP_UTF8)) return FALSE; cmd=_T("git diff-index --cached --quiet HEAD --ignore-submodules"); if(g_Git.Run(cmd,&out,CP_UTF8)) return FALSE; return TRUE; }
BOOL CGit::IsInitRepos() { CString cmdout; cmdout.Empty(); if(g_Git.Run(_T("git.exe rev-parse --revs-only HEAD"),&cmdout,CP_UTF8)) { // CMessageBox::Show(NULL,cmdout,_T("TortoiseGit"),MB_OK); return TRUE; } if(cmdout.IsEmpty()) return TRUE; return FALSE; }
int CTGitPathList::FillBasedOnIndexFlags(unsigned short flag, CTGitPathList* list /*nullptr*/) { Clear(); CTGitPath path; CAutoRepository repository(g_Git.GetGitRepository()); if (!repository) return -1; CAutoIndex index; if (git_repository_index(index.GetPointer(), repository)) return -1; int count; if (list == nullptr) count = 1; else count = list->GetCount(); for (int j = 0; j < count; ++j) { for (size_t i = 0, ecount = git_index_entrycount(index); i < ecount; ++i) { const git_index_entry *e = git_index_get_byindex(index, i); if (!e || !((e->flags | e->flags_extended) & flag) || !e->path) continue; CString one = CUnicodeUtils::GetUnicode(e->path); if (!(!list || (*list)[j].GetWinPathString().IsEmpty() || one == (*list)[j].GetGitPathString() || (PathIsDirectory(g_Git.CombinePath((*list)[j].GetWinPathString())) && one.Find((*list)[j].GetGitPathString() + _T("/")) == 0))) continue; //SetFromGit will clear all status path.SetFromGit(one); if ((e->flags | e->flags_extended) & GIT_IDXENTRY_SKIP_WORKTREE) path.m_Action = CTGitPath::LOGACTIONS_SKIPWORKTREE; else if ((e->flags | e->flags_extended) & GIT_IDXENTRY_VALID) path.m_Action = CTGitPath::LOGACTIONS_ASSUMEVALID; AddPath(path); } } RemoveDuplicates(); return 0; }
int CGit::ListConflictFile(CTGitPathList &list,CTGitPath *path) { BYTE_VECTOR vector; CString cmd; if(path) cmd.Format(_T("git.exe ls-files -u -t -z -- \"%s\""),path->GetGitPathString()); else cmd=_T("git.exe ls-files -u -t -z"); if(g_Git.Run(cmd,&vector)) { return -1; } list.ParserFromLsFile(vector); return 0; }
int CGit::GetTagList(STRING_VECTOR &list) { int ret; CString cmd,output; cmd=_T("git.exe tag -l"); int i=0; ret=g_Git.Run(cmd,&output,CP_UTF8); if(!ret) { int pos=0; CString one; while( pos>=0 ) { i++; one=output.Tokenize(_T("\n"),pos); list.push_back(one); } } return ret; }
CString CGit::GetCurrentBranch(void) { CString output; //Run(_T("git.exe branch"),&branch); int ret=g_Git.Run(_T("git.exe branch"),&output,CP_UTF8); if(!ret) { int pos=0; CString one; while( pos>=0 ) { //i++; one=output.Tokenize(_T("\n"),pos); //list.push_back(one.Right(one.GetLength()-2)); if(one[0] == _T('*')) return one.Right(one.GetLength()-2); } } return CString(""); }
CString CGit::GetGitGlobalConfig() { return g_Git.GetHomeDirectory() + _T("\\.gitconfig"); }
int CGitDiff::SubmoduleDiff(const CTGitPath * pPath, const CTGitPath * /*pPath2*/, const git_revnum_t &rev1, const git_revnum_t &rev2, bool /*blame*/, bool /*unified*/) { CString oldhash; CString newhash; bool dirty = false; CString cmd; bool isWorkingCopy = false; if( rev2 == GIT_REV_ZERO || rev1 == GIT_REV_ZERO ) { oldhash = GIT_REV_ZERO; newhash = GIT_REV_ZERO; CString rev; if( rev2 != GIT_REV_ZERO ) rev = rev2; if( rev1 != GIT_REV_ZERO ) rev = rev1; isWorkingCopy = true; cmd.Format(_T("git.exe diff %s -- \"%s\""), rev,pPath->GetGitPathString()); CString output, err; if (g_Git.Run(cmd, &output, &err, CP_UTF8)) { CMessageBox::Show(NULL, output + L"\n" + err, _T("TortoiseGit"), MB_OK|MB_ICONERROR); return -1; } if (output.IsEmpty()) { output.Empty(); err.Empty(); // also compare against index cmd.Format(_T("git.exe diff -- \"%s\""), pPath->GetGitPathString()); if (g_Git.Run(cmd, &output, &err, CP_UTF8)) { CMessageBox::Show(NULL, output + _T("\n") + err, _T("TortoiseGit"), MB_OK | MB_ICONERROR); return -1; } if (output.IsEmpty()) { CMessageBox::Show(NULL, CString(MAKEINTRESOURCE(IDS_ERR_EMPTYDIFF)), _T("TortoiseGit"), MB_OK | MB_ICONERROR); return -1; } else if (CMessageBox::Show(NULL, CString(MAKEINTRESOURCE(IDS_SUBMODULE_EMPTYDIFF)), _T("TortoiseGit"), 1, IDI_QUESTION, CString(MAKEINTRESOURCE(IDS_MSGBOX_YES)), CString(MAKEINTRESOURCE(IDS_MSGBOX_NO))) == 1) { CString sCmd; sCmd.Format(_T("/command:subupdate /bkpath:\"%s\""), g_Git.m_CurrentDir); CAppUtils::RunTortoiseGitProc(sCmd); } return -1; } int start =0; int oldstart = output.Find(_T("-Subproject commit"),start); if(oldstart<0) { CMessageBox::Show(NULL,_T("Subproject Diff Format error") ,_T("TortoiseGit"),MB_OK|MB_ICONERROR); return -1; } oldhash = output.Mid(oldstart+ CString(_T("-Subproject commit")).GetLength()+1,40); start = 0; int newstart = output.Find(_T("+Subproject commit"),start); if(oldstart<0) { CMessageBox::Show(NULL,_T("Subproject Diff Format error") ,_T("TortoiseGit"),MB_OK|MB_ICONERROR); return -1; } newhash = output.Mid(newstart+ CString(_T("+Subproject commit")).GetLength()+1,40); dirty = output.Mid(newstart + CString(_T("+Subproject commit")).GetLength() + 41) == _T("-dirty\n"); } else { cmd.Format(_T("git.exe diff-tree -r -z %s %s -- \"%s\""), rev2,rev1,pPath->GetGitPathString()); BYTE_VECTOR bytes, errBytes; if(g_Git.Run(cmd, &bytes, &errBytes)) { CString err; g_Git.StringAppend(&err, &errBytes[0], CP_UTF8); CMessageBox::Show(NULL,err,_T("TortoiseGit"),MB_OK|MB_ICONERROR); return -1; } g_Git.StringAppend(&oldhash, &bytes[15], CP_UTF8, 40); g_Git.StringAppend(&newhash, &bytes[15+41], CP_UTF8, 40); } CString oldsub; CString newsub; bool oldOK = false, newOK = false; CGit subgit; subgit.m_CurrentDir=g_Git.m_CurrentDir+_T("\\")+pPath->GetWinPathString(); CSubmoduleDiffDlg::ChangeType changeType = CSubmoduleDiffDlg::Unknown; if(pPath->HasAdminDir()) { int encode=CAppUtils::GetLogOutputEncode(&subgit); int oldTime = 0, newTime = 0; if(oldhash != GIT_REV_ZERO) { CString cmdout, cmderr; cmd.Format(_T("git.exe log -n1 --pretty=format:\"%%ct %%s\" %s --"), oldhash); oldOK = !subgit.Run(cmd, &cmdout, &cmderr, encode); if (oldOK) { int pos = cmdout.Find(_T(" ")); oldTime = _ttoi(cmdout.Left(pos)); oldsub = cmdout.Mid(pos + 1); } else oldsub = cmderr; } if (newhash != GIT_REV_ZERO) { CString cmdout, cmderr; cmd.Format(_T("git.exe log -n1 --pretty=format:\"%%ct %%s\" %s --"), newhash); newOK = !subgit.Run(cmd, &cmdout, &cmderr, encode); if (newOK) { int pos = cmdout.Find(_T(" ")); newTime = _ttoi(cmdout.Left(pos)); newsub = cmdout.Mid(pos + 1); } else newsub = cmderr; } if (oldhash == GIT_REV_ZERO) { oldOK = true; changeType = CSubmoduleDiffDlg::NewSubmodule; } else if (newhash == GIT_REV_ZERO) { newOK = true; changeType = CSubmoduleDiffDlg::DeleteSubmodule; } else if (oldhash != newhash) { bool ffNewer = false, ffOlder = false; ffNewer = subgit.IsFastForward(oldhash, newhash); if (!ffNewer) { ffOlder = subgit.IsFastForward(newhash, oldhash); if (!ffOlder) { if (newTime > oldTime) changeType = CSubmoduleDiffDlg::NewerTime; else if (newTime < oldTime) changeType = CSubmoduleDiffDlg::OlderTime; else changeType = CSubmoduleDiffDlg::SameTime; } else changeType = CSubmoduleDiffDlg::Rewind; } else changeType = CSubmoduleDiffDlg::FastForward; } } if (!oldOK || !newOK) changeType = CSubmoduleDiffDlg::Unknown; CSubmoduleDiffDlg submoduleDiffDlg; submoduleDiffDlg.SetDiff(pPath->GetWinPath(), isWorkingCopy, oldhash, oldsub, oldOK, newhash, newsub, newOK, dirty, changeType); submoduleDiffDlg.DoModal(); if (submoduleDiffDlg.IsRefresh()) return 1; return 0; }
void CGitDiff::GetSubmoduleChangeType(CGit& subgit, const CString& oldhash, const CString& newhash, bool& oldOK, bool& newOK, ChangeType& changeType, CString& oldsub, CString& newsub) { CString cmd; int encode = CAppUtils::GetLogOutputEncode(&subgit); int oldTime = 0, newTime = 0; if (oldhash != GIT_REV_ZERO) { CString cmdout, cmderr; cmd.Format(_T("git.exe log -n1 --pretty=format:\"%%ct %%s\" %s --"), (LPCTSTR)oldhash); oldOK = !subgit.Run(cmd, &cmdout, &cmderr, encode); if (oldOK) { int pos = cmdout.Find(_T(" ")); oldTime = _ttoi(cmdout.Left(pos)); oldsub = cmdout.Mid(pos + 1); } else oldsub = cmderr; } if (newhash != GIT_REV_ZERO) { CString cmdout, cmderr; cmd.Format(_T("git.exe log -n1 --pretty=format:\"%%ct %%s\" %s --"), (LPCTSTR)newhash); newOK = !subgit.Run(cmd, &cmdout, &cmderr, encode); if (newOK) { int pos = cmdout.Find(_T(" ")); newTime = _ttoi(cmdout.Left(pos)); newsub = cmdout.Mid(pos + 1); } else newsub = cmderr; } if (oldhash == GIT_REV_ZERO) { oldOK = true; changeType = NewSubmodule; } else if (newhash == GIT_REV_ZERO) { newOK = true; changeType = DeleteSubmodule; } else if (oldhash != newhash) { bool ffNewer = false, ffOlder = false; ffNewer = subgit.IsFastForward(oldhash, newhash); if (!ffNewer) { ffOlder = subgit.IsFastForward(newhash, oldhash); if (!ffOlder) { if (newTime > oldTime) changeType = NewerTime; else if (newTime < oldTime) changeType = OlderTime; else changeType = SameTime; } else changeType = Rewind; } else changeType = FastForward; } else if (oldhash == newhash) changeType = Identical; if (!oldOK || !newOK) changeType = Unknown; }
int CGitDiff::SubmoduleDiff(CTGitPath * pPath,CTGitPath * /*pPath2*/, git_revnum_t rev1, git_revnum_t rev2, bool /*blame*/, bool /*unified*/) { CString oldhash; CString newhash; CString cmd; bool isWorkingCopy = false; if( rev2 == GIT_REV_ZERO || rev1 == GIT_REV_ZERO ) { oldhash = GIT_REV_ZERO; newhash = GIT_REV_ZERO; CString rev; if( rev2 != GIT_REV_ZERO ) rev = rev2; if( rev1 != GIT_REV_ZERO ) rev = rev1; isWorkingCopy = true; cmd.Format(_T("git.exe diff %s -- \"%s\""), rev,pPath->GetGitPathString()); CString output, err; if (g_Git.Run(cmd, &output, &err, CP_ACP)) { CMessageBox::Show(NULL, output + L"\n" + err, _T("TortoiseGit"), MB_OK|MB_ICONERROR); return -1; } int start =0; int oldstart = output.Find(_T("-Subproject commit"),start); if(oldstart<0) { CMessageBox::Show(NULL,_T("Subproject Diff Format error") ,_T("TortoiseGit"),MB_OK|MB_ICONERROR); return -1; } oldhash = output.Mid(oldstart+ CString(_T("-Subproject commit")).GetLength()+1,40); start = 0; int newstart = output.Find(_T("+Subproject commit"),start); if(oldstart<0) { CMessageBox::Show(NULL,_T("Subproject Diff Format error") ,_T("TortoiseGit"),MB_OK|MB_ICONERROR); return -1; } newhash = output.Mid(newstart+ CString(_T("+Subproject commit")).GetLength()+1,40); } else { cmd.Format(_T("git.exe diff-tree -r -z %s %s -- \"%s\""), rev2,rev1,pPath->GetGitPathString()); BYTE_VECTOR bytes, errBytes; if(g_Git.Run(cmd, &bytes, &errBytes)) { CString err; g_Git.StringAppend(&err,&errBytes[0],CP_ACP); CMessageBox::Show(NULL,err,_T("TortoiseGit"),MB_OK|MB_ICONERROR); return -1; } g_Git.StringAppend(&oldhash,&bytes[15],CP_ACP,40); g_Git.StringAppend(&newhash,&bytes[15+41],CP_ACP,40); } CString oldsub; CString newsub; CGit subgit; subgit.m_CurrentDir=g_Git.m_CurrentDir+_T("\\")+pPath->GetWinPathString(); if(pPath->HasAdminDir()) { int encode=CAppUtils::GetLogOutputEncode(&subgit); if(oldhash != GIT_REV_ZERO) { cmd.Format(_T("git log -n1 --pretty=format:\"%%s\" %s"),oldhash); subgit.Run(cmd,&oldsub,encode); } if(newsub != GIT_REV_ZERO) { cmd.Format(_T("git log -n1 --pretty=format:\"%%s\" %s"),newhash); subgit.Run(cmd,&newsub,encode); } } CSubmoduleDiffDlg submoduleDiffDlg; submoduleDiffDlg.SetDiff(pPath->GetWinPath(), isWorkingCopy, oldhash, oldsub, newhash, newsub); submoduleDiffDlg.DoModal(); return 0; }
CString CGit::GetGitGlobalXDGConfig() { return g_Git.GetGitGlobalXDGConfigPath() + _T("\\config"); }
CString CGit::GetGitGlobalXDGConfigPath() { return g_Git.GetHomeDirectory() + _T("\\.config\\git"); }
int CGitDiff::SubmoduleDiffNull(const CTGitPath * pPath, const git_revnum_t &rev1) { CString oldhash = GIT_REV_ZERO; CString oldsub ; CString newsub; CString newhash; CString cmd; if (rev1 != GIT_REV_ZERO) cmd.Format(L"git.exe ls-tree \"%s\" -- \"%s\"", (LPCTSTR)rev1, (LPCTSTR)pPath->GetGitPathString()); else cmd.Format(L"git.exe ls-files -s -- \"%s\"", (LPCTSTR)pPath->GetGitPathString()); CString output, err; if (g_Git.Run(cmd, &output, &err, CP_UTF8)) { CMessageBox::Show(nullptr, output + L'\n' + err, L"TortoiseGit", MB_OK | MB_ICONERROR); return -1; } int start = output.Find(L' '); if(start>0) { if (rev1 != GIT_REV_ZERO) // in ls-files the hash is in the second column; in ls-tree it's in the third one start = output.Find(L' ', start + 1); if(start>0) newhash=output.Mid(start+1, 40); CGit subgit; subgit.m_CurrentDir = g_Git.CombinePath(pPath); int encode=CAppUtils::GetLogOutputEncode(&subgit); cmd.Format(L"git.exe log -n1 --pretty=format:\"%%s\" %s --", (LPCTSTR)newhash); bool toOK = !subgit.Run(cmd,&newsub,encode); bool dirty = false; if (rev1 == GIT_REV_ZERO && !(pPath->m_Action & CTGitPath::LOGACTIONS_DELETED)) { CString dirtyList; subgit.Run(L"git.exe status --porcelain", &dirtyList, encode); dirty = !dirtyList.IsEmpty(); } CSubmoduleDiffDlg submoduleDiffDlg; if (pPath->m_Action & CTGitPath::LOGACTIONS_DELETED) submoduleDiffDlg.SetDiff(pPath->GetWinPath(), false, newhash, newsub, toOK, oldhash, oldsub, false, dirty, DeleteSubmodule); else submoduleDiffDlg.SetDiff(pPath->GetWinPath(), false, oldhash, oldsub, true, newhash, newsub, toOK, dirty, NewSubmodule); submoduleDiffDlg.DoModal(); if (submoduleDiffDlg.IsRefresh()) return 1; return 0; } if (rev1 != GIT_REV_ZERO) CMessageBox::Show(nullptr, L"ls-tree output format error", L"TortoiseGit", MB_OK | MB_ICONERROR); else CMessageBox::Show(nullptr, L"ls-files output format error", L"TortoiseGit", MB_OK | MB_ICONERROR); return -1; }
bool CleanupCommand::Execute() { bool bRet = false; CCleanTypeDlg dlg; if( dlg.DoModal() == IDOK) { bool quotepath = g_Git.GetConfigValueBool(_T("core.quotepath")); CString cmd; cmd.Format(_T("git.exe clean")); if (dlg.m_bDryRun || !dlg.m_bNoRecycleBin) cmd += _T(" -n "); if(dlg.m_bDir) cmd += _T(" -d "); switch(dlg.m_CleanType) { case 0: cmd += _T(" -fx"); break; case 1: cmd += _T(" -f"); break; case 2: cmd += _T(" -fX"); break; } STRING_VECTOR submoduleList; SubmodulePayload payload(submoduleList); if (dlg.m_bSubmodules) { payload.basePath = CTGitPath(g_Git.m_CurrentDir).GetGitPathString(); if (pathList.GetCount() != 1 || pathList.GetCount() == 1 && !pathList[0].IsEmpty()) { for (int i = 0; i < pathList.GetCount(); ++i) { CString path; if (pathList[i].IsDirectory()) payload.prefixList.push_back(pathList[i].GetGitPathString()); else payload.prefixList.push_back(pathList[i].GetContainingDirectory().GetGitPathString()); } } if (!GetSubmodulePathList(payload)) return FALSE; std::sort(submoduleList.begin(), submoduleList.end()); } if (dlg.m_bDryRun || dlg.m_bNoRecycleBin) { while (true) { CProgressDlg progress; for (int i = 0; i < this->pathList.GetCount(); ++i) { CString path; if (this->pathList[i].IsDirectory()) path = pathList[i].GetGitPathString(); else path = pathList[i].GetContainingDirectory().GetGitPathString(); progress.m_GitDirList.push_back(g_Git.m_CurrentDir); progress.m_GitCmdList.push_back(cmd + _T(" \"") + path + _T("\"")); } if (dlg.m_bSubmodules) { for (CString dir : submoduleList) { progress.m_GitDirList.push_back(CTGitPath(dir).GetWinPathString()); progress.m_GitCmdList.push_back(cmd); } } INT_PTR idRetry = -1; if (!dlg.m_bDryRun) idRetry = progress.m_PostFailCmdList.Add(CString(MAKEINTRESOURCE(IDS_MSGBOX_RETRY))); INT_PTR result = progress.DoModal(); if (result == IDOK) return TRUE; if (progress.m_GitStatus && result == IDC_PROGRESS_BUTTON1 + idRetry) continue; break; } } else { CSysProgressDlg sysProgressDlg; sysProgressDlg.SetAnimation(IDR_CLEANUPANI); sysProgressDlg.SetTitle(CString(MAKEINTRESOURCE(IDS_APPNAME))); sysProgressDlg.SetLine(1, CString(MAKEINTRESOURCE(IDS_PROC_CLEANUP_INFO1))); sysProgressDlg.SetLine(2, CString(MAKEINTRESOURCE(IDS_PROGRESSWAIT))); sysProgressDlg.SetShowProgressBar(false); sysProgressDlg.ShowModeless((HWND)NULL, true); CTGitPathList delList; for (size_t i = 0; i <= submoduleList.size(); ++i) { CGit git; CGit *pGit; if (i == 0) pGit = &g_Git; else { git.m_CurrentDir = submoduleList[i - 1]; pGit = &git; } CString cmdout, cmdouterr; if (pGit->Run(cmd, &cmdout, &cmdouterr, CP_UTF8)) { MessageBox(nullptr, cmdouterr, _T("TortoiseGit"), MB_ICONERROR); return FALSE; } if (sysProgressDlg.HasUserCancelled()) { CMessageBox::Show(nullptr, IDS_SVN_USERCANCELLED, IDS_APPNAME, MB_OK); return FALSE; } int pos = 0; CString token = cmdout.Tokenize(_T("\n"), pos); while (!token.IsEmpty()) { if (token.Mid(0, 13) == _T("Would remove ")) { CString tempPath = token.Mid(13).TrimRight(); if (quotepath) { tempPath = UnescapeQuotePath(tempPath.Trim(_T('"'))); } if (i == 0) delList.AddPath(CTGitPath(tempPath)); else delList.AddPath(CTGitPath(submoduleList[i - 1] + "/" + tempPath)); } token = cmdout.Tokenize(_T("\n"), pos); } if (sysProgressDlg.HasUserCancelled()) { CMessageBox::Show(nullptr, IDS_SVN_USERCANCELLED, IDS_APPNAME, MB_OK); return FALSE; } } delList.DeleteAllFiles(true, false); sysProgressDlg.Stop(); } } #if 0 CProgressDlg progress; progress.SetTitle(IDS_PROC_CLEANUP); progress.SetAnimation(IDR_CLEANUPANI); progress.SetShowProgressBar(false); progress.SetLine(1, CString(MAKEINTRESOURCE(IDS_PROC_CLEANUP_INFO1))); progress.SetLine(2, CString(MAKEINTRESOURCE(IDS_PROC_CLEANUP_INFO2))); progress.ShowModeless(hwndExplorer); CString strSuccessfullPaths, strFailedPaths; for (int i=0; i<pathList.GetCount(); ++i) { SVN svn; if (!svn.CleanUp(pathList[i])) { strFailedPaths += _T("- ") + pathList[i].GetWinPathString() + _T("\n"); strFailedPaths += svn.GetLastErrorMessage() + _T("\n\n"); } else { strSuccessfullPaths += _T("- ") + pathList[i].GetWinPathString() + _T("\n"); // after the cleanup has finished, crawl the path downwards and send a change // notification for every directory to the shell. This will update the // overlays in the left tree view of the explorer. CDirFileEnum crawler(pathList[i].GetWinPathString()); CString sPath; bool bDir = false; CTSVNPathList updateList; while (crawler.NextFile(sPath, &bDir)) { if ((bDir) && (!g_SVNAdminDir.IsAdminDirPath(sPath))) { updateList.AddPath(CTSVNPath(sPath)); } } updateList.AddPath(pathList[i]); CShellUpdater::Instance().AddPathsForUpdate(updateList); CShellUpdater::Instance().Flush(); updateList.SortByPathname(true); for (INT_PTR i=0; i<updateList.GetCount(); ++i) { SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH, updateList[i].GetWinPath(), NULL); CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": notify change for path %s\n"), updateList[i].GetWinPath()); } } } progress.Stop(); CString strMessage; if ( !strSuccessfullPaths.IsEmpty() ) { CString tmp; tmp.Format(IDS_PROC_CLEANUPFINISHED, (LPCTSTR)strSuccessfullPaths); strMessage += tmp; bRet = true; } if ( !strFailedPaths.IsEmpty() ) { if (!strMessage.IsEmpty()) strMessage += _T("\n"); CString tmp; tmp.Format(IDS_PROC_CLEANUPFINISHED_FAILED, (LPCTSTR)strFailedPaths); strMessage += tmp; bRet = false; } CMessageBox::Show(hwndExplorer, strMessage, _T("TortoiseGit"), MB_OK | (strFailedPaths.IsEmpty()?MB_ICONINFORMATION:MB_ICONERROR)); #endif CShellUpdater::Instance().Flush(); return bRet; }