Add note for new users that a merge conflict requires a commit
[TortoiseGit.git] / src / TortoiseProc / SyncDlg.cpp
blobe8d4f32aa1270402ec1a2b29dca84bff304bef11
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 // SyncDlg.cpp : implementation file
23 #include "stdafx.h"
24 #include "TortoiseProc.h"
25 #include "SyncDlg.h"
26 #include "AppUtils.h"
27 #include "ProgressDlg.h"
28 #include "MessageBox.h"
29 #include "ImportPatchDlg.h"
30 #include "RebaseDlg.h"
31 #include "Hooks.h"
32 #include "SmartHandle.h"
33 #include "ProgressCommands/FetchProgressCommand.h"
34 #include "SyncTabCtrl.h"
35 #include "SysProgressDlg.h"
37 // CSyncDlg dialog
39 IMPLEMENT_DYNAMIC(CSyncDlg, CResizableStandAloneDialog)
41 CSyncDlg::CSyncDlg(CWnd* pParent /*=nullptr*/)
42 : CResizableStandAloneDialog(CSyncDlg::IDD, pParent)
43 , m_iPullRebase(0)
44 , m_CurrentCmd(0)
45 , m_bInited(false)
46 , m_CmdOutCurrentPos(0)
47 , m_bAutoLoadPuttyKey(CAppUtils::IsSSHPutty())
48 , m_bForce(BST_UNCHECKED)
49 , m_bBlock(false)
50 , m_BufStart(0)
51 , m_pThread(nullptr)
52 , m_bAbort(false)
53 , m_bDone(false)
54 , m_bWantToExit(false)
55 , m_GitCmdStatus(-1)
56 , m_startTick(GetTickCount64())
57 , m_seq(0)
59 m_pTooltip = &m_tooltips;
62 CSyncDlg::~CSyncDlg()
66 void CSyncDlg::DoDataExchange(CDataExchange* pDX)
68 CDialog::DoDataExchange(pDX);
69 DDX_Check(pDX, IDC_CHECK_PUTTY_KEY, m_bAutoLoadPuttyKey);
70 DDX_Check(pDX, IDC_CHECK_FORCE,m_bForce);
71 DDX_Control(pDX, IDC_COMBOBOXEX_URL, m_ctrlURL);
72 DDX_Control(pDX, IDC_BUTTON_TABCTRL, m_ctrlDumyButton);
73 DDX_Control(pDX, IDC_BUTTON_PULL, m_ctrlPull);
74 DDX_Control(pDX, IDC_BUTTON_PUSH, m_ctrlPush);
75 DDX_Control(pDX, IDC_STATIC_STATUS, m_ctrlStatus);
76 DDX_Control(pDX, IDC_PROGRESS_SYNC, m_ctrlProgress);
77 DDX_Control(pDX, IDC_ANIMATE_SYNC, m_ctrlAnimate);
78 DDX_Control(pDX, IDC_BUTTON_SUBMODULE,m_ctrlSubmodule);
79 DDX_Control(pDX, IDC_BUTTON_STASH, m_ctrlStash);
80 DDX_Control(pDX, IDC_PROG_LABEL, m_ctrlProgLabel);
81 BRANCH_COMBOX_DDX;
84 BEGIN_MESSAGE_MAP(CSyncDlg, CResizableStandAloneDialog)
85 ON_BN_CLICKED(IDC_BUTTON_PULL, &CSyncDlg::OnBnClickedButtonPull)
86 ON_BN_CLICKED(IDC_BUTTON_PUSH, &CSyncDlg::OnBnClickedButtonPush)
87 ON_BN_CLICKED(IDC_BUTTON_APPLY, &CSyncDlg::OnBnClickedButtonApply)
88 ON_BN_CLICKED(IDC_BUTTON_EMAIL, &CSyncDlg::OnBnClickedButtonEmail)
89 ON_BN_CLICKED(IDC_BUTTON_MANAGE, &CSyncDlg::OnBnClickedButtonManage)
90 BRANCH_COMBOX_EVENT
91 ON_CBN_EDITCHANGE(IDC_COMBOBOXEX_URL, &CSyncDlg::OnCbnEditchangeComboboxex)
92 ON_CBN_EDITCHANGE(IDC_COMBOBOXEX_REMOTE_BRANCH, &CSyncDlg::OnCbnEditchangeComboboxex)
93 ON_MESSAGE(MSG_PROGRESSDLG_UPDATE_UI, OnProgressUpdateUI)
94 ON_MESSAGE(WM_PROG_CMD_FINISH, OnProgCmdFinish)
95 ON_BN_CLICKED(IDC_BUTTON_COMMIT, &CSyncDlg::OnBnClickedButtonCommit)
96 ON_BN_CLICKED(IDC_BUTTON_SUBMODULE, &CSyncDlg::OnBnClickedButtonSubmodule)
97 ON_BN_CLICKED(IDC_BUTTON_STASH, &CSyncDlg::OnBnClickedButtonStash)
98 ON_WM_TIMER()
99 ON_REGISTERED_MESSAGE(TaskBarButtonCreated, OnTaskbarBtnCreated)
100 ON_BN_CLICKED(IDC_CHECK_FORCE, &CSyncDlg::OnBnClickedCheckForce)
101 ON_BN_CLICKED(IDC_LOG, &CSyncDlg::OnBnClickedLog)
102 ON_WM_DESTROY()
103 ON_WM_THEMECHANGED()
104 END_MESSAGE_MAP()
106 void CSyncDlg::EnableControlButton(bool bEnabled)
108 GetDlgItem(IDC_BUTTON_PULL)->EnableWindow(bEnabled);
109 GetDlgItem(IDC_BUTTON_PUSH)->EnableWindow(bEnabled);
110 GetDlgItem(IDC_BUTTON_APPLY)->EnableWindow(bEnabled);
111 GetDlgItem(IDC_BUTTON_EMAIL)->EnableWindow(bEnabled);
112 GetDlgItem(IDOK)->EnableWindow(bEnabled);
113 GetDlgItem(IDC_BUTTON_SUBMODULE)->EnableWindow(bEnabled);
114 GetDlgItem(IDC_BUTTON_STASH)->EnableWindow(bEnabled);
116 // CSyncDlg message handlers
118 bool CSyncDlg::AskSetTrackedBranch()
120 CString remote, remoteBranch;
121 g_Git.GetRemoteTrackedBranch(m_strLocalBranch, remote, remoteBranch);
122 if (remoteBranch.IsEmpty())
124 remoteBranch = m_strRemoteBranch;
125 if (remoteBranch.IsEmpty())
126 remoteBranch = m_strLocalBranch;
127 CString temp;
128 temp.Format(IDS_NOTYET_SETTRACKEDBRANCH, (LPCTSTR)m_strLocalBranch, (LPCTSTR)remoteBranch);
129 BOOL dontShowAgain = FALSE;
130 auto ret = CMessageBox::ShowCheck(GetSafeHwnd(), temp, L"TortoiseGit", MB_ICONQUESTION | MB_YESNOCANCEL, nullptr, CString(MAKEINTRESOURCE(IDS_MSGBOX_DONOTSHOW)), &dontShowAgain);
131 if (dontShowAgain)
132 CRegDWORD(L"Software\\TortoiseGit\\AskSetTrackedBranch") = FALSE;
133 if (ret == IDCANCEL)
134 return false;
135 if (ret == IDYES)
137 CString key;
138 key.Format(L"branch.%s.remote", (LPCTSTR)m_strLocalBranch);
139 g_Git.SetConfigValue(key, m_strURL);
140 key.Format(L"branch.%s.merge", (LPCTSTR)m_strLocalBranch);
141 g_Git.SetConfigValue(key, L"refs/heads/" + g_Git.StripRefName(remoteBranch));
144 return true;
147 void CSyncDlg::OnBnClickedButtonPull()
149 int CurrentEntry;
150 CurrentEntry = (int)this->m_ctrlPull.GetCurrentEntry();
151 this->m_regPullButton = CurrentEntry;
153 this->m_bAbort=false;
154 this->m_GitCmdList.clear();
155 m_ctrlCmdOut.SetWindowText(L"");
156 m_LogText.Empty();
158 this->UpdateData();
159 UpdateCombox();
161 if (g_Git.GetHash(m_oldHash, L"HEAD"))
163 MessageBox(g_Git.GetGitLastErr(L"Could not get HEAD hash."), L"TortoiseGit", MB_ICONERROR);
164 return;
167 m_refList.Clear();
168 m_newHashMap.clear();
169 m_oldHashMap.clear();
171 if( CurrentEntry == 0)
173 CGitHash localBranchHash;
174 if (g_Git.GetHash(localBranchHash, m_strLocalBranch))
176 MessageBox(g_Git.GetGitLastErr(L"Could not get hash of \"" + m_strLocalBranch + L"\"."), L"TortoiseGit", MB_ICONERROR);
177 return;
179 if (localBranchHash != m_oldHash)
181 CMessageBox::Show(GetSafeHwnd(), IDS_PROC_SYNC_PULLWRONGBRANCH, IDS_APPNAME, MB_OK | MB_ICONERROR);
182 return;
186 if(this->m_strURL.IsEmpty())
188 CMessageBox::Show(GetSafeHwnd(), IDS_PROC_GITCONFIG_URLEMPTY, IDS_APPNAME, MB_OK | MB_ICONERROR);
189 return;
192 if (CurrentEntry == 6)
194 SwitchToRun();
195 m_ctrlTabCtrl.ShowTab(IDC_LOG - 1, false);
196 m_ctrlTabCtrl.ShowTab(IDC_REFLIST - 1, false);
197 m_ctrlTabCtrl.ShowTab(IDC_OUT_LOGLIST - 1, false);
198 m_ctrlTabCtrl.ShowTab(IDC_OUT_CHANGELIST - 1, false);
199 m_ctrlTabCtrl.ShowTab(IDC_IN_LOGLIST - 1, false);
200 m_ctrlTabCtrl.ShowTab(IDC_IN_CHANGELIST - 1, false);
201 m_ctrlTabCtrl.ShowTab(IDC_IN_CONFLICT - 1, false);
202 m_ctrlTabCtrl.ShowTab(IDC_TAGCOMPARELIST - 1, true);
204 CSysProgressDlg sysProgressDlg;
205 sysProgressDlg.SetTitle(CString(MAKEINTRESOURCE(IDS_APPNAME)));
206 sysProgressDlg.SetLine(1, CString(MAKEINTRESOURCE(IDS_LOADING)));
207 sysProgressDlg.SetLine(2, CString(MAKEINTRESOURCE(IDS_PROGRESSWAIT)));
208 sysProgressDlg.SetShowProgressBar(false);
209 sysProgressDlg.ShowModal(this, true);
210 CString err;
211 auto ret = m_tagCompareList.Fill(m_strURL, err);
212 sysProgressDlg.Stop();
213 if (ret)
214 MessageBox(err, L"TortoiseGit", MB_ICONERROR);
216 BringWindowToTop();
217 SwitchToInput();
218 EnableControlButton();
219 return;
222 if (!IsURL() && !m_strRemoteBranch.IsEmpty() && CurrentEntry == 0 && CRegDWORD(L"Software\\TortoiseGit\\AskSetTrackedBranch", TRUE) == TRUE)
224 if (!AskSetTrackedBranch())
225 return;
228 if (m_bAutoLoadPuttyKey && CurrentEntry != 4) // CurrentEntry (Remote Update) handles this on its own)
230 CAppUtils::LaunchPAgent(nullptr, &m_strURL);
233 if (g_Git.GetMapHashToFriendName(m_oldHashMap))
234 MessageBox(g_Git.GetGitLastErr(L"Could not get all refs."), L"TortoiseGit", MB_ICONERROR);
236 CString force;
237 if(this->m_bForce)
238 force = L" --force";
240 CString cmd;
242 m_iPullRebase = 0;
243 if (CurrentEntry == 0 && CRegDWORD(L"Software\\TortoiseGit\\PullRebaseBehaviorLike1816", FALSE) == FALSE) // check whether we need to override Pull if pull.rebase is set
245 CAutoRepository repo(g_Git.GetGitRepository());
246 if (!repo)
247 MessageBox(CGit::GetLibGit2LastErr(L"Could not open repository."), L"TortoiseGit", MB_OK | MB_ICONERROR);
249 // Check config branch.<name>.rebase and pull.reabse
252 if (!repo)
253 break;
255 if (git_repository_head_detached(repo) == 1)
256 break;
258 CAutoConfig config(true);
259 if (git_repository_config(config.GetPointer(), repo))
260 break;
262 // branch.<name>.rebase overrides pull.rebase
263 if (config.GetBOOL(L"branch." + g_Git.GetCurrentBranch() + L".rebase", m_iPullRebase) == GIT_ENOTFOUND)
265 if (config.GetBOOL(L"pull.rebase", m_iPullRebase) == GIT_ENOTFOUND)
266 break;
267 else
269 CString value;
270 config.GetString(L"pull.rebase", value);
271 if (value == L"preserve")
273 m_iPullRebase = 2;
274 break;
278 else
280 CString value;
281 config.GetString(L"branch." + g_Git.GetCurrentBranch() + L".rebase", value);
282 if (value == L"preserve")
284 m_iPullRebase = 2;
285 break;
288 } while (0);
289 if (m_iPullRebase > 0)
291 CurrentEntry = 1;
292 if (m_strRemoteBranch.IsEmpty())
294 CMessageBox::Show(GetSafeHwnd(), IDS_PROC_PULL_EMPTYBRANCH, IDS_APPNAME, MB_ICONEXCLAMATION);
295 return;
300 SwitchToRun();
302 ShowTab(IDC_CMD_LOG);
304 m_ctrlTabCtrl.ShowTab(IDC_REFLIST - 1, true);
305 m_ctrlTabCtrl.ShowTab(IDC_IN_LOGLIST - 1, false);
306 m_ctrlTabCtrl.ShowTab(IDC_IN_CHANGELIST - 1, false);
307 m_ctrlTabCtrl.ShowTab(IDC_IN_CONFLICT - 1, false);
308 m_ctrlTabCtrl.ShowTab(IDC_TAGCOMPARELIST - 1, false);
310 ///Pull
311 if(CurrentEntry == 0) //Pull
313 CString remotebranch;
314 remotebranch = m_strRemoteBranch;
316 if(!IsURL())
318 CString pullRemote, pullBranch;
319 g_Git.GetRemoteTrackedBranch(m_strLocalBranch, pullRemote, pullBranch);
320 if(pullBranch == remotebranch && pullRemote == this->m_strURL)
321 remotebranch.Empty();
324 cmd.Format(L"git.exe pull -v --progress%s \"%s\" %s",
325 (LPCTSTR)force,
326 (LPCTSTR)m_strURL,
327 (LPCTSTR)remotebranch);
329 m_CurrentCmd = GIT_COMMAND_PULL;
330 m_GitCmdList.push_back(cmd);
332 m_pThread = AfxBeginThread(ProgressThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
333 if (!m_pThread)
335 // ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
337 else
339 m_pThread->m_bAutoDelete = TRUE;
340 m_pThread->ResumeThread();
345 ///Fetch
346 if (CurrentEntry == 1 || CurrentEntry == 2 || CurrentEntry == 3)
348 m_oldRemoteHash.Empty();
349 CString remotebranch;
350 if (CurrentEntry == 3)
351 m_strRemoteBranch.Empty();
352 else if (IsURL() || m_strRemoteBranch.IsEmpty())
354 remotebranch=this->m_strRemoteBranch;
357 else
359 remotebranch.Format(L"remotes/%s/%s", (LPCTSTR)m_strURL, (LPCTSTR)m_strRemoteBranch);
360 g_Git.GetHash(m_oldRemoteHash, remotebranch);
361 if (m_oldRemoteHash.IsEmpty())
362 remotebranch=m_strRemoteBranch;
363 else
364 remotebranch = m_strRemoteBranch + L':' + remotebranch;
367 if (CurrentEntry == 1 || CurrentEntry == 3)
368 m_CurrentCmd = GIT_COMMAND_FETCH;
369 else
370 m_CurrentCmd = GIT_COMMAND_FETCHANDREBASE;
372 if (g_Git.UsingLibGit2(CGit::GIT_CMD_FETCH))
374 CString refspec;
375 if (!remotebranch.IsEmpty())
376 refspec.Format(L"refs/heads/%s:refs/remotes/%s/%s", (LPCTSTR)m_strRemoteBranch, (LPCTSTR)m_strURL, (LPCTSTR)m_strRemoteBranch);
378 progressCommand = std::make_unique<FetchProgressCommand>();
379 FetchProgressCommand* fetchProgressCommand = static_cast<FetchProgressCommand*>(progressCommand.get());
380 fetchProgressCommand->SetUrl(m_strURL);
381 fetchProgressCommand->SetRefSpec(refspec);
382 m_GitProgressList.SetCommand(progressCommand.get());
383 m_GitProgressList.Init();
384 ShowTab(IDC_CMD_GIT_PROG);
386 else
388 cmd.Format(L"git.exe fetch --progress -v%s \"%s\" %s",
389 (LPCTSTR)force,
390 (LPCTSTR)m_strURL,
391 (LPCTSTR)remotebranch);
393 m_GitCmdList.push_back(cmd);
395 m_pThread = AfxBeginThread(ProgressThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
396 if (!m_pThread)
398 // ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
400 else
402 m_pThread->m_bAutoDelete = TRUE;
403 m_pThread->ResumeThread();
408 ///Remote Update
409 if (CurrentEntry == 4)
411 if (m_bAutoLoadPuttyKey)
413 for (size_t i = 0; i < m_remotelist.size(); ++i)
414 CAppUtils::LaunchPAgent(nullptr, &m_remotelist[i]);
417 m_CurrentCmd = GIT_COMMAND_REMOTE;
418 cmd = L"git.exe remote update";
419 m_GitCmdList.push_back(cmd);
421 InterlockedExchange(&m_bBlock, TRUE);
423 m_pThread = AfxBeginThread(ProgressThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
424 if (!m_pThread)
426 // ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
427 InterlockedExchange(&m_bBlock, FALSE);
429 else
431 m_pThread->m_bAutoDelete = TRUE;
432 m_pThread->ResumeThread();
436 ///Cleanup stale remote banches
437 if (CurrentEntry == 5)
439 m_CurrentCmd = GIT_COMMAND_REMOTE;
440 cmd.Format(L"git.exe remote prune \"%s\"", (LPCTSTR)m_strURL);
441 m_GitCmdList.push_back(cmd);
443 InterlockedExchange(&m_bBlock, TRUE);
445 m_pThread = AfxBeginThread(ProgressThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
446 if (!m_pThread)
448 // ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
449 InterlockedExchange(&m_bBlock, FALSE);
451 else
453 m_pThread->m_bAutoDelete = TRUE;
454 m_pThread->ResumeThread();
459 void CSyncDlg::ShowInCommits(const CString& friendname)
461 CGitHash newHash;
463 if (g_Git.GetHash(newHash, friendname))
465 MessageBox(g_Git.GetGitLastErr(L"Could not get " + friendname + L" hash."), L"TortoiseGit", MB_ICONERROR);
466 return;
469 if (newHash == m_oldHash)
471 m_ctrlTabCtrl.ShowTab(IDC_IN_CHANGELIST - 1, false);
472 m_InLogList.ShowText(CString(MAKEINTRESOURCE(IDS_UPTODATE)));
473 m_ctrlTabCtrl.ShowTab(IDC_IN_LOGLIST - 1, true);
474 ShowTab(IDC_REFLIST);
476 else
478 m_ctrlTabCtrl.ShowTab(IDC_IN_CHANGELIST - 1, true);
479 m_ctrlTabCtrl.ShowTab(IDC_IN_LOGLIST - 1, true);
481 AddDiffFileList(&m_InChangeFileList, &m_arInChangeList, newHash.ToString(), m_oldHash.ToString());
483 CString range;
484 range.Format(L"%s..%s", (LPCTSTR)m_oldHash.ToString(), (LPCTSTR)newHash.ToString());
485 m_InLogList.FillGitLog(nullptr, &range, CGit::LOG_INFO_STAT | CGit::LOG_INFO_FILESTATE | CGit::LOG_INFO_SHOW_MERGEDFILE);
486 ShowTab(IDC_IN_LOGLIST);
490 void CSyncDlg::PullComplete()
492 EnableControlButton(true);
493 SwitchToInput();
494 this->FetchOutList(true);
496 if( this ->m_GitCmdStatus )
498 int hasConflicts = g_Git.HasWorkingTreeConflicts();
499 if (hasConflicts < 0)
501 this->m_ctrlCmdOut.SetSel(-1,-1);
502 this->m_ctrlCmdOut.ReplaceSel(g_Git.GetGitLastErr(L"Checking for conflicts failed.", CGit::GIT_CMD_CHECKCONFLICTS));
504 this->ShowTab(IDC_CMD_LOG);
505 return;
508 if (hasConflicts)
510 this->m_ConflictFileList.Clear();
511 this->m_ConflictFileList.GetStatus(nullptr, true);
512 this->m_ConflictFileList.Show(CTGitPath::LOGACTIONS_UNMERGED,
513 CTGitPath::LOGACTIONS_UNMERGED);
515 this->ShowTab(IDC_IN_CONFLICT);
516 CMessageBox::ShowCheck(GetSafeHwnd(), IDS_NEED_TO_RESOLVE_CONFLICTS_HINT, IDS_APPNAME, MB_ICONINFORMATION, L"MergeConflictsNeedsCommit", IDS_MSGBOX_DONOTSHOWAGAIN);
518 else
519 this->ShowTab(IDC_CMD_LOG);
522 else
523 ShowInCommits(L"HEAD");
526 void CSyncDlg::FetchComplete()
528 EnableControlButton(true);
529 SwitchToInput();
531 if (g_Git.UsingLibGit2(CGit::GIT_CMD_FETCH))
532 ShowTab(IDC_CMD_GIT_PROG);
533 else
534 ShowTab(IDC_REFLIST);
536 if (m_GitCmdStatus || (m_CurrentCmd != GIT_COMMAND_FETCHANDREBASE && m_iPullRebase == 0))
538 FetchOutList(true);
539 return;
542 CString remote;
543 CString remotebranch;
544 CString upstream = L"FETCH_HEAD";
545 m_ctrlURL.GetWindowText(remote);
546 if (!remote.IsEmpty())
548 if (std::find(m_remotelist.cbegin(), m_remotelist.cend(), remote) == m_remotelist.cend())
549 remote.Empty();
551 m_ctrlRemoteBranch.GetWindowText(remotebranch);
552 if (!remote.IsEmpty() && !remotebranch.IsEmpty())
553 upstream = L"remotes/" + remote + L'/' + remotebranch;
555 if (m_iPullRebase > 0)
557 CAppUtils::RebaseAfterFetch(upstream, m_iPullRebase ? 2 : 0, m_iPullRebase == 2);
558 FillNewRefMap();
559 FetchOutList(true);
561 ShowInCommits(L"HEAD");
563 return;
566 CGitHash remoteBranchHash;
567 g_Git.GetHash(remoteBranchHash, upstream);
568 if (remoteBranchHash == m_oldRemoteHash && !m_oldRemoteHash.IsEmpty() && CMessageBox::ShowCheck(this->GetSafeHwnd(), IDS_REBASE_BRANCH_UNCHANGED, IDS_APPNAME, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, L"OpenRebaseRemoteBranchUnchanged", IDS_MSGBOX_DONOTSHOWAGAIN) == IDNO)
570 ShowInCommits(upstream);
571 return;
574 if (g_Git.IsFastForward(L"HEAD", upstream))
576 UINT ret = CMessageBox::ShowCheck(GetSafeHwnd(), IDS_REBASE_BRANCH_FF, IDS_APPNAME, 2, IDI_QUESTION, IDS_MERGEBUTTON, IDS_REBASEBUTTON, IDS_ABORTBUTTON, L"OpenRebaseRemoteBranchFastForwards", IDS_MSGBOX_DONOTSHOWAGAIN);
577 if (ret == 3)
578 return;
579 if (ret == 1)
581 CProgressDlg mergeProgress;
582 mergeProgress.m_GitCmd = L"git.exe merge --ff-only " + upstream;
583 mergeProgress.m_AutoClose = AUTOCLOSE_IF_NO_ERRORS;
584 mergeProgress.m_PostCmdCallback = [](DWORD status, PostCmdList& postCmdList)
586 if (status && g_Git.HasWorkingTreeConflicts())
588 // there are conflict files
589 postCmdList.emplace_back(IDI_RESOLVE, IDS_PROGRS_CMD_RESOLVE, []
591 CString sCmd;
592 sCmd.Format(L"/command:commit /path:\"%s\"", (LPCTSTR)g_Git.m_CurrentDir);
593 CAppUtils::RunTortoiseGitProc(sCmd);
597 mergeProgress.DoModal();
598 FillNewRefMap();
599 FetchOutList(true);
601 ShowInCommits(L"HEAD");
603 return;
607 CAppUtils::RebaseAfterFetch(upstream);
608 FillNewRefMap();
609 FetchOutList(true);
611 ShowInCommits(L"HEAD");
614 void CSyncDlg::StashComplete()
616 EnableControlButton(true);
617 INT_PTR entry = m_ctrlStash.GetCurrentEntry();
618 if (entry != 1 && entry != 2)
619 return;
621 SwitchToInput();
622 if (m_GitCmdStatus)
624 int hasConflicts = g_Git.HasWorkingTreeConflicts();
625 if (hasConflicts < 0)
627 m_ctrlCmdOut.SetSel(-1, -1);
628 m_ctrlCmdOut.ReplaceSel(g_Git.GetGitLastErr(L"Checking for conflicts failed.", CGit::GIT_CMD_CHECKCONFLICTS));
630 ShowTab(IDC_CMD_LOG);
631 return;
634 if (hasConflicts)
636 m_ConflictFileList.Clear();
637 m_ConflictFileList.GetStatus(nullptr, true);
638 m_ConflictFileList.Show(CTGitPath::LOGACTIONS_UNMERGED, CTGitPath::LOGACTIONS_UNMERGED);
640 ShowTab(IDC_IN_CONFLICT);
642 else
643 ShowTab(IDC_CMD_LOG);
647 void CSyncDlg::OnBnClickedButtonPush()
649 this->UpdateData();
650 UpdateCombox();
651 m_ctrlCmdOut.SetWindowText(L"");
652 m_LogText.Empty();
654 if(this->m_strURL.IsEmpty())
656 CMessageBox::Show(GetSafeHwnd(), IDS_PROC_GITCONFIG_URLEMPTY, IDS_APPNAME, MB_OK | MB_ICONERROR);
657 return;
660 if (!IsURL() && m_ctrlPush.GetCurrentEntry() == 0 && CRegDWORD(L"Software\\TortoiseGit\\AskSetTrackedBranch", TRUE) == TRUE)
662 if (!AskSetTrackedBranch())
663 return;
666 this->m_regPushButton=(DWORD)this->m_ctrlPush.GetCurrentEntry();
667 this->SwitchToRun();
668 this->m_bAbort=false;
669 this->m_GitCmdList.clear();
671 ShowTab(IDC_CMD_LOG);
673 CString cmd;
674 CString arg;
676 CString error;
677 DWORD exitcode = 0xFFFFFFFF;
678 if (CHooks::Instance().PrePush(g_Git.m_CurrentDir, exitcode, error))
680 if (exitcode)
682 CString temp;
683 temp.Format(IDS_ERR_HOOKFAILED, (LPCTSTR)error);
684 CMessageBox::Show(GetSafeHwnd(), temp, L"TortoiseGit", MB_OK | MB_ICONERROR);
685 return ;
689 CString refName = g_Git.FixBranchName(m_strLocalBranch);
690 switch (m_ctrlPush.GetCurrentEntry())
692 case 1:
693 arg += L" --tags";
694 break;
695 case 2:
696 refName = L"refs/notes/commits"; //default ref for notes
697 break;
700 if(this->m_bForce)
701 arg += L" --force";
703 cmd.Format(L"git.exe push -v --progress%s \"%s\" %s",
704 (LPCTSTR)arg,
705 (LPCTSTR)m_strURL,
706 (LPCTSTR)refName);
708 if (!m_strRemoteBranch.IsEmpty() && m_ctrlPush.GetCurrentEntry() != 2)
710 cmd += L':' + m_strRemoteBranch;
713 m_GitCmdList.push_back(cmd);
715 m_CurrentCmd = GIT_COMMAND_PUSH;
717 if(this->m_bAutoLoadPuttyKey)
719 CAppUtils::LaunchPAgent(nullptr, &m_strURL);
722 m_pThread = AfxBeginThread(ProgressThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
723 if (!m_pThread)
725 // ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
727 else
729 m_pThread->m_bAutoDelete = TRUE;
730 m_pThread->ResumeThread();
734 void CSyncDlg::OnBnClickedButtonApply()
736 CGitHash oldhash;
737 if (g_Git.GetHash(oldhash, L"HEAD"))
739 MessageBox(g_Git.GetGitLastErr(L"Could not get HEAD hash."), L"TortoiseGit", MB_ICONERROR);
740 return;
743 CImportPatchDlg dlg;
744 CString cmd,output;
746 if(dlg.DoModal() == IDOK)
748 int err=0;
749 for (int i = 0; i < dlg.m_PathList.GetCount(); ++i)
751 cmd.Format(L"git.exe am \"%s\"", (LPCTSTR)dlg.m_PathList[i].GetGitPathString());
753 if (g_Git.Run(cmd, &output, CP_UTF8))
755 CMessageBox::Show(GetSafeHwnd(), output, L"TortoiseGit", MB_OK | MB_ICONERROR);
757 err=1;
758 break;
760 this->m_ctrlCmdOut.SetSel(-1,-1);
761 this->m_ctrlCmdOut.ReplaceSel(cmd + L'\n');
762 this->m_ctrlCmdOut.SetSel(-1,-1);
763 this->m_ctrlCmdOut.ReplaceSel(output);
766 CGitHash newhash;
767 if (g_Git.GetHash(newhash, L"HEAD"))
769 MessageBox(g_Git.GetGitLastErr(L"Could not get HEAD hash after applying patches."), L"TortoiseGit", MB_ICONERROR);
770 return;
773 this->m_InLogList.Clear();
774 this->m_InChangeFileList.Clear();
776 if(newhash == oldhash)
778 this->m_ctrlTabCtrl.ShowTab(IDC_IN_CHANGELIST-1,false);
779 this->m_InLogList.ShowText(L"No commits get from patch");
780 this->m_ctrlTabCtrl.ShowTab(IDC_IN_LOGLIST-1,true);
783 else
785 this->m_ctrlTabCtrl.ShowTab(IDC_IN_CHANGELIST-1,true);
786 this->m_ctrlTabCtrl.ShowTab(IDC_IN_LOGLIST-1,true);
788 CString range;
789 range.Format(L"%s..%s", (LPCTSTR)m_oldHash.ToString(), (LPCTSTR)newhash.ToString());
790 this->AddDiffFileList(&m_InChangeFileList, &m_arInChangeList, newhash.ToString(), oldhash.ToString());
791 m_InLogList.FillGitLog(nullptr, &range, CGit::LOG_INFO_STAT| CGit::LOG_INFO_FILESTATE | CGit::LOG_INFO_SHOW_MERGEDFILE);
793 this->FetchOutList(true);
796 this->m_ctrlTabCtrl.ShowTab(IDC_CMD_LOG-1,true);
798 if(err)
800 this->ShowTab(IDC_CMD_LOG);
802 else
804 this->ShowTab(IDC_IN_LOGLIST);
809 void CSyncDlg::OnBnClickedButtonEmail()
811 CString cmd, out, err;
813 this->m_strLocalBranch = this->m_ctrlLocalBranch.GetString();
814 this->m_ctrlRemoteBranch.GetWindowText(this->m_strRemoteBranch);
815 this->m_ctrlURL.GetWindowText(this->m_strURL);
816 m_strURL=m_strURL.Trim();
817 m_strRemoteBranch=m_strRemoteBranch.Trim();
819 cmd.Format(L"git.exe format-patch -o \"%s\" %s..%s",
820 (LPCTSTR)g_Git.m_CurrentDir,
821 (LPCTSTR)(m_strURL + L'/' + m_strRemoteBranch), (LPCTSTR)g_Git.FixBranchName(m_strLocalBranch));
823 if (g_Git.Run(cmd, &out, &err, CP_UTF8))
825 CMessageBox::Show(GetSafeHwnd(), out + L'\n' + err, L"TortoiseGit", MB_OK | MB_ICONERROR);
826 return ;
829 CAppUtils::SendPatchMail(cmd,out);
831 void CSyncDlg::ShowProgressCtrl(bool bShow)
833 int b=bShow?SW_NORMAL:SW_HIDE;
834 this->m_ctrlAnimate.ShowWindow(b);
835 this->m_ctrlProgress.ShowWindow(b);
836 this->m_ctrlProgLabel.ShowWindow(b);
837 this->m_ctrlAnimate.Open(IDR_DOWNLOAD);
838 if(b == SW_NORMAL)
839 this->m_ctrlAnimate.Play(0, UINT_MAX, UINT_MAX);
840 else
841 this->m_ctrlAnimate.Stop();
843 void CSyncDlg::ShowInputCtrl(bool bShow)
845 int b=bShow?SW_NORMAL:SW_HIDE;
846 this->m_ctrlURL.ShowWindow(b);
847 this->m_ctrlLocalBranch.ShowWindow(b);
848 this->m_ctrlRemoteBranch.ShowWindow(b);
849 this->GetDlgItem(IDC_BUTTON_LOCAL_BRANCH)->ShowWindow(b);
850 this->GetDlgItem(IDC_BUTTON_REMOTE_BRANCH)->ShowWindow(b);
851 this->GetDlgItem(IDC_STATIC_LOCAL_BRANCH)->ShowWindow(b);
852 this->GetDlgItem(IDC_STATIC_REMOTE_BRANCH)->ShowWindow(b);
853 this->GetDlgItem(IDC_BUTTON_MANAGE)->ShowWindow(b);
854 this->GetDlgItem(IDC_CHECK_PUTTY_KEY)->ShowWindow(b);
855 this->GetDlgItem(IDC_CHECK_FORCE)->ShowWindow(b);
856 this->GetDlgItem(IDC_STATIC_REMOTE_URL)->ShowWindow(b);
858 BOOL CSyncDlg::OnInitDialog()
860 CResizableStandAloneDialog::OnInitDialog();
861 CAppUtils::MarkWindowAsUnpinnable(m_hWnd);
863 // Let the TaskbarButtonCreated message through the UIPI filter. If we don't
864 // do this, Explorer would be unable to send that message to our window if we
865 // were running elevated. It's OK to make the call all the time, since if we're
866 // not elevated, this is a no-op.
867 CHANGEFILTERSTRUCT cfs = { sizeof(CHANGEFILTERSTRUCT) };
868 typedef BOOL STDAPICALLTYPE ChangeWindowMessageFilterExDFN(HWND hWnd, UINT message, DWORD action, PCHANGEFILTERSTRUCT pChangeFilterStruct);
869 CAutoLibrary hUser = AtlLoadSystemLibraryUsingFullPath(L"user32.dll");
870 if (hUser)
872 ChangeWindowMessageFilterExDFN *pfnChangeWindowMessageFilterEx = (ChangeWindowMessageFilterExDFN*)GetProcAddress(hUser, "ChangeWindowMessageFilterEx");
873 if (pfnChangeWindowMessageFilterEx)
875 pfnChangeWindowMessageFilterEx(m_hWnd, TaskBarButtonCreated, MSGFLT_ALLOW, &cfs);
878 m_pTaskbarList.Release();
879 if (FAILED(m_pTaskbarList.CoCreateInstance(CLSID_TaskbarList)))
880 m_pTaskbarList = nullptr;
882 this->GetDlgItem(IDC_CHECK_PUTTY_KEY)->EnableWindow(CAppUtils::IsSSHPutty());
885 this->m_ctrlAnimate.ShowWindow(SW_NORMAL);
886 this->m_ctrlAnimate.Open(IDR_DOWNLOAD);
887 this->m_ctrlAnimate.Play(0,-1,-1);
890 // ------------------ Create Tabctrl -----------
891 CWnd *pwnd=this->GetDlgItem(IDC_BUTTON_TABCTRL);
892 CRect rectDummy;
893 pwnd->GetWindowRect(&rectDummy);
894 this->ScreenToClient(rectDummy);
896 if (!m_ctrlTabCtrl.Create(CMFCTabCtrl::STYLE_FLAT, rectDummy, this, IDC_SYNC_TAB))
898 TRACE0("Failed to create output tab window\n");
899 return FALSE; // fail to create
901 m_ctrlTabCtrl.SetResizeMode(CMFCTabCtrl::RESIZE_NO);
903 // -------------Create Command Log Ctrl ---------
904 DWORD dwStyle;
905 dwStyle= ES_MULTILINE | ES_READONLY | WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_AUTOVSCROLL |WS_VSCROLL ;
907 if( !m_ctrlCmdOut.Create(dwStyle,rectDummy,&m_ctrlTabCtrl,IDC_CMD_LOG))
909 TRACE0("Failed to create Log commits window\n");
910 return FALSE; // fail to create
913 // set the font to use in the log message view, configured in the settings dialog
914 CFont m_logFont;
915 CAppUtils::CreateFontForLogs(m_logFont);
916 m_ctrlCmdOut.SetFont(&m_logFont);
917 m_ctrlTabCtrl.InsertTab(&m_ctrlCmdOut, CString(MAKEINTRESOURCE(IDS_LOG)), -1);
918 // make the log message rich edit control send a message when the mouse pointer is over a link
919 m_ctrlCmdOut.SendMessage(EM_SETEVENTMASK, NULL, ENM_LINK | ENM_SCROLL);
921 //---------- Create in coming list ctrl -----------
922 dwStyle =LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_OWNERDATA | WS_BORDER | WS_TABSTOP | WS_CHILD | WS_VISIBLE;;
924 if( !m_InLogList.Create(dwStyle,rectDummy,&m_ctrlTabCtrl,IDC_IN_LOGLIST))
926 TRACE0("Failed to create output commits window\n");
927 return FALSE; // fail to create
929 // for some unknown reason, the SetExtendedStyle in OnCreate/PreSubclassWindow is not working here
930 m_InLogList.SetStyle();
932 m_ctrlTabCtrl.InsertTab(&m_InLogList, CString(MAKEINTRESOURCE(IDS_PROC_SYNC_INCOMMITS)), -1);
934 m_InLogList.m_ColumnRegKey = L"SyncIn";
935 m_InLogList.InsertGitColumn();
937 //----------- Create In Change file list -----------
938 dwStyle = LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP | WS_CHILD | WS_VISIBLE;
940 if( !m_InChangeFileList.Create(dwStyle,rectDummy,&m_ctrlTabCtrl,IDC_IN_CHANGELIST))
942 TRACE0("Failed to create output change files window\n");
943 return FALSE; // fail to create
945 m_ctrlTabCtrl.InsertTab(&m_InChangeFileList, CString(MAKEINTRESOURCE(IDS_PROC_SYNC_INCHANGELIST)), -1);
947 m_InChangeFileList.Init(GITSLC_COLEXT | GITSLC_COLSTATUS |GITSLC_COLADD|GITSLC_COLDEL, L"InSyncDlg",
948 (CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_COMPARETWOREVISIONS) |
949 CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_GNUDIFF2REVISIONS)), false, false, GITSLC_COLEXT | GITSLC_COLSTATUS | GITSLC_COLADD | GITSLC_COLDEL);
952 //---------- Create Conflict List Ctrl -----------------
953 dwStyle = LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP | WS_CHILD | WS_VISIBLE;
955 if( !m_ConflictFileList.Create(dwStyle,rectDummy,&m_ctrlTabCtrl,IDC_IN_CONFLICT))
957 TRACE0("Failed to create output change files window\n");
958 return FALSE; // fail to create
960 m_ctrlTabCtrl.InsertTab(&m_ConflictFileList, CString(MAKEINTRESOURCE(IDS_PROC_SYNC_CONFLICTS)), -1);
962 m_ConflictFileList.Init(GITSLC_COLEXT | GITSLC_COLSTATUS |GITSLC_COLADD|GITSLC_COLDEL, L"ConflictSyncDlg",
963 (GITSLC_POPEXPLORE | GITSLC_POPOPEN | GITSLC_POPSHOWLOG |
964 GITSLC_POPCONFLICT|GITSLC_POPRESOLVE),false);
967 //---------- Create Commit Out List Ctrl---------------
969 dwStyle =LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_OWNERDATA | WS_BORDER | WS_TABSTOP | WS_CHILD | WS_VISIBLE;;
971 if( !m_OutLogList.Create(dwStyle,rectDummy,&m_ctrlTabCtrl,IDC_OUT_LOGLIST))
973 TRACE0("Failed to create output commits window\n");
974 return FALSE; // fail to create
977 // for some unknown reason, the SetExtendedStyle in OnCreate/PreSubclassWindow is not working here
978 m_OutLogList.SetStyle();
980 m_ctrlTabCtrl.InsertTab(&m_OutLogList, CString(MAKEINTRESOURCE(IDS_PROC_SYNC_OUTCOMMITS)), -1);
982 m_OutLogList.m_ColumnRegKey = L"SyncOut";
983 m_OutLogList.InsertGitColumn();
985 //------------- Create Change File List Control ----------------
987 dwStyle = LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP | WS_CHILD | WS_VISIBLE;
989 if( !m_OutChangeFileList.Create(dwStyle,rectDummy,&m_ctrlTabCtrl,IDC_OUT_CHANGELIST))
991 TRACE0("Failed to create output change files window\n");
992 return FALSE; // fail to create
994 m_ctrlTabCtrl.InsertTab(&m_OutChangeFileList, CString(MAKEINTRESOURCE(IDS_PROC_SYNC_OUTCHANGELIST)), -1);
996 m_OutChangeFileList.Init(GITSLC_COLEXT | GITSLC_COLSTATUS | GITSLC_COLADD | GITSLC_COLDEL, L"OutSyncDlg",
997 (CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_COMPARETWOREVISIONS) |
998 CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_GNUDIFF2REVISIONS)), false, false, GITSLC_COLEXT | GITSLC_COLSTATUS | GITSLC_COLADD | GITSLC_COLDEL);
1000 dwStyle = LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP | LVS_SINGLESEL | WS_CHILD | WS_VISIBLE;
1001 if (!m_GitProgressList.Create(dwStyle | LVS_OWNERDATA, rectDummy, &m_ctrlTabCtrl, IDC_CMD_GIT_PROG))
1003 TRACE0("Failed to create Git Progress List Window\n");
1004 return FALSE; // fail to create
1006 m_ctrlTabCtrl.InsertTab(&m_GitProgressList, CString(MAKEINTRESOURCE(IDS_LOG)), -1);
1007 m_GitProgressList.m_pAnimate = &m_ctrlAnimate;
1008 m_GitProgressList.m_pPostWnd = this;
1009 m_GitProgressList.m_pProgressLabelCtrl = &m_ctrlProgLabel;
1010 m_GitProgressList.m_pProgControl = &m_ctrlProgress;
1011 m_GitProgressList.m_pTaskbarList = m_pTaskbarList;
1013 dwStyle = LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP | WS_CHILD | WS_VISIBLE | LVS_SINGLESEL;
1014 DWORD exStyle = LVS_EX_HEADERDRAGDROP | LVS_EX_DOUBLEBUFFER | LVS_EX_INFOTIP;
1015 if (CRegDWORD(L"Software\\TortoiseGit\\FullRowSelect", TRUE))
1016 exStyle |= LVS_EX_FULLROWSELECT;
1017 if (g_Git.m_IsUseLibGit2)
1019 m_refList.Create(dwStyle, rectDummy, &m_ctrlTabCtrl, IDC_REFLIST);
1020 m_refList.SetExtendedStyle(exStyle);
1021 m_refList.Init();
1022 m_ctrlTabCtrl.InsertTab(&m_refList, CString(MAKEINTRESOURCE(IDS_REFLIST)), -1);
1024 m_tagCompareList.Create(dwStyle, rectDummy, &m_ctrlTabCtrl, IDC_TAGCOMPARELIST);
1025 m_tagCompareList.SetExtendedStyle(exStyle);
1026 m_tagCompareList.Init();
1027 m_ctrlTabCtrl.InsertTab(&m_tagCompareList, CString(MAKEINTRESOURCE(IDS_PROC_SYNC_COMPARETAGS)), -1);
1030 AdjustControlSize(IDC_CHECK_PUTTY_KEY);
1031 AdjustControlSize(IDC_CHECK_FORCE);
1033 AddAnchor(IDC_SYNC_TAB,TOP_LEFT,BOTTOM_RIGHT);
1035 AddAnchor(IDC_GROUP_INFO,TOP_LEFT,TOP_RIGHT);
1036 AddAnchor(IDC_COMBOBOXEX_URL,TOP_LEFT,TOP_RIGHT);
1037 AddAnchor(IDC_BUTTON_MANAGE,TOP_RIGHT);
1038 AddAnchor(IDC_BUTTON_PULL,BOTTOM_LEFT);
1039 AddAnchor(IDC_BUTTON_PUSH,BOTTOM_LEFT);
1040 AddAnchor(IDC_BUTTON_SUBMODULE,BOTTOM_LEFT);
1041 AddAnchor(IDC_BUTTON_STASH,BOTTOM_LEFT);
1042 AddAnchor(IDC_BUTTON_APPLY,BOTTOM_RIGHT);
1043 AddAnchor(IDC_BUTTON_EMAIL,BOTTOM_RIGHT);
1044 AddAnchor(IDC_PROGRESS_SYNC,TOP_LEFT,TOP_RIGHT);
1045 AddAnchor(IDOK,BOTTOM_RIGHT);
1046 AddAnchor(IDHELP,BOTTOM_RIGHT);
1047 AddAnchor(IDC_STATIC_STATUS, BOTTOM_LEFT, BOTTOM_RIGHT);
1048 AddAnchor(IDC_ANIMATE_SYNC,TOP_LEFT);
1049 AddAnchor(IDC_BUTTON_COMMIT,BOTTOM_LEFT);
1050 AddAnchor(IDC_LOG, BOTTOM_LEFT);
1052 // do not use BRANCH_COMBOX_ADD_ANCHOR here, we want to have different stylings
1053 AddAnchor(IDC_COMBOBOXEX_LOCAL_BRANCH, TOP_LEFT,TOP_CENTER);
1054 AddAnchor(IDC_COMBOBOXEX_REMOTE_BRANCH, TOP_CENTER, TOP_RIGHT);
1055 AddAnchor(IDC_BUTTON_LOCAL_BRANCH, TOP_CENTER);
1056 AddAnchor(IDC_BUTTON_REMOTE_BRANCH, TOP_RIGHT);
1057 AddAnchor(IDC_STATIC_REMOTE_BRANCH, TOP_CENTER);
1058 AddAnchor(IDC_PROG_LABEL, TOP_LEFT);
1060 CString WorkingDir=g_Git.m_CurrentDir;
1061 WorkingDir.Replace(L':', L'_');
1062 m_RegKeyRemoteBranch = L"Software\\TortoiseGit\\History\\SyncBranch\\" + WorkingDir;
1065 this->AddOthersToAnchor();
1067 this->m_ctrlPush.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_PUSH)));
1068 this->m_ctrlPush.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_PUSHTAGS)));
1069 this->m_ctrlPush.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_PUSHNOTES)));
1071 this->m_ctrlPull.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_PULL)));
1072 this->m_ctrlPull.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_FETCH)));
1073 this->m_ctrlPull.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_FETCHREBASE)));
1074 this->m_ctrlPull.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_FETCHALL)));
1075 this->m_ctrlPull.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_REMOTEUPDATE)));
1076 this->m_ctrlPull.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_CLEANUPSTALEBRANCHES)));
1077 this->m_ctrlPull.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_COMPARETAGS)));
1079 this->m_ctrlSubmodule.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_SUBKODULEUPDATE)));
1080 this->m_ctrlSubmodule.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_SUBKODULEINIT)));
1081 this->m_ctrlSubmodule.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_SUBKODULESYNC)));
1083 this->m_ctrlStash.AddEntry(CString(MAKEINTRESOURCE(IDS_MENUSTASHSAVE)));
1084 this->m_ctrlStash.AddEntry(CString(MAKEINTRESOURCE(IDS_MENUSTASHPOP)));
1085 this->m_ctrlStash.AddEntry(CString(MAKEINTRESOURCE(IDS_MENUSTASHAPPLY)));
1087 WorkingDir.Replace(L':', L'_');
1089 CString regkey ;
1090 regkey.Format(L"Software\\TortoiseGit\\TortoiseProc\\Sync\\%s", (LPCTSTR)WorkingDir);
1092 this->m_regPullButton = CRegDWORD(regkey + L"\\Pull", 0);
1093 this->m_regPushButton = CRegDWORD(regkey + L"\\Push", 0);
1094 this->m_regSubmoduleButton = CRegDWORD(regkey + L"\\Submodule");
1095 this->m_regAutoLoadPutty = CRegDWORD(regkey + L"\\AutoLoadPutty", CAppUtils::IsSSHPutty());
1097 this->UpdateData();
1098 this->m_bAutoLoadPuttyKey = m_regAutoLoadPutty;
1099 if(!CAppUtils::IsSSHPutty())
1100 m_bAutoLoadPuttyKey = false;
1101 this->UpdateData(FALSE);
1103 this->m_ctrlPull.SetCurrentEntry(this->m_regPullButton);
1104 this->m_ctrlPush.SetCurrentEntry(this->m_regPushButton);
1105 this->m_ctrlSubmodule.SetCurrentEntry(this->m_regSubmoduleButton);
1107 CString sWindowTitle;
1108 GetWindowText(sWindowTitle);
1109 CAppUtils::SetWindowTitle(m_hWnd, g_Git.m_CurrentDir, sWindowTitle);
1111 EnableSaveRestore(L"SyncDlg");
1113 m_ctrlURL.SetCaseSensitive(TRUE);
1115 m_ctrlURL.SetCustomAutoSuggest(true, true, true);
1116 m_ctrlURL.SetMaxHistoryItems(0x7FFFFFFF);
1117 this->m_ctrlURL.LoadHistory(L"Software\\TortoiseGit\\History\\SyncURL\\" + WorkingDir, L"url");
1119 m_remotelist.clear();
1120 if(!g_Git.GetRemoteList(m_remotelist))
1122 for (unsigned int i = 0; i < m_remotelist.size(); ++i)
1124 m_ctrlURL.AddString(m_remotelist[i]);
1127 m_ctrlURL.SetCurSel(0);
1128 m_ctrlRemoteBranch.SetCurSel(0);
1130 this->LoadBranchInfo();
1132 this->m_bInited=true;
1133 FetchOutList();
1135 m_ctrlTabCtrl.ShowTab(IDC_CMD_LOG-1,false);
1136 m_ctrlTabCtrl.ShowTab(IDC_IN_LOGLIST-1,false);
1137 m_ctrlTabCtrl.ShowTab(IDC_IN_CHANGELIST-1,false);
1138 m_ctrlTabCtrl.ShowTab(IDC_IN_CONFLICT-1,false);
1139 m_ctrlTabCtrl.ShowTab(IDC_CMD_GIT_PROG-1, false);
1140 m_ctrlTabCtrl.ShowTab(IDC_REFLIST-1, false);
1141 m_ctrlTabCtrl.ShowTab(IDC_TAGCOMPARELIST - 1, false);
1143 m_ctrlRemoteBranch.m_bWantReturn = TRUE;
1144 m_ctrlURL.m_bWantReturn = TRUE;
1146 if (m_seq > 0 && (DWORD)CRegDWORD(L"Software\\TortoiseGit\\SyncDialogRandomPos"))
1148 m_seq %= 5;
1149 RECT rect;
1150 GetWindowRect(&rect);
1151 rect.top -= m_seq * 30;
1152 rect.bottom -= m_seq * 30;
1153 if (rect.top < 0)
1155 rect.top += 150;
1156 rect.bottom += 150;
1158 MoveWindow(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
1161 return TRUE; // return TRUE unless you set the focus to a control
1162 // EXCEPTION: OCX Property Pages should return FALSE
1165 void CSyncDlg::OnBnClickedButtonManage()
1167 CAppUtils::LaunchRemoteSetting();
1168 Refresh();
1171 void CSyncDlg::Refresh()
1173 theApp.DoWaitCursor(1);
1175 int lastSelected = m_ctrlURL.GetCurSel();
1176 CString url;
1177 this->m_ctrlURL.GetWindowText(url);
1179 this->m_ctrlURL.Reset();
1180 CString workingDir = g_Git.m_CurrentDir;
1181 workingDir.Replace(L':', L'_');
1182 this->m_ctrlURL.LoadHistory(L"Software\\TortoiseGit\\History\\SyncURL\\" + workingDir, L"url");
1184 bool found = false;
1185 m_remotelist.clear();
1186 if (!g_Git.GetRemoteList(m_remotelist))
1188 for (size_t i = 0; i < m_remotelist.size(); ++i)
1190 m_ctrlURL.AddString(m_remotelist[i]);
1191 if (m_remotelist[i] == url)
1192 found = true;
1195 if (lastSelected >= 0 && !found)
1197 m_ctrlURL.SetCurSel(0);
1198 m_ctrlURL.GetWindowText(url);
1201 CString local;
1202 CString remote;
1203 this->m_ctrlLocalBranch.GetWindowText(local);
1204 this->m_ctrlRemoteBranch.GetWindowText(remote);
1206 this->LoadBranchInfo();
1208 this->m_ctrlLocalBranch.AddString(local);
1209 this->m_ctrlRemoteBranch.AddString(remote);
1210 this->m_ctrlURL.AddString(url);
1212 m_OutLogList.ShowText(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_REFRESHING)));
1213 this->FetchOutList(true);
1214 theApp.DoWaitCursor(-1);
1217 BOOL CSyncDlg::PreTranslateMessage(MSG* pMsg)
1219 if (pMsg->message == WM_KEYDOWN)
1221 switch (pMsg->wParam)
1223 case VK_F5:
1225 if (m_bBlock)
1226 return CResizableStandAloneDialog::PreTranslateMessage(pMsg);
1227 Refresh();
1229 break;
1231 /* Avoid TAB control destroy but dialog exist*/
1232 case VK_ESCAPE:
1233 case VK_CANCEL:
1235 TCHAR buff[129];
1236 ::GetClassName(pMsg->hwnd, buff, _countof(buff) - 1);
1238 /* Use MSFTEDIT_CLASS http://msdn.microsoft.com/en-us/library/bb531344.aspx */
1239 if (_wcsnicmp(buff, MSFTEDIT_CLASS, _countof(buff) - 1) == 0 || //Unicode and MFC 2012 and later
1240 _wcsnicmp(buff, RICHEDIT_CLASS, _countof(buff) - 1) == 0 || //ANSI or MFC 2010
1241 _wcsnicmp(buff, L"SysListView32", _countof(buff) - 1) == 0)
1243 this->PostMessage(WM_KEYDOWN,VK_ESCAPE,0);
1244 return TRUE;
1249 return __super::PreTranslateMessage(pMsg);
1251 void CSyncDlg::FetchOutList(bool force)
1253 if (!m_bInited || m_bWantToExit)
1254 return;
1255 m_OutChangeFileList.Clear();
1256 this->m_OutLogList.Clear();
1258 m_ctrlTabCtrl.ShowTab(IDC_OUT_LOGLIST - 1, true);
1259 m_ctrlTabCtrl.ShowTab(IDC_OUT_CHANGELIST - 1, true);
1261 CString remote;
1262 this->m_ctrlURL.GetWindowText(remote);
1263 CString remotebranch;
1264 this->m_ctrlRemoteBranch.GetWindowText(remotebranch);
1265 remotebranch = remote + L'/' + remotebranch;
1266 CGitHash remotebranchHash;
1267 g_Git.GetHash(remotebranchHash, remotebranch);
1269 if(IsURL())
1271 CString str;
1272 str.LoadString(IDS_PROC_SYNC_PUSH_UNKNOWN);
1273 m_OutLogList.ShowText(str);
1274 this->m_ctrlTabCtrl.ShowTab(m_OutChangeFileList.GetDlgCtrlID()-1,FALSE);
1275 m_OutLocalBranch.Empty();
1276 m_OutRemoteBranch.Empty();
1278 this->GetDlgItem(IDC_BUTTON_EMAIL)->EnableWindow(FALSE);
1279 return ;
1282 else if(remotebranchHash.IsEmpty())
1284 CString str;
1285 str.Format(IDS_PROC_SYNC_PUSH_UNKNOWNBRANCH, (LPCTSTR)remotebranch);
1286 m_OutLogList.ShowText(str);
1287 this->m_ctrlTabCtrl.ShowTab(m_OutChangeFileList.GetDlgCtrlID()-1,FALSE);
1288 m_OutLocalBranch.Empty();
1289 m_OutRemoteBranch.Empty();
1291 this->GetDlgItem(IDC_BUTTON_EMAIL)->EnableWindow(FALSE);
1292 return ;
1294 else
1296 CString localbranch;
1297 localbranch=this->m_ctrlLocalBranch.GetString();
1299 if(localbranch != m_OutLocalBranch || m_OutRemoteBranch != remotebranch || force)
1301 m_OutLogList.ClearText();
1303 CGitHash base, localBranchHash;
1304 bool isFastForward = g_Git.IsFastForward(remotebranch, localbranch, &base);
1306 if (g_Git.GetHash(localBranchHash, localbranch))
1308 MessageBox(g_Git.GetGitLastErr(L"Could not get hash of \"" + localbranch + L"\"."), L"TortoiseGit", MB_ICONERROR);
1309 return;
1311 if (remotebranchHash == localBranchHash)
1313 CString str;
1314 str.Format(IDS_PROC_SYNC_COMMITSAHEAD, 0, (LPCTSTR)remotebranch);
1315 m_OutLogList.ShowText(str);
1316 this->m_ctrlStatus.SetWindowText(str);
1317 this->m_ctrlTabCtrl.ShowTab(m_OutChangeFileList.GetDlgCtrlID()-1,FALSE);
1318 this->GetDlgItem(IDC_BUTTON_EMAIL)->EnableWindow(FALSE);
1320 else if (isFastForward || m_bForce)
1322 CString range;
1323 range.Format(L"%s..%s", (LPCTSTR)g_Git.FixBranchName(remotebranch), (LPCTSTR)g_Git.FixBranchName(localbranch));
1324 //fast forward
1325 m_OutLogList.FillGitLog(nullptr, &range, CGit::LOG_INFO_STAT | CGit::LOG_INFO_FILESTATE | CGit::LOG_INFO_SHOW_MERGEDFILE);
1326 CString str;
1327 str.Format(IDS_PROC_SYNC_COMMITSAHEAD, m_OutLogList.GetItemCount(), (LPCTSTR)remotebranch);
1328 this->m_ctrlStatus.SetWindowText(str);
1330 if (isFastForward)
1331 AddDiffFileList(&m_OutChangeFileList, &m_arOutChangeList, localbranch, remotebranch);
1332 else
1334 AddDiffFileList(&m_OutChangeFileList, &m_arOutChangeList, localbranch, base.ToString());
1337 this->m_ctrlTabCtrl.ShowTab(m_OutChangeFileList.GetDlgCtrlID()-1,TRUE);
1338 this->GetDlgItem(IDC_BUTTON_EMAIL)->EnableWindow(TRUE);
1340 else
1342 CString str;
1343 str.Format(IDS_PROC_SYNC_NOFASTFORWARD, (LPCTSTR)localbranch, (LPCTSTR)remotebranch);
1344 m_OutLogList.ShowText(str);
1345 this->m_ctrlStatus.SetWindowText(str);
1346 this->m_ctrlTabCtrl.ShowTab(m_OutChangeFileList.GetDlgCtrlID() - 1, FALSE);
1347 this->GetDlgItem(IDC_BUTTON_EMAIL)->EnableWindow(FALSE);
1350 this->m_OutLocalBranch=localbranch;
1351 this->m_OutRemoteBranch=remotebranch;
1355 bool CSyncDlg::IsURL()
1357 CString str;
1358 this->m_ctrlURL.GetWindowText(str);
1359 return str.Find(L'\\') >= 0 || str.Find(L'/') >= 0;
1362 void CSyncDlg::OnCbnEditchangeComboboxex()
1364 SetTimer(IDT_INPUT, 1000, nullptr);
1365 this->m_OutLogList.ShowText(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_WAINTINPUT)));
1367 //this->FetchOutList();
1370 UINT CSyncDlg::ProgressThread()
1372 m_startTick = GetTickCount64();
1373 m_bDone = false;
1374 STRING_VECTOR list;
1375 CProgressDlg::RunCmdList(this, m_GitCmdList, list, true, nullptr, &this->m_bAbort, &this->m_Databuf);
1376 InterlockedExchange(&m_bBlock, FALSE);
1377 return 0;
1380 LRESULT CSyncDlg::OnProgressUpdateUI(WPARAM wParam,LPARAM lParam)
1382 if (m_bWantToExit)
1383 return 0;
1384 if(wParam == MSG_PROGRESSDLG_START)
1386 m_BufStart = 0;
1387 m_ctrlAnimate.Play(0, UINT_MAX, UINT_MAX);
1388 this->m_ctrlProgress.SetPos(0);
1389 if (m_pTaskbarList)
1391 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NORMAL);
1392 m_pTaskbarList->SetProgressValue(m_hWnd, 0, 100);
1396 if(wParam == MSG_PROGRESSDLG_END || wParam == MSG_PROGRESSDLG_FAILED)
1398 ULONGLONG tickSpent = GetTickCount64() - m_startTick;
1399 CString strEndTime = CLoglistUtils::FormatDateAndTime(CTime::GetCurrentTime(), DATE_SHORTDATE, true, false);
1401 m_BufStart = 0;
1402 m_Databuf.m_critSec.Lock();
1403 m_Databuf.clear();
1404 m_Databuf.m_critSec.Unlock();
1406 m_bDone = true;
1407 m_ctrlAnimate.Stop();
1408 m_ctrlProgress.SetPos(100);
1409 //this->DialogEnableWindow(IDOK,TRUE);
1412 CString text;
1413 m_ctrlCmdOut.GetWindowText(text);
1414 text.Remove('\r');
1415 CAppUtils::StyleURLs(text, &m_ctrlCmdOut);
1418 DWORD exitCode = (DWORD)lParam;
1419 if (exitCode)
1421 if (m_pTaskbarList)
1423 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_ERROR);
1424 m_pTaskbarList->SetProgressValue(m_hWnd, 100, 100);
1426 CString log;
1427 log.Format(IDS_PROC_PROGRESS_GITUNCLEANEXIT, exitCode);
1428 CString err;
1429 err.Format(L"\r\n\r\n%s (%I64u ms @ %s)\r\n", (LPCTSTR)log, tickSpent, (LPCTSTR)strEndTime);
1430 CProgressDlg::InsertColorText(this->m_ctrlCmdOut, err, RGB(255,0,0));
1431 if (CRegDWORD(L"Software\\TortoiseGit\\NoSounds", FALSE) == FALSE)
1432 PlaySound((LPCTSTR)SND_ALIAS_SYSTEMEXCLAMATION, nullptr, SND_ALIAS_ID | SND_ASYNC);
1434 else
1436 if (m_pTaskbarList)
1437 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NOPROGRESS);
1438 CString temp;
1439 temp.LoadString(IDS_SUCCESS);
1440 CString log;
1441 log.Format(L"\r\n%s (%I64u ms @ %s)\r\n", (LPCTSTR)temp, tickSpent, (LPCTSTR)strEndTime);
1442 CProgressDlg::InsertColorText(this->m_ctrlCmdOut, log, RGB(0,0,255));
1444 m_GitCmdStatus = exitCode;
1446 //if(wParam == MSG_PROGRESSDLG_END)
1447 RunPostAction();
1450 if(lParam != 0)
1451 ParserCmdOutput((char)lParam);
1452 else
1454 m_Databuf.m_critSec.Lock();
1455 for (size_t i = m_BufStart; i < m_Databuf.size(); ++i)
1457 char c = m_Databuf[m_BufStart];
1458 ++m_BufStart;
1459 m_Databuf.m_critSec.Unlock();
1460 ParserCmdOutput(c);
1462 m_Databuf.m_critSec.Lock();
1465 if (m_BufStart > 1000)
1467 m_Databuf.erase(m_Databuf.cbegin(), m_Databuf.cbegin() + m_BufStart);
1468 m_BufStart = 0;
1470 m_Databuf.m_critSec.Unlock();
1473 return 0;
1476 static REF_VECTOR HashMapToRefMap(MAP_HASH_NAME& map)
1478 auto rmap = REF_VECTOR();
1479 for (auto mit = map.cbegin(); mit != map.cend(); ++mit)
1481 for (auto rit = mit->second.cbegin(); rit != mit->second.cend(); ++rit)
1483 rmap.emplace_back(TGitRef{ *rit, mit->first });
1486 return rmap;
1489 void CSyncDlg::FillNewRefMap()
1491 m_refList.Clear();
1492 m_newHashMap.clear();
1494 if (!g_Git.m_IsUseLibGit2)
1495 return;
1497 CAutoRepository repo(g_Git.GetGitRepository());
1498 if (!repo)
1500 CMessageBox::Show(m_hWnd, CGit::GetLibGit2LastErr(L"Could not open repository."), L"TortoiseGit", MB_OK | MB_ICONERROR);
1501 return;
1504 if (CGit::GetMapHashToFriendName(repo, m_newHashMap))
1506 MessageBox(CGit::GetLibGit2LastErr(L"Could not get all refs."), L"TortoiseGit", MB_ICONERROR);
1507 return;
1510 auto oldRefMap = HashMapToRefMap(m_oldHashMap);
1511 auto newRefMap = HashMapToRefMap(m_newHashMap);
1512 for (auto oit = oldRefMap.cbegin(); oit != oldRefMap.cend(); ++oit)
1514 bool found = false;
1515 for (auto nit = newRefMap.cbegin(); nit != newRefMap.cend(); ++nit)
1517 // changed ref
1518 if (oit->name == nit->name)
1520 found = true;
1521 m_refList.AddEntry(repo, oit->name, &oit->hash, &nit->hash);
1522 break;
1525 // deleted ref
1526 if (!found)
1527 m_refList.AddEntry(repo, oit->name, &oit->hash, nullptr);
1529 for (auto nit = newRefMap.cbegin(); nit != newRefMap.cend(); ++nit)
1531 bool found = false;
1532 for (auto oit = oldRefMap.cbegin(); oit != oldRefMap.cend(); ++oit)
1534 if (oit->name == nit->name)
1536 found = true;
1537 break;
1540 // new ref
1541 if (!found)
1542 m_refList.AddEntry(repo, nit->name, nullptr, &nit->hash);
1544 m_refList.Show();
1547 void CSyncDlg::RunPostAction()
1549 if (m_bWantToExit)
1550 return;
1552 FillNewRefMap();
1554 if (this->m_CurrentCmd == GIT_COMMAND_PUSH)
1556 DWORD exitcode = 0xFFFFFFFF;
1557 CString error;
1558 if (CHooks::Instance().PostPush(g_Git.m_CurrentDir, exitcode, error))
1560 if (exitcode)
1562 CString temp;
1563 temp.Format(IDS_ERR_HOOKFAILED, (LPCTSTR)error);
1564 CMessageBox::Show(GetSafeHwnd(), temp, L"TortoiseGit", MB_OK | MB_ICONERROR);
1565 return;
1569 EnableControlButton(true);
1570 SwitchToInput();
1571 this->FetchOutList(true);
1573 else if (this->m_CurrentCmd == GIT_COMMAND_PULL)
1574 PullComplete();
1575 else if (this->m_CurrentCmd == GIT_COMMAND_FETCH || this->m_CurrentCmd == GIT_COMMAND_FETCHANDREBASE)
1576 FetchComplete();
1577 else if (this->m_CurrentCmd == GIT_COMMAND_SUBMODULE)
1579 //this->m_ctrlCmdOut.SetSel(-1,-1);
1580 //this->m_ctrlCmdOut.ReplaceSel(L"Done\r\n");
1581 //this->m_ctrlCmdOut.SetSel(-1,-1);
1582 EnableControlButton(true);
1583 SwitchToInput();
1585 else if (this->m_CurrentCmd == GIT_COMMAND_STASH)
1586 StashComplete();
1587 else if (this->m_CurrentCmd == GIT_COMMAND_REMOTE)
1589 this->FetchOutList(true);
1590 EnableControlButton(true);
1591 SwitchToInput();
1592 ShowTab(IDC_REFLIST);
1595 void CSyncDlg::ParserCmdOutput(char ch)
1597 if (m_bAbort)
1598 return;
1599 CProgressDlg::ParserCmdOutput(m_ctrlCmdOut,m_ctrlProgress,m_hWnd,m_pTaskbarList,m_LogText,ch);
1601 void CSyncDlg::OnBnClickedButtonCommit()
1603 CString cmd = L"/command:commit";
1604 cmd += L" /path:\"";
1605 cmd += g_Git.m_CurrentDir;
1606 cmd += L'"';
1608 CAppUtils::RunTortoiseGitProc(cmd);
1611 void CSyncDlg::OnOK()
1613 UpdateCombox();
1614 this->UpdateData();
1615 m_ctrlURL.SaveHistory();
1616 SaveHistory();
1617 m_regAutoLoadPutty = this->m_bAutoLoadPuttyKey;
1618 m_tooltips.Pop();
1619 __super::OnOK();
1622 void CSyncDlg::OnCancel()
1624 m_bAbort = true;
1625 m_GitProgressList.Cancel();
1626 if (m_bDone && !m_GitProgressList.IsRunning())
1628 CResizableStandAloneDialog::OnCancel();
1629 return;
1631 if (m_GitProgressList.IsRunning())
1632 WaitForSingleObject(m_GitProgressList.m_pThread->m_hThread, 10000);
1634 if (g_Git.m_CurrentGitPi.hProcess)
1636 DWORD dwConfirmKillProcess = CRegDWORD(L"Software\\TortoiseGit\\ConfirmKillProcess");
1637 if (dwConfirmKillProcess && CMessageBox::Show(m_hWnd, IDS_PROC_CONFIRMKILLPROCESS, IDS_APPNAME, MB_YESNO | MB_ICONQUESTION) != IDYES)
1638 return;
1639 if (::GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0))
1640 ::WaitForSingleObject(g_Git.m_CurrentGitPi.hProcess, 10000);
1642 CProgressDlg::KillProcessTree(g_Git.m_CurrentGitPi.dwProcessId);
1645 ::WaitForSingleObject(g_Git.m_CurrentGitPi.hProcess ,10000);
1646 if (m_pThread)
1648 if (::WaitForSingleObject(m_pThread->m_hThread, 5000) == WAIT_TIMEOUT)
1649 g_Git.KillRelatedThreads(m_pThread);
1651 m_tooltips.Pop();
1652 CResizableStandAloneDialog::OnCancel();
1655 void CSyncDlg::OnBnClickedButtonSubmodule()
1657 this->UpdateData();
1658 UpdateCombox();
1659 m_ctrlCmdOut.SetWindowText(L"");
1660 m_LogText.Empty();
1662 this->m_regSubmoduleButton = (DWORD)this->m_ctrlSubmodule.GetCurrentEntry();
1664 this->SwitchToRun();
1666 this->m_bAbort=false;
1667 this->m_GitCmdList.clear();
1669 ShowTab(IDC_CMD_LOG);
1671 CString cmd;
1673 switch (m_ctrlSubmodule.GetCurrentEntry())
1675 case 0:
1676 cmd = L"git.exe submodule update --init";
1677 break;
1678 case 1:
1679 cmd = L"git.exe submodule init";
1680 break;
1681 case 2:
1682 cmd = L"git.exe submodule sync";
1683 break;
1686 m_GitCmdList.push_back(cmd);
1688 m_CurrentCmd = GIT_COMMAND_SUBMODULE;
1690 m_pThread = AfxBeginThread(ProgressThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
1691 if (!m_pThread)
1693 // ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
1695 else
1697 m_pThread->m_bAutoDelete = TRUE;
1698 m_pThread->ResumeThread();
1702 void CSyncDlg::OnBnClickedButtonStash()
1704 UpdateData();
1705 UpdateCombox();
1706 m_ctrlCmdOut.SetWindowText(L"");
1707 m_LogText.Empty();
1709 SwitchToRun();
1711 m_bAbort = false;
1712 m_GitCmdList.clear();
1714 ShowTab(IDC_CMD_LOG);
1716 m_ctrlTabCtrl.ShowTab(IDC_IN_LOGLIST - 1, false);
1717 m_ctrlTabCtrl.ShowTab(IDC_IN_CHANGELIST -1, false);
1718 m_ctrlTabCtrl.ShowTab(IDC_IN_CONFLICT -1, false);
1720 CString cmd;
1721 switch (m_ctrlStash.GetCurrentEntry())
1723 case 0:
1724 cmd = L"git.exe stash push";
1725 if (!CAppUtils::IsGitVersionNewerOrEqual(2, 14))
1726 cmd = L"git.exe stash save";
1727 break;
1728 case 1:
1729 cmd = L"git.exe stash pop";
1730 break;
1731 case 2:
1732 cmd = L"git.exe stash apply";
1733 break;
1736 m_GitCmdList.push_back(cmd);
1737 m_CurrentCmd = GIT_COMMAND_STASH;
1739 m_pThread = AfxBeginThread(ProgressThreadEntry, this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
1740 if (!m_pThread)
1742 //ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
1744 else
1746 m_pThread->m_bAutoDelete = TRUE;
1747 m_pThread->ResumeThread();
1751 void CSyncDlg::OnTimer(UINT_PTR nIDEvent)
1753 if( nIDEvent == IDT_INPUT)
1755 KillTimer(IDT_INPUT);
1756 this->FetchOutList(true);
1757 m_ctrlTabCtrl.ShowTab(IDC_TAGCOMPARELIST - 1, false);
1761 LRESULT CSyncDlg::OnTaskbarBtnCreated(WPARAM wParam, LPARAM lParam)
1763 m_pTaskbarList.Release();
1764 m_pTaskbarList.CoCreateInstance(CLSID_TaskbarList);
1765 m_GitProgressList.m_pTaskbarList = m_pTaskbarList;
1766 return __super::OnTaskbarButtonCreated(wParam, lParam);
1769 void CSyncDlg::OnBnClickedCheckForce()
1771 UpdateData();
1774 void CSyncDlg::OnBnClickedLog()
1776 CString cmd = L"/command:log";
1777 cmd += L" /path:\"";
1778 cmd += g_Git.m_CurrentDir;
1779 cmd += L'"';
1781 CAppUtils::RunTortoiseGitProc(cmd);
1784 LRESULT CSyncDlg::OnProgCmdFinish(WPARAM /*wParam*/, LPARAM /*lParam*/)
1786 RefreshCursor();
1787 RunPostAction();
1788 return 0;
1791 void CSyncDlg::OnDestroy()
1793 m_bWantToExit = true;
1794 __super::OnDestroy();
1797 LRESULT CSyncDlg::OnThemeChanged()
1799 CMFCVisualManager::GetInstance()->DestroyInstance();
1800 return 0;
1803 void CSyncDlg::OnEnLinkLog(NMHDR *pNMHDR, LRESULT *pResult)
1805 // similar code in ProgressDlg.cpp and LogDlg.cpp
1806 ENLINK *pEnLink = reinterpret_cast<ENLINK *>(pNMHDR);
1807 if ((pEnLink->msg == WM_LBUTTONUP) || (pEnLink->msg == WM_SETCURSOR))
1809 CString msg;
1810 m_ctrlCmdOut.GetWindowText(msg);
1811 msg.Replace(L"\r\n", L"\n");
1812 CString url = msg.Mid(pEnLink->chrg.cpMin, pEnLink->chrg.cpMax - pEnLink->chrg.cpMin);
1813 // check if it's an email address
1814 auto atpos = url.Find(L'@');
1815 if ((atpos > 0) && (url.ReverseFind(L'.') > atpos) && !::PathIsURL(url))
1816 url = L"mailto:" + url;
1817 if (::PathIsURL(url))
1819 if (pEnLink->msg == WM_LBUTTONUP)
1820 ShellExecute(GetSafeHwnd(), L"open", url, nullptr, nullptr, SW_SHOWDEFAULT);
1821 else
1823 static RECT prevRect = { 0 };
1824 CWnd* pMsgView = &m_ctrlCmdOut;
1825 if (pMsgView)
1827 RECT rc;
1828 POINTL pt;
1829 pMsgView->SendMessage(EM_POSFROMCHAR, (WPARAM)&pt, pEnLink->chrg.cpMin);
1830 rc.left = pt.x;
1831 rc.top = pt.y;
1832 pMsgView->SendMessage(EM_POSFROMCHAR, (WPARAM)&pt, pEnLink->chrg.cpMax);
1833 rc.right = pt.x;
1834 rc.bottom = pt.y + 12;
1835 if ((prevRect.left != rc.left) || (prevRect.top != rc.top))
1837 m_tooltips.DelTool(pMsgView, 1);
1838 m_tooltips.AddTool(pMsgView, url, &rc, 1);
1839 prevRect = rc;
1845 *pResult = 0;
1848 void CSyncDlg::OnEnscrollLog()
1850 m_tooltips.DelTool(&m_ctrlCmdOut, 1);