1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2016 - TortoiseGit
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 // SyncDlg.cpp : implementation file
24 #include "TortoiseProc.h"
27 #include "ProgressDlg.h"
28 #include "MessageBox.h"
29 #include "ImportPatchDlg.h"
30 #include "RebaseDlg.h"
32 #include "SmartHandle.h"
33 #include "ProgressCommands/FetchProgressCommand.h"
37 IMPLEMENT_DYNAMIC(CSyncDlg
, CResizableStandAloneDialog
)
39 CSyncDlg::CSyncDlg(CWnd
* pParent
/*=nullptr*/)
40 : CResizableStandAloneDialog(CSyncDlg::IDD
, pParent
)
44 m_pTooltip
=&this->m_tooltips
;
47 m_bAutoLoadPuttyKey
= CAppUtils::IsSSHPutty();
54 m_bWantToExit
= false;
56 m_startTick
= GetTickCount64();
64 void CSyncDlg::DoDataExchange(CDataExchange
* pDX
)
66 CDialog::DoDataExchange(pDX
);
67 DDX_Check(pDX
, IDC_CHECK_PUTTY_KEY
, m_bAutoLoadPuttyKey
);
68 DDX_Check(pDX
, IDC_CHECK_FORCE
,m_bForce
);
69 DDX_Control(pDX
, IDC_COMBOBOXEX_URL
, m_ctrlURL
);
70 DDX_Control(pDX
, IDC_BUTTON_TABCTRL
, m_ctrlDumyButton
);
71 DDX_Control(pDX
, IDC_BUTTON_PULL
, m_ctrlPull
);
72 DDX_Control(pDX
, IDC_BUTTON_PUSH
, m_ctrlPush
);
73 DDX_Control(pDX
, IDC_STATIC_STATUS
, m_ctrlStatus
);
74 DDX_Control(pDX
, IDC_PROGRESS_SYNC
, m_ctrlProgress
);
75 DDX_Control(pDX
, IDC_ANIMATE_SYNC
, m_ctrlAnimate
);
76 DDX_Control(pDX
, IDC_BUTTON_SUBMODULE
,m_ctrlSubmodule
);
77 DDX_Control(pDX
, IDC_BUTTON_STASH
, m_ctrlStash
);
78 DDX_Control(pDX
, IDC_PROG_LABEL
, m_ctrlProgLabel
);
82 BEGIN_MESSAGE_MAP(CSyncDlg
, CResizableStandAloneDialog
)
83 ON_BN_CLICKED(IDC_BUTTON_PULL
, &CSyncDlg::OnBnClickedButtonPull
)
84 ON_BN_CLICKED(IDC_BUTTON_PUSH
, &CSyncDlg::OnBnClickedButtonPush
)
85 ON_BN_CLICKED(IDC_BUTTON_APPLY
, &CSyncDlg::OnBnClickedButtonApply
)
86 ON_BN_CLICKED(IDC_BUTTON_EMAIL
, &CSyncDlg::OnBnClickedButtonEmail
)
87 ON_BN_CLICKED(IDC_BUTTON_MANAGE
, &CSyncDlg::OnBnClickedButtonManage
)
89 ON_CBN_EDITCHANGE(IDC_COMBOBOXEX_URL
, &CSyncDlg::OnCbnEditchangeComboboxex
)
90 ON_CBN_EDITCHANGE(IDC_COMBOBOXEX_REMOTE_BRANCH
, &CSyncDlg::OnCbnEditchangeComboboxex
)
91 ON_MESSAGE(MSG_PROGRESSDLG_UPDATE_UI
, OnProgressUpdateUI
)
92 ON_MESSAGE(WM_PROG_CMD_FINISH
, OnProgCmdFinish
)
93 ON_NOTIFY(LVN_COLUMNCLICK
, IDC_IN_LOGLIST
, OnLvnInLogListColumnClick
)
94 ON_BN_CLICKED(IDC_BUTTON_COMMIT
, &CSyncDlg::OnBnClickedButtonCommit
)
95 ON_BN_CLICKED(IDC_BUTTON_SUBMODULE
, &CSyncDlg::OnBnClickedButtonSubmodule
)
96 ON_BN_CLICKED(IDC_BUTTON_STASH
, &CSyncDlg::OnBnClickedButtonStash
)
98 ON_REGISTERED_MESSAGE(TaskBarButtonCreated
, OnTaskbarBtnCreated
)
99 ON_BN_CLICKED(IDC_CHECK_FORCE
, &CSyncDlg::OnBnClickedCheckForce
)
100 ON_BN_CLICKED(IDC_LOG
, &CSyncDlg::OnBnClickedLog
)
104 void CSyncDlg::EnableControlButton(bool bEnabled
)
106 GetDlgItem(IDC_BUTTON_PULL
)->EnableWindow(bEnabled
);
107 GetDlgItem(IDC_BUTTON_PUSH
)->EnableWindow(bEnabled
);
108 GetDlgItem(IDC_BUTTON_APPLY
)->EnableWindow(bEnabled
);
109 GetDlgItem(IDC_BUTTON_EMAIL
)->EnableWindow(bEnabled
);
110 GetDlgItem(IDOK
)->EnableWindow(bEnabled
);
111 GetDlgItem(IDC_BUTTON_SUBMODULE
)->EnableWindow(bEnabled
);
112 GetDlgItem(IDC_BUTTON_STASH
)->EnableWindow(bEnabled
);
114 // CSyncDlg message handlers
116 bool CSyncDlg::AskSetTrackedBranch()
118 CString remote
, remoteBranch
;
119 g_Git
.GetRemoteTrackedBranch(m_strLocalBranch
, remote
, remoteBranch
);
120 if (remoteBranch
.IsEmpty())
122 remoteBranch
= m_strRemoteBranch
;
123 if (remoteBranch
.IsEmpty())
124 remoteBranch
= m_strLocalBranch
;
126 temp
.Format(IDS_NOTYET_SETTRACKEDBRANCH
, (LPCTSTR
)m_strLocalBranch
, (LPCTSTR
)remoteBranch
);
127 BOOL dontShowAgain
= FALSE
;
128 auto ret
= CMessageBox::ShowCheck(GetSafeHwnd(), temp
, L
"TortoiseGit", MB_ICONQUESTION
| MB_YESNOCANCEL
, nullptr, CString(MAKEINTRESOURCE(IDS_MSGBOX_DONOTSHOW
)), &dontShowAgain
);
130 CRegDWORD(L
"Software\\TortoiseGit\\AskSetTrackedBranch") = FALSE
;
136 key
.Format(L
"branch.%s.remote", (LPCTSTR
)m_strLocalBranch
);
137 g_Git
.SetConfigValue(key
, m_strURL
);
138 key
.Format(L
"branch.%s.merge", (LPCTSTR
)m_strLocalBranch
);
139 g_Git
.SetConfigValue(key
, L
"refs/heads/" + g_Git
.StripRefName(remoteBranch
));
145 void CSyncDlg::OnBnClickedButtonPull()
148 CurrentEntry
= (int)this->m_ctrlPull
.GetCurrentEntry();
149 this->m_regPullButton
= CurrentEntry
;
151 this->m_bAbort
=false;
152 this->m_GitCmdList
.clear();
153 m_ctrlCmdOut
.SetWindowTextW(_T(""));
159 if (g_Git
.GetHash(m_oldHash
, _T("HEAD")))
161 MessageBox(g_Git
.GetGitLastErr(_T("Could not get HEAD hash.")), _T("TortoiseGit"), MB_ICONERROR
);
166 m_newHashMap
.clear();
167 m_oldHashMap
.clear();
169 if( CurrentEntry
== 0)
171 CGitHash localBranchHash
;
172 if (g_Git
.GetHash(localBranchHash
, m_strLocalBranch
))
174 MessageBox(g_Git
.GetGitLastErr(_T("Could not get hash of \"") + m_strLocalBranch
+ _T("\".")), _T("TortoiseGit"), MB_ICONERROR
);
177 if (localBranchHash
!= m_oldHash
)
179 CMessageBox::Show(GetSafeHwnd(), IDS_PROC_SYNC_PULLWRONGBRANCH
, IDS_APPNAME
, MB_OK
| MB_ICONERROR
);
184 if(this->m_strURL
.IsEmpty())
186 CMessageBox::Show(GetSafeHwnd(), IDS_PROC_GITCONFIG_URLEMPTY
, IDS_APPNAME
, MB_OK
| MB_ICONERROR
);
190 if (!IsURL() && !m_strRemoteBranch
.IsEmpty() && CurrentEntry
== 0 && CRegDWORD(L
"Software\\TortoiseGit\\AskSetTrackedBranch", TRUE
) == TRUE
)
192 if (!AskSetTrackedBranch())
196 if (m_bAutoLoadPuttyKey
&& CurrentEntry
!= 4) // CurrentEntry (Remote Update) handles this on its own)
198 CAppUtils::LaunchPAgent(nullptr, &m_strURL
);
201 if (g_Git
.GetMapHashToFriendName(m_oldHashMap
))
202 MessageBox(g_Git
.GetGitLastErr(_T("Could not get all refs.")), _T("TortoiseGit"), MB_ICONERROR
);
206 force
= _T(" --force");
211 if (CurrentEntry
== 0 && CRegDWORD(L
"Software\\TortoiseGit\\PullRebaseBehaviorLike1816", FALSE
) == FALSE
) // check whether we need to override Pull if pull.rebase is set
213 CAutoRepository
repo(g_Git
.GetGitRepository());
215 MessageBox(CGit::GetLibGit2LastErr(_T("Could not open repository.")), _T("TortoiseGit"), MB_OK
| MB_ICONERROR
);
217 // Check config branch.<name>.rebase and pull.reabse
223 if (git_repository_head_detached(repo
) == 1)
226 CAutoConfig
config(true);
227 if (git_repository_config(config
.GetPointer(), repo
))
230 // branch.<name>.rebase overrides pull.rebase
231 if (config
.GetBOOL(_T("branch.") + g_Git
.GetCurrentBranch() + _T(".rebase"), m_iPullRebase
) == GIT_ENOTFOUND
)
233 if (config
.GetBOOL(_T("pull.rebase"), m_iPullRebase
) == GIT_ENOTFOUND
)
238 config
.GetString(_T("pull.rebase"), value
);
239 if (value
== _T("preserve"))
249 config
.GetString(_T("branch.") + g_Git
.GetCurrentBranch() + _T(".rebase"), value
);
250 if (value
== _T("preserve"))
257 if (m_iPullRebase
> 0)
260 if (m_strRemoteBranch
.IsEmpty())
262 CMessageBox::Show(GetSafeHwnd(), IDS_PROC_PULL_EMPTYBRANCH
, IDS_APPNAME
, MB_ICONEXCLAMATION
);
270 ShowTab(IDC_CMD_LOG
);
272 m_ctrlTabCtrl
.ShowTab(IDC_REFLIST
- 1, true);
273 m_ctrlTabCtrl
.ShowTab(IDC_IN_LOGLIST
- 1, false);
274 m_ctrlTabCtrl
.ShowTab(IDC_IN_CHANGELIST
- 1, false);
275 m_ctrlTabCtrl
.ShowTab(IDC_IN_CONFLICT
- 1, false);
278 if(CurrentEntry
== 0) //Pull
280 CString remotebranch
;
281 remotebranch
= m_strRemoteBranch
;
285 CString pullRemote
, pullBranch
;
286 g_Git
.GetRemoteTrackedBranch(m_strLocalBranch
, pullRemote
, pullBranch
);
287 if(pullBranch
== remotebranch
&& pullRemote
== this->m_strURL
)
288 remotebranch
.Empty();
291 cmd
.Format(_T("git.exe pull -v --progress%s \"%s\" %s"),
294 (LPCTSTR
)remotebranch
);
296 m_CurrentCmd
= GIT_COMMAND_PULL
;
297 m_GitCmdList
.push_back(cmd
);
299 m_pThread
= AfxBeginThread(ProgressThreadEntry
, this, THREAD_PRIORITY_NORMAL
,0,CREATE_SUSPENDED
);
302 // ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
306 m_pThread
->m_bAutoDelete
= TRUE
;
307 m_pThread
->ResumeThread();
313 if (CurrentEntry
== 1 || CurrentEntry
== 2 || CurrentEntry
== 3)
315 m_oldRemoteHash
.Empty();
316 CString remotebranch
;
317 if (CurrentEntry
== 3)
318 m_strRemoteBranch
.Empty();
319 else if (IsURL() || m_strRemoteBranch
.IsEmpty())
321 remotebranch
=this->m_strRemoteBranch
;
326 remotebranch
.Format(_T("remotes/%s/%s"), (LPCTSTR
)m_strURL
, (LPCTSTR
)m_strRemoteBranch
);
327 g_Git
.GetHash(m_oldRemoteHash
, remotebranch
);
328 if (m_oldRemoteHash
.IsEmpty())
329 remotebranch
=m_strRemoteBranch
;
331 remotebranch
=m_strRemoteBranch
+_T(":")+remotebranch
;
334 if (CurrentEntry
== 1 || CurrentEntry
== 3)
335 m_CurrentCmd
= GIT_COMMAND_FETCH
;
337 m_CurrentCmd
= GIT_COMMAND_FETCHANDREBASE
;
339 if (g_Git
.UsingLibGit2(CGit::GIT_CMD_FETCH
))
342 if (!remotebranch
.IsEmpty())
343 refspec
.Format(_T("refs/heads/%s:refs/remotes/%s/%s"), (LPCTSTR
)m_strRemoteBranch
, (LPCTSTR
)m_strURL
, (LPCTSTR
)m_strRemoteBranch
);
345 progressCommand
= std::make_unique
<FetchProgressCommand
>();
346 FetchProgressCommand
* fetchProgressCommand
= static_cast<FetchProgressCommand
*>(progressCommand
.get());
347 fetchProgressCommand
->SetUrl(m_strURL
);
348 fetchProgressCommand
->SetRefSpec(refspec
);
349 m_GitProgressList
.SetCommand(progressCommand
.get());
350 m_GitProgressList
.Init();
351 ShowTab(IDC_CMD_GIT_PROG
);
355 cmd
.Format(_T("git.exe fetch --progress -v%s \"%s\" %s"),
358 (LPCTSTR
)remotebranch
);
360 m_GitCmdList
.push_back(cmd
);
362 m_pThread
= AfxBeginThread(ProgressThreadEntry
, this, THREAD_PRIORITY_NORMAL
,0,CREATE_SUSPENDED
);
365 // ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
369 m_pThread
->m_bAutoDelete
= TRUE
;
370 m_pThread
->ResumeThread();
376 if (CurrentEntry
== 4)
378 if (m_bAutoLoadPuttyKey
)
381 if (!g_Git
.GetRemoteList(list
))
383 for (size_t i
= 0; i
< list
.size(); ++i
)
384 CAppUtils::LaunchPAgent(nullptr, &list
[i
]);
388 m_CurrentCmd
= GIT_COMMAND_REMOTE
;
389 cmd
=_T("git.exe remote update");
390 m_GitCmdList
.push_back(cmd
);
392 InterlockedExchange(&m_bBlock
, TRUE
);
394 m_pThread
= AfxBeginThread(ProgressThreadEntry
, this, THREAD_PRIORITY_NORMAL
,0,CREATE_SUSPENDED
);
397 // ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
398 InterlockedExchange(&m_bBlock
, FALSE
);
402 m_pThread
->m_bAutoDelete
= TRUE
;
403 m_pThread
->ResumeThread();
407 ///Cleanup stale remote banches
408 if (CurrentEntry
== 5)
410 m_CurrentCmd
= GIT_COMMAND_REMOTE
;
411 cmd
.Format(_T("git.exe remote prune \"%s\""), (LPCTSTR
)m_strURL
);
412 m_GitCmdList
.push_back(cmd
);
414 InterlockedExchange(&m_bBlock
, TRUE
);
416 m_pThread
= AfxBeginThread(ProgressThreadEntry
, this, THREAD_PRIORITY_NORMAL
,0,CREATE_SUSPENDED
);
419 // ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
420 InterlockedExchange(&m_bBlock
, FALSE
);
424 m_pThread
->m_bAutoDelete
= TRUE
;
425 m_pThread
->ResumeThread();
430 void CSyncDlg::ShowInCommits(const CString
& friendname
)
434 if (g_Git
.GetHash(newHash
, friendname
))
436 MessageBox(g_Git
.GetGitLastErr(L
"Could not get " + friendname
+ L
" hash."), L
"TortoiseGit", MB_ICONERROR
);
440 if (newHash
== m_oldHash
)
442 m_ctrlTabCtrl
.ShowTab(IDC_IN_CHANGELIST
- 1, false);
443 m_InLogList
.ShowText(CString(MAKEINTRESOURCE(IDS_UPTODATE
)));
444 m_ctrlTabCtrl
.ShowTab(IDC_IN_LOGLIST
- 1, true);
445 ShowTab(IDC_REFLIST
);
449 m_ctrlTabCtrl
.ShowTab(IDC_IN_CHANGELIST
- 1, true);
450 m_ctrlTabCtrl
.ShowTab(IDC_IN_LOGLIST
- 1, true);
452 AddDiffFileList(&m_InChangeFileList
, &m_arInChangeList
, newHash
.ToString(), m_oldHash
.ToString());
455 range
.Format(L
"%s..%s", (LPCTSTR
)m_oldHash
.ToString(), (LPCTSTR
)newHash
.ToString());
456 m_InLogList
.FillGitLog(nullptr, &range
, CGit::LOG_INFO_STAT
| CGit::LOG_INFO_FILESTATE
| CGit::LOG_INFO_SHOW_MERGEDFILE
);
457 ShowTab(IDC_IN_LOGLIST
);
461 void CSyncDlg::PullComplete()
463 EnableControlButton(true);
465 this->FetchOutList(true);
467 if( this ->m_GitCmdStatus
)
469 int hasConflicts
= g_Git
.HasWorkingTreeConflicts();
470 if (hasConflicts
< 0)
472 this->m_ctrlCmdOut
.SetSel(-1,-1);
473 this->m_ctrlCmdOut
.ReplaceSel(g_Git
.GetGitLastErr(L
"Checking for conflicts failed.", CGit::GIT_CMD_CHECKCONFLICTS
));
475 this->ShowTab(IDC_CMD_LOG
);
481 this->m_ConflictFileList
.Clear();
486 this->m_ConflictFileList
.GetStatus(&list
,true);
487 this->m_ConflictFileList
.Show(CTGitPath::LOGACTIONS_UNMERGED
,
488 CTGitPath::LOGACTIONS_UNMERGED
);
490 this->ShowTab(IDC_IN_CONFLICT
);
493 this->ShowTab(IDC_CMD_LOG
);
497 ShowInCommits(L
"HEAD");
500 void CSyncDlg::FetchComplete()
502 EnableControlButton(true);
505 if (g_Git
.UsingLibGit2(CGit::GIT_CMD_FETCH
))
506 ShowTab(IDC_CMD_GIT_PROG
);
508 ShowTab(IDC_REFLIST
);
510 if (m_GitCmdStatus
|| (m_CurrentCmd
!= GIT_COMMAND_FETCHANDREBASE
&& m_iPullRebase
== 0))
517 CString remotebranch
;
518 CString upstream
= _T("FETCH_HEAD");
519 m_ctrlURL
.GetWindowText(remote
);
520 if (!remote
.IsEmpty())
522 STRING_VECTOR remotes
;
523 g_Git
.GetRemoteList(remotes
);
524 if (std::find(remotes
.cbegin(), remotes
.cend(), remote
) == remotes
.cend())
527 m_ctrlRemoteBranch
.GetWindowText(remotebranch
);
528 if (!remote
.IsEmpty() && !remotebranch
.IsEmpty())
529 upstream
= _T("remotes/") + remote
+ _T("/") + remotebranch
;
531 if (m_iPullRebase
> 0)
533 CAppUtils::RebaseAfterFetch(upstream
, m_iPullRebase
? 2 : 0, m_iPullRebase
== 2);
537 ShowInCommits(L
"HEAD");
542 CGitHash remoteBranchHash
;
543 g_Git
.GetHash(remoteBranchHash
, upstream
);
544 if (remoteBranchHash
== m_oldRemoteHash
&& !m_oldRemoteHash
.IsEmpty() && CMessageBox::ShowCheck(this->GetSafeHwnd(), IDS_REBASE_BRANCH_UNCHANGED
, IDS_APPNAME
, MB_ICONQUESTION
| MB_YESNO
| MB_DEFBUTTON2
, _T("OpenRebaseRemoteBranchUnchanged"), IDS_MSGBOX_DONOTSHOWAGAIN
) == IDNO
)
546 ShowInCommits(upstream
);
550 if (g_Git
.IsFastForward(_T("HEAD"), upstream
))
552 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
);
557 CProgressDlg mergeProgress
;
558 mergeProgress
.m_GitCmd
= _T("git.exe merge --ff-only ") + upstream
;
559 mergeProgress
.m_AutoClose
= AUTOCLOSE_IF_NO_ERRORS
;
560 mergeProgress
.m_PostCmdCallback
= [](DWORD status
, PostCmdList
& postCmdList
)
562 if (status
&& g_Git
.HasWorkingTreeConflicts())
564 // there are conflict files
565 postCmdList
.emplace_back(IDI_RESOLVE
, IDS_PROGRS_CMD_RESOLVE
, []
568 sCmd
.Format(_T("/command:commit /path:\"%s\""), g_Git
.m_CurrentDir
);
569 CAppUtils::RunTortoiseGitProc(sCmd
);
573 mergeProgress
.DoModal();
577 ShowInCommits(L
"HEAD");
583 CAppUtils::RebaseAfterFetch(upstream
);
587 ShowInCommits(L
"HEAD");
590 void CSyncDlg::StashComplete()
592 EnableControlButton(true);
593 INT_PTR entry
= m_ctrlStash
.GetCurrentEntry();
594 if (entry
!= 1 && entry
!= 2)
600 int hasConflicts
= g_Git
.HasWorkingTreeConflicts();
601 if (hasConflicts
< 0)
603 m_ctrlCmdOut
.SetSel(-1, -1);
604 m_ctrlCmdOut
.ReplaceSel(g_Git
.GetGitLastErr(L
"Checking for conflicts failed.", CGit::GIT_CMD_CHECKCONFLICTS
));
606 ShowTab(IDC_CMD_LOG
);
612 m_ConflictFileList
.Clear();
617 m_ConflictFileList
.GetStatus(&list
,true);
618 m_ConflictFileList
.Show(CTGitPath::LOGACTIONS_UNMERGED
, CTGitPath::LOGACTIONS_UNMERGED
);
620 ShowTab(IDC_IN_CONFLICT
);
623 ShowTab(IDC_CMD_LOG
);
627 void CSyncDlg::OnBnClickedButtonPush()
631 m_ctrlCmdOut
.SetWindowTextW(_T(""));
634 if(this->m_strURL
.IsEmpty())
636 CMessageBox::Show(GetSafeHwnd(), IDS_PROC_GITCONFIG_URLEMPTY
, IDS_APPNAME
, MB_OK
| MB_ICONERROR
);
640 if (!IsURL() && m_ctrlPush
.GetCurrentEntry() == 0 && CRegDWORD(L
"Software\\TortoiseGit\\AskSetTrackedBranch", TRUE
) == TRUE
)
642 if (!AskSetTrackedBranch())
646 this->m_regPushButton
=(DWORD
)this->m_ctrlPush
.GetCurrentEntry();
648 this->m_bAbort
=false;
649 this->m_GitCmdList
.clear();
651 ShowTab(IDC_CMD_LOG
);
657 DWORD exitcode
= 0xFFFFFFFF;
658 if (CHooks::Instance().PrePush(g_Git
.m_CurrentDir
, exitcode
, error
))
663 temp
.Format(IDS_ERR_HOOKFAILED
, (LPCTSTR
)error
);
664 CMessageBox::Show(GetSafeHwnd(), temp
, _T("TortoiseGit"), MB_OK
| MB_ICONERROR
);
669 CString refName
= g_Git
.FixBranchName(m_strLocalBranch
);
670 switch (m_ctrlPush
.GetCurrentEntry())
673 arg
+= _T(" --tags");
676 refName
= _T("refs/notes/commits"); //default ref for notes
681 arg
+= _T(" --force");
683 cmd
.Format(_T("git.exe push -v --progress%s \"%s\" %s"),
688 if (!m_strRemoteBranch
.IsEmpty() && m_ctrlPush
.GetCurrentEntry() != 2)
690 cmd
+= _T(":") + m_strRemoteBranch
;
693 m_GitCmdList
.push_back(cmd
);
695 m_CurrentCmd
= GIT_COMMAND_PUSH
;
697 if(this->m_bAutoLoadPuttyKey
)
699 CAppUtils::LaunchPAgent(nullptr, &m_strURL
);
702 m_pThread
= AfxBeginThread(ProgressThreadEntry
, this, THREAD_PRIORITY_NORMAL
,0,CREATE_SUSPENDED
);
705 // ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
709 m_pThread
->m_bAutoDelete
= TRUE
;
710 m_pThread
->ResumeThread();
714 void CSyncDlg::OnBnClickedButtonApply()
717 if (g_Git
.GetHash(oldhash
, _T("HEAD")))
719 MessageBox(g_Git
.GetGitLastErr(_T("Could not get HEAD hash.")), _T("TortoiseGit"), MB_ICONERROR
);
726 if(dlg
.DoModal() == IDOK
)
729 for (int i
= 0; i
< dlg
.m_PathList
.GetCount(); ++i
)
731 cmd
.Format(_T("git.exe am \"%s\""), (LPCTSTR
)dlg
.m_PathList
[i
].GetGitPathString());
733 if (g_Git
.Run(cmd
, &output
, CP_UTF8
))
735 CMessageBox::Show(GetSafeHwnd(), output
, _T("TortoiseGit"), MB_OK
| MB_ICONERROR
);
740 this->m_ctrlCmdOut
.SetSel(-1,-1);
741 this->m_ctrlCmdOut
.ReplaceSel(cmd
+_T("\n"));
742 this->m_ctrlCmdOut
.SetSel(-1,-1);
743 this->m_ctrlCmdOut
.ReplaceSel(output
);
747 if (g_Git
.GetHash(newhash
, _T("HEAD")))
749 MessageBox(g_Git
.GetGitLastErr(_T("Could not get HEAD hash after applying patches.")), _T("TortoiseGit"), MB_ICONERROR
);
753 this->m_InLogList
.Clear();
754 this->m_InChangeFileList
.Clear();
756 if(newhash
== oldhash
)
758 this->m_ctrlTabCtrl
.ShowTab(IDC_IN_CHANGELIST
-1,false);
759 this->m_InLogList
.ShowText(_T("No commits get from patch"));
760 this->m_ctrlTabCtrl
.ShowTab(IDC_IN_LOGLIST
-1,true);
765 this->m_ctrlTabCtrl
.ShowTab(IDC_IN_CHANGELIST
-1,true);
766 this->m_ctrlTabCtrl
.ShowTab(IDC_IN_LOGLIST
-1,true);
769 range
.Format(_T("%s..%s"), (LPCTSTR
)m_oldHash
.ToString(), (LPCTSTR
)newhash
.ToString());
770 this->AddDiffFileList(&m_InChangeFileList
, &m_arInChangeList
, newhash
.ToString(), oldhash
.ToString());
771 m_InLogList
.FillGitLog(nullptr, &range
, CGit::LOG_INFO_STAT
| CGit::LOG_INFO_FILESTATE
| CGit::LOG_INFO_SHOW_MERGEDFILE
);
773 this->FetchOutList(true);
776 this->m_ctrlTabCtrl
.ShowTab(IDC_CMD_LOG
-1,true);
780 this->ShowTab(IDC_CMD_LOG
);
784 this->ShowTab(IDC_IN_LOGLIST
);
789 void CSyncDlg::OnBnClickedButtonEmail()
791 CString cmd
, out
, err
;
793 this->m_strLocalBranch
= this->m_ctrlLocalBranch
.GetString();
794 this->m_ctrlRemoteBranch
.GetWindowText(this->m_strRemoteBranch
);
795 this->m_ctrlURL
.GetWindowText(this->m_strURL
);
796 m_strURL
=m_strURL
.Trim();
797 m_strRemoteBranch
=m_strRemoteBranch
.Trim();
799 cmd
.Format(_T("git.exe format-patch -o \"%s\" %s..%s"),
800 (LPCTSTR
)g_Git
.m_CurrentDir
,
801 (LPCTSTR
)(m_strURL
+ _T('/') + m_strRemoteBranch
), (LPCTSTR
)g_Git
.FixBranchName(m_strLocalBranch
));
803 if (g_Git
.Run(cmd
, &out
, &err
, CP_UTF8
))
805 CMessageBox::Show(GetSafeHwnd(), out
+ L
"\n" + err
, _T("TortoiseGit"), MB_OK
| MB_ICONERROR
);
809 CAppUtils::SendPatchMail(cmd
,out
);
811 void CSyncDlg::ShowProgressCtrl(bool bShow
)
813 int b
=bShow
?SW_NORMAL
:SW_HIDE
;
814 this->m_ctrlAnimate
.ShowWindow(b
);
815 this->m_ctrlProgress
.ShowWindow(b
);
816 this->m_ctrlProgLabel
.ShowWindow(b
);
817 this->m_ctrlAnimate
.Open(IDR_DOWNLOAD
);
819 this->m_ctrlAnimate
.Play(0, UINT_MAX
, UINT_MAX
);
821 this->m_ctrlAnimate
.Stop();
823 void CSyncDlg::ShowInputCtrl(bool bShow
)
825 int b
=bShow
?SW_NORMAL
:SW_HIDE
;
826 this->m_ctrlURL
.ShowWindow(b
);
827 this->m_ctrlLocalBranch
.ShowWindow(b
);
828 this->m_ctrlRemoteBranch
.ShowWindow(b
);
829 this->GetDlgItem(IDC_BUTTON_LOCAL_BRANCH
)->ShowWindow(b
);
830 this->GetDlgItem(IDC_BUTTON_REMOTE_BRANCH
)->ShowWindow(b
);
831 this->GetDlgItem(IDC_STATIC_LOCAL_BRANCH
)->ShowWindow(b
);
832 this->GetDlgItem(IDC_STATIC_REMOTE_BRANCH
)->ShowWindow(b
);
833 this->GetDlgItem(IDC_BUTTON_MANAGE
)->ShowWindow(b
);
834 this->GetDlgItem(IDC_CHECK_PUTTY_KEY
)->ShowWindow(b
);
835 this->GetDlgItem(IDC_CHECK_FORCE
)->ShowWindow(b
);
836 this->GetDlgItem(IDC_STATIC_REMOTE_URL
)->ShowWindow(b
);
838 BOOL
CSyncDlg::OnInitDialog()
840 CResizableStandAloneDialog::OnInitDialog();
841 CAppUtils::MarkWindowAsUnpinnable(m_hWnd
);
843 // Let the TaskbarButtonCreated message through the UIPI filter. If we don't
844 // do this, Explorer would be unable to send that message to our window if we
845 // were running elevated. It's OK to make the call all the time, since if we're
846 // not elevated, this is a no-op.
847 CHANGEFILTERSTRUCT cfs
= { sizeof(CHANGEFILTERSTRUCT
) };
848 typedef BOOL STDAPICALLTYPE
ChangeWindowMessageFilterExDFN(HWND hWnd
, UINT message
, DWORD action
, PCHANGEFILTERSTRUCT pChangeFilterStruct
);
849 CAutoLibrary hUser
= AtlLoadSystemLibraryUsingFullPath(_T("user32.dll"));
852 ChangeWindowMessageFilterExDFN
*pfnChangeWindowMessageFilterEx
= (ChangeWindowMessageFilterExDFN
*)GetProcAddress(hUser
, "ChangeWindowMessageFilterEx");
853 if (pfnChangeWindowMessageFilterEx
)
855 pfnChangeWindowMessageFilterEx(m_hWnd
, TaskBarButtonCreated
, MSGFLT_ALLOW
, &cfs
);
858 m_pTaskbarList
.Release();
859 if (FAILED(m_pTaskbarList
.CoCreateInstance(CLSID_TaskbarList
)))
860 m_pTaskbarList
= nullptr;
862 this->GetDlgItem(IDC_CHECK_PUTTY_KEY
)->EnableWindow(CAppUtils::IsSSHPutty());
865 this->m_ctrlAnimate.ShowWindow(SW_NORMAL);
866 this->m_ctrlAnimate.Open(IDR_DOWNLOAD);
867 this->m_ctrlAnimate.Play(0,-1,-1);
870 // ------------------ Create Tabctrl -----------
871 CWnd
*pwnd
=this->GetDlgItem(IDC_BUTTON_TABCTRL
);
873 pwnd
->GetWindowRect(&rectDummy
);
874 this->ScreenToClient(rectDummy
);
876 if (!m_ctrlTabCtrl
.Create(CMFCTabCtrl::STYLE_FLAT
, rectDummy
, this, IDC_SYNC_TAB
))
878 TRACE0("Failed to create output tab window\n");
879 return FALSE
; // fail to create
881 m_ctrlTabCtrl
.SetResizeMode(CMFCTabCtrl::RESIZE_NO
);
883 // -------------Create Command Log Ctrl ---------
885 dwStyle
= ES_MULTILINE
| ES_READONLY
| WS_CHILD
| WS_VISIBLE
| ES_AUTOHSCROLL
| ES_AUTOVSCROLL
|WS_VSCROLL
;
887 if( !m_ctrlCmdOut
.Create(dwStyle
,rectDummy
,&m_ctrlTabCtrl
,IDC_CMD_LOG
))
889 TRACE0("Failed to create Log commits window\n");
890 return FALSE
; // fail to create
893 // set the font to use in the log message view, configured in the settings dialog
895 CAppUtils::CreateFontForLogs(m_logFont
);
896 //GetDlgItem(IDC_CMD_LOG)->SetFont(&m_logFont);
897 m_ctrlCmdOut
.SetFont(&m_logFont
);
898 m_ctrlTabCtrl
.InsertTab(&m_ctrlCmdOut
, CString(MAKEINTRESOURCE(IDS_LOG
)), -1);
900 //m_ctrlCmdOut.ReplaceSel(_T("Hello"));
902 //---------- Create in coming list ctrl -----------
903 dwStyle
=LVS_REPORT
| LVS_SHOWSELALWAYS
| LVS_ALIGNLEFT
| LVS_OWNERDATA
| WS_BORDER
| WS_TABSTOP
| WS_CHILD
| WS_VISIBLE
;;
905 if( !m_InLogList
.Create(dwStyle
,rectDummy
,&m_ctrlTabCtrl
,IDC_IN_LOGLIST
))
907 TRACE0("Failed to create output commits window\n");
908 return FALSE
; // fail to create
911 m_ctrlTabCtrl
.InsertTab(&m_InLogList
, CString(MAKEINTRESOURCE(IDS_PROC_SYNC_INCOMMITS
)), -1);
913 m_InLogList
.m_ColumnRegKey
=_T("SyncIn");
914 m_InLogList
.InsertGitColumn();
916 //----------- Create In Change file list -----------
917 dwStyle
= LVS_REPORT
| LVS_SHOWSELALWAYS
| LVS_ALIGNLEFT
| WS_BORDER
| WS_TABSTOP
|LVS_SINGLESEL
|WS_CHILD
| WS_VISIBLE
;
919 if( !m_InChangeFileList
.Create(dwStyle
,rectDummy
,&m_ctrlTabCtrl
,IDC_IN_CHANGELIST
))
921 TRACE0("Failed to create output change files window\n");
922 return FALSE
; // fail to create
924 m_ctrlTabCtrl
.InsertTab(&m_InChangeFileList
, CString(MAKEINTRESOURCE(IDS_PROC_SYNC_INCHANGELIST
)), -1);
926 m_InChangeFileList
.Init(GITSLC_COLEXT
| GITSLC_COLSTATUS
|GITSLC_COLADD
|GITSLC_COLDEL
, _T("InSyncDlg"),
927 (CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_COMPARETWOREVISIONS
) |
928 CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_GNUDIFF2REVISIONS
)), false, true, GITSLC_COLEXT
| GITSLC_COLSTATUS
| GITSLC_COLADD
| GITSLC_COLDEL
);
931 //---------- Create Conflict List Ctrl -----------------
932 dwStyle
= LVS_REPORT
| LVS_SHOWSELALWAYS
| LVS_ALIGNLEFT
| WS_BORDER
| WS_TABSTOP
| WS_CHILD
| WS_VISIBLE
;
934 if( !m_ConflictFileList
.Create(dwStyle
,rectDummy
,&m_ctrlTabCtrl
,IDC_IN_CONFLICT
))
936 TRACE0("Failed to create output change files window\n");
937 return FALSE
; // fail to create
939 m_ctrlTabCtrl
.InsertTab(&m_ConflictFileList
, CString(MAKEINTRESOURCE(IDS_PROC_SYNC_CONFLICTS
)), -1);
941 m_ConflictFileList
.Init(GITSLC_COLEXT
| GITSLC_COLSTATUS
|GITSLC_COLADD
|GITSLC_COLDEL
, _T("ConflictSyncDlg"),
942 (CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_COMPARETWOREVISIONS
) |
943 CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_GNUDIFF2REVISIONS
) |
944 GITSLC_POPCONFLICT
|GITSLC_POPRESOLVE
),false);
947 //---------- Create Commit Out List Ctrl---------------
949 dwStyle
=LVS_REPORT
| LVS_SHOWSELALWAYS
| LVS_ALIGNLEFT
| LVS_OWNERDATA
| WS_BORDER
| WS_TABSTOP
| WS_CHILD
| WS_VISIBLE
;;
951 if( !m_OutLogList
.Create(dwStyle
,rectDummy
,&m_ctrlTabCtrl
,IDC_OUT_LOGLIST
))
953 TRACE0("Failed to create output commits window\n");
954 return FALSE
; // fail to create
958 m_ctrlTabCtrl
.InsertTab(&m_OutLogList
, CString(MAKEINTRESOURCE(IDS_PROC_SYNC_OUTCOMMITS
)), -1);
960 m_OutLogList
.m_ColumnRegKey
= _T("SyncOut");
961 m_OutLogList
.InsertGitColumn();
963 //------------- Create Change File List Control ----------------
965 dwStyle
= LVS_REPORT
| LVS_SHOWSELALWAYS
| LVS_ALIGNLEFT
| WS_BORDER
| WS_TABSTOP
|LVS_SINGLESEL
|WS_CHILD
| WS_VISIBLE
;
967 if( !m_OutChangeFileList
.Create(dwStyle
,rectDummy
,&m_ctrlTabCtrl
,IDC_OUT_CHANGELIST
))
969 TRACE0("Failed to create output change files window\n");
970 return FALSE
; // fail to create
972 m_ctrlTabCtrl
.InsertTab(&m_OutChangeFileList
, CString(MAKEINTRESOURCE(IDS_PROC_SYNC_OUTCHANGELIST
)), -1);
974 m_OutChangeFileList
.Init(GITSLC_COLEXT
| GITSLC_COLSTATUS
| GITSLC_COLADD
| GITSLC_COLDEL
, _T("OutSyncDlg"),
975 (CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_COMPARETWOREVISIONS
) |
976 CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_GNUDIFF2REVISIONS
)), false, true, GITSLC_COLEXT
| GITSLC_COLSTATUS
| GITSLC_COLADD
| GITSLC_COLDEL
);
978 if (!m_GitProgressList
.Create(dwStyle
| LVS_OWNERDATA
, rectDummy
, &m_ctrlTabCtrl
, IDC_CMD_GIT_PROG
))
980 TRACE0("Failed to create Git Progress List Window\n");
981 return FALSE
; // fail to create
983 m_ctrlTabCtrl
.InsertTab(&m_GitProgressList
, CString(MAKEINTRESOURCE(IDS_LOG
)), -1);
984 m_GitProgressList
.m_pAnimate
= &m_ctrlAnimate
;
985 m_GitProgressList
.m_pPostWnd
= this;
986 m_GitProgressList
.m_pProgressLabelCtrl
= &m_ctrlProgLabel
;
987 m_GitProgressList
.m_pProgControl
= &m_ctrlProgress
;
988 m_GitProgressList
.m_pTaskbarList
= m_pTaskbarList
;
990 dwStyle
= LVS_REPORT
| LVS_SHOWSELALWAYS
| LVS_ALIGNLEFT
| WS_BORDER
| WS_TABSTOP
| WS_CHILD
| WS_VISIBLE
;
991 DWORD exStyle
= LVS_EX_HEADERDRAGDROP
| LVS_EX_DOUBLEBUFFER
| LVS_EX_INFOTIP
;
992 if (CRegDWORD(L
"Software\\TortoiseGit\\FullRowSelect", TRUE
))
993 exStyle
|= LVS_EX_FULLROWSELECT
;
994 if (g_Git
.m_IsUseLibGit2
)
996 m_refList
.Create(dwStyle
, rectDummy
, &m_ctrlTabCtrl
, IDC_REFLIST
);
997 m_refList
.SetExtendedStyle(exStyle
);
999 m_ctrlTabCtrl
.InsertTab(&m_refList
, CString(MAKEINTRESOURCE(IDS_REFLIST
)), -1);
1002 AddAnchor(IDC_SYNC_TAB
,TOP_LEFT
,BOTTOM_RIGHT
);
1004 AddAnchor(IDC_GROUP_INFO
,TOP_LEFT
,TOP_RIGHT
);
1005 AddAnchor(IDC_COMBOBOXEX_URL
,TOP_LEFT
,TOP_RIGHT
);
1006 AddAnchor(IDC_BUTTON_MANAGE
,TOP_RIGHT
);
1007 AddAnchor(IDC_BUTTON_PULL
,BOTTOM_LEFT
);
1008 AddAnchor(IDC_BUTTON_PUSH
,BOTTOM_LEFT
);
1009 AddAnchor(IDC_BUTTON_SUBMODULE
,BOTTOM_LEFT
);
1010 AddAnchor(IDC_BUTTON_STASH
,BOTTOM_LEFT
);
1011 AddAnchor(IDC_BUTTON_APPLY
,BOTTOM_RIGHT
);
1012 AddAnchor(IDC_BUTTON_EMAIL
,BOTTOM_RIGHT
);
1013 AddAnchor(IDC_PROGRESS_SYNC
,TOP_LEFT
,TOP_RIGHT
);
1014 AddAnchor(IDOK
,BOTTOM_RIGHT
);
1015 AddAnchor(IDHELP
,BOTTOM_RIGHT
);
1016 AddAnchor(IDC_STATIC_STATUS
, BOTTOM_LEFT
, BOTTOM_RIGHT
);
1017 AddAnchor(IDC_ANIMATE_SYNC
,TOP_LEFT
);
1018 AddAnchor(IDC_BUTTON_COMMIT
,BOTTOM_LEFT
);
1019 AddAnchor(IDC_LOG
, BOTTOM_LEFT
);
1021 // do not use BRANCH_COMBOX_ADD_ANCHOR here, we want to have different stylings
1022 AddAnchor(IDC_COMBOBOXEX_LOCAL_BRANCH
, TOP_LEFT
,TOP_CENTER
);
1023 AddAnchor(IDC_COMBOBOXEX_REMOTE_BRANCH
, TOP_CENTER
, TOP_RIGHT
);
1024 AddAnchor(IDC_BUTTON_LOCAL_BRANCH
, TOP_CENTER
);
1025 AddAnchor(IDC_BUTTON_REMOTE_BRANCH
, TOP_RIGHT
);
1026 AddAnchor(IDC_STATIC_REMOTE_BRANCH
, TOP_CENTER
);
1027 AddAnchor(IDC_PROG_LABEL
, TOP_LEFT
);
1029 AdjustControlSize(IDC_CHECK_PUTTY_KEY
);
1030 AdjustControlSize(IDC_CHECK_FORCE
);
1032 CString WorkingDir
=g_Git
.m_CurrentDir
;
1033 WorkingDir
.Replace(_T(':'),_T('_'));
1034 m_RegKeyRemoteBranch
= CString(_T("Software\\TortoiseGit\\History\\SyncBranch\\"))+WorkingDir
;
1037 this->AddOthersToAnchor();
1039 this->m_ctrlPush
.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_PUSH
)));
1040 this->m_ctrlPush
.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_PUSHTAGS
)));
1041 this->m_ctrlPush
.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_PUSHNOTES
)));
1043 this->m_ctrlPull
.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_PULL
)));
1044 this->m_ctrlPull
.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_FETCH
)));
1045 this->m_ctrlPull
.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_FETCHREBASE
)));
1046 this->m_ctrlPull
.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_FETCHALL
)));
1047 this->m_ctrlPull
.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_REMOTEUPDATE
)));
1048 this->m_ctrlPull
.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_CLEANUPSTALEBRANCHES
)));
1050 this->m_ctrlSubmodule
.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_SUBKODULEUPDATE
)));
1051 this->m_ctrlSubmodule
.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_SUBKODULEINIT
)));
1052 this->m_ctrlSubmodule
.AddEntry(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_SUBKODULESYNC
)));
1054 this->m_ctrlStash
.AddEntry(CString(MAKEINTRESOURCE(IDS_MENUSTASHSAVE
)));
1055 this->m_ctrlStash
.AddEntry(CString(MAKEINTRESOURCE(IDS_MENUSTASHPOP
)));
1056 this->m_ctrlStash
.AddEntry(CString(MAKEINTRESOURCE(IDS_MENUSTASHAPPLY
)));
1058 WorkingDir
.Replace(_T(':'),_T('_'));
1061 regkey
.Format(_T("Software\\TortoiseGit\\TortoiseProc\\Sync\\%s"), (LPCTSTR
)WorkingDir
);
1063 this->m_regPullButton
= CRegDWORD(regkey
+_T("\\Pull"),0);
1064 this->m_regPushButton
= CRegDWORD(regkey
+_T("\\Push"),0);
1065 this->m_regSubmoduleButton
= CRegDWORD(regkey
+_T("\\Submodule"));
1066 this->m_regAutoLoadPutty
= CRegDWORD(regkey
+ _T("\\AutoLoadPutty"), CAppUtils::IsSSHPutty());
1069 this->m_bAutoLoadPuttyKey
= m_regAutoLoadPutty
;
1070 if(!CAppUtils::IsSSHPutty())
1071 m_bAutoLoadPuttyKey
= false;
1072 this->UpdateData(FALSE
);
1074 this->m_ctrlPull
.SetCurrentEntry(this->m_regPullButton
);
1075 this->m_ctrlPush
.SetCurrentEntry(this->m_regPushButton
);
1076 this->m_ctrlSubmodule
.SetCurrentEntry(this->m_regSubmoduleButton
);
1078 CString sWindowTitle
;
1079 GetWindowText(sWindowTitle
);
1080 CAppUtils::SetWindowTitle(m_hWnd
, g_Git
.m_CurrentDir
, sWindowTitle
);
1082 EnableSaveRestore(_T("SyncDlg"));
1084 m_ctrlURL
.SetCaseSensitive(TRUE
);
1085 m_ctrlURL
.SetURLHistory(true);
1086 m_ctrlURL
.SetMaxHistoryItems(0x7FFFFFFF);
1087 this->m_ctrlURL
.LoadHistory(CString(_T("Software\\TortoiseGit\\History\\SyncURL\\"))+WorkingDir
, _T("url"));
1091 if(!g_Git
.GetRemoteList(list
))
1093 for (unsigned int i
= 0; i
< list
.size(); ++i
)
1095 m_ctrlURL
.AddString(list
[i
]);
1098 m_ctrlURL
.SetCurSel(0);
1099 m_ctrlRemoteBranch
.SetCurSel(0);
1101 this->LoadBranchInfo();
1103 this->m_bInited
=true;
1106 m_ctrlTabCtrl
.ShowTab(IDC_CMD_LOG
-1,false);
1107 m_ctrlTabCtrl
.ShowTab(IDC_IN_LOGLIST
-1,false);
1108 m_ctrlTabCtrl
.ShowTab(IDC_IN_CHANGELIST
-1,false);
1109 m_ctrlTabCtrl
.ShowTab(IDC_IN_CONFLICT
-1,false);
1110 m_ctrlTabCtrl
.ShowTab(IDC_CMD_GIT_PROG
-1, false);
1111 m_ctrlTabCtrl
.ShowTab(IDC_REFLIST
-1, false);
1113 m_ctrlRemoteBranch
.m_bWantReturn
= TRUE
;
1114 m_ctrlURL
.m_bWantReturn
= TRUE
;
1116 if (m_seq
> 0 && (DWORD
)CRegDWORD(_T("Software\\TortoiseGit\\SyncDialogRandomPos")))
1120 GetWindowRect(&rect
);
1121 rect
.top
-= m_seq
* 30;
1122 rect
.bottom
-= m_seq
* 30;
1128 MoveWindow(rect
.left
, rect
.top
, rect
.right
- rect
.left
, rect
.bottom
- rect
.top
);
1131 return TRUE
; // return TRUE unless you set the focus to a control
1132 // EXCEPTION: OCX Property Pages should return FALSE
1135 void CSyncDlg::OnBnClickedButtonManage()
1137 CAppUtils::LaunchRemoteSetting();
1141 void CSyncDlg::Refresh()
1143 theApp
.DoWaitCursor(1);
1145 int lastSelected
= m_ctrlURL
.GetCurSel();
1147 this->m_ctrlURL
.GetWindowText(url
);
1149 this->m_ctrlURL
.Reset();
1150 CString workingDir
= g_Git
.m_CurrentDir
;
1151 workingDir
.Replace(_T(':'), _T('_'));
1152 this->m_ctrlURL
.LoadHistory(_T("Software\\TortoiseGit\\History\\SyncURL\\") + workingDir
, _T("url"));
1156 if (!g_Git
.GetRemoteList(list
))
1158 for (size_t i
= 0; i
< list
.size(); ++i
)
1160 m_ctrlURL
.AddString(list
[i
]);
1165 if (lastSelected
>= 0 && !found
)
1167 m_ctrlURL
.SetCurSel(0);
1168 m_ctrlURL
.GetWindowText(url
);
1173 this->m_ctrlLocalBranch
.GetWindowText(local
);
1174 this->m_ctrlRemoteBranch
.GetWindowText(remote
);
1176 this->LoadBranchInfo();
1178 this->m_ctrlLocalBranch
.AddString(local
);
1179 this->m_ctrlRemoteBranch
.AddString(remote
);
1180 this->m_ctrlURL
.AddString(url
);
1182 m_OutLogList
.ShowText(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_REFRESHING
)));
1183 this->FetchOutList(true);
1184 theApp
.DoWaitCursor(-1);
1187 BOOL
CSyncDlg::PreTranslateMessage(MSG
* pMsg
)
1189 if (pMsg
->message
== WM_KEYDOWN
)
1191 switch (pMsg
->wParam
)
1196 return CResizableStandAloneDialog::PreTranslateMessage(pMsg
);
1201 /* Avoid TAB control destroy but dialog exist*/
1205 TCHAR buff
[128] = { 0 };
1206 ::GetClassName(pMsg
->hwnd
,buff
,128);
1208 /* Use MSFTEDIT_CLASS http://msdn.microsoft.com/en-us/library/bb531344.aspx */
1209 if (_tcsnicmp(buff
, MSFTEDIT_CLASS
, 128) == 0 || //Unicode and MFC 2012 and later
1210 _tcsnicmp(buff
, RICHEDIT_CLASS
, 128) == 0 || //ANSI or MFC 2010
1211 _tcsnicmp(buff
, _T("SysListView32"), 128) == 0)
1213 this->PostMessage(WM_KEYDOWN
,VK_ESCAPE
,0);
1219 return __super::PreTranslateMessage(pMsg
);
1221 void CSyncDlg::FetchOutList(bool force
)
1225 m_OutChangeFileList
.Clear();
1226 this->m_OutLogList
.Clear();
1229 this->m_ctrlURL
.GetWindowText(remote
);
1230 CString remotebranch
;
1231 this->m_ctrlRemoteBranch
.GetWindowText(remotebranch
);
1232 remotebranch
=remote
+_T("/")+remotebranch
;
1233 CGitHash remotebranchHash
;
1234 g_Git
.GetHash(remotebranchHash
, remotebranch
);
1239 str
.LoadString(IDS_PROC_SYNC_PUSH_UNKNOWN
);
1240 m_OutLogList
.ShowText(str
);
1241 this->m_ctrlTabCtrl
.ShowTab(m_OutChangeFileList
.GetDlgCtrlID()-1,FALSE
);
1242 m_OutLocalBranch
.Empty();
1243 m_OutRemoteBranch
.Empty();
1245 this->GetDlgItem(IDC_BUTTON_EMAIL
)->EnableWindow(FALSE
);
1249 else if(remotebranchHash
.IsEmpty())
1252 str
.Format(IDS_PROC_SYNC_PUSH_UNKNOWNBRANCH
, (LPCTSTR
)remotebranch
);
1253 m_OutLogList
.ShowText(str
);
1254 this->m_ctrlTabCtrl
.ShowTab(m_OutChangeFileList
.GetDlgCtrlID()-1,FALSE
);
1255 m_OutLocalBranch
.Empty();
1256 m_OutRemoteBranch
.Empty();
1258 this->GetDlgItem(IDC_BUTTON_EMAIL
)->EnableWindow(FALSE
);
1263 CString localbranch
;
1264 localbranch
=this->m_ctrlLocalBranch
.GetString();
1266 if(localbranch
!= m_OutLocalBranch
|| m_OutRemoteBranch
!= remotebranch
|| force
)
1268 m_OutLogList
.ClearText();
1270 CGitHash base
, localBranchHash
;
1271 bool isFastForward
= g_Git
.IsFastForward(remotebranch
, localbranch
, &base
);
1273 if (g_Git
.GetHash(localBranchHash
, localbranch
))
1275 MessageBox(g_Git
.GetGitLastErr(_T("Could not get hash of \"") + localbranch
+ _T("\".")), _T("TortoiseGit"), MB_ICONERROR
);
1278 if (remotebranchHash
== localBranchHash
)
1281 str
.Format(IDS_PROC_SYNC_COMMITSAHEAD
, 0, (LPCTSTR
)remotebranch
);
1282 m_OutLogList
.ShowText(str
);
1283 this->m_ctrlStatus
.SetWindowText(str
);
1284 this->m_ctrlTabCtrl
.ShowTab(m_OutChangeFileList
.GetDlgCtrlID()-1,FALSE
);
1285 this->GetDlgItem(IDC_BUTTON_EMAIL
)->EnableWindow(FALSE
);
1287 else if (isFastForward
|| m_bForce
)
1290 range
.Format(_T("%s..%s"), (LPCTSTR
)g_Git
.FixBranchName(remotebranch
), (LPCTSTR
)g_Git
.FixBranchName(localbranch
));
1292 m_OutLogList
.FillGitLog(nullptr, &range
, CGit::LOG_INFO_STAT
| CGit::LOG_INFO_FILESTATE
| CGit::LOG_INFO_SHOW_MERGEDFILE
);
1294 str
.Format(IDS_PROC_SYNC_COMMITSAHEAD
, m_OutLogList
.GetItemCount(), (LPCTSTR
)remotebranch
);
1295 this->m_ctrlStatus
.SetWindowText(str
);
1298 AddDiffFileList(&m_OutChangeFileList
, &m_arOutChangeList
, localbranch
, remotebranch
);
1301 AddDiffFileList(&m_OutChangeFileList
, &m_arOutChangeList
, localbranch
, base
.ToString());
1304 this->m_ctrlTabCtrl
.ShowTab(m_OutChangeFileList
.GetDlgCtrlID()-1,TRUE
);
1305 this->GetDlgItem(IDC_BUTTON_EMAIL
)->EnableWindow(TRUE
);
1310 str
.Format(IDS_PROC_SYNC_NOFASTFORWARD
, (LPCTSTR
)localbranch
, (LPCTSTR
)remotebranch
);
1311 m_OutLogList
.ShowText(str
);
1312 this->m_ctrlStatus
.SetWindowText(str
);
1313 this->m_ctrlTabCtrl
.ShowTab(m_OutChangeFileList
.GetDlgCtrlID() - 1, FALSE
);
1314 this->GetDlgItem(IDC_BUTTON_EMAIL
)->EnableWindow(FALSE
);
1317 this->m_OutLocalBranch
=localbranch
;
1318 this->m_OutRemoteBranch
=remotebranch
;
1322 bool CSyncDlg::IsURL()
1325 this->m_ctrlURL
.GetWindowText(str
);
1326 if(str
.Find(_T('\\'))>=0 || str
.Find(_T('/'))>=0)
1332 void CSyncDlg::OnCbnEditchangeComboboxex()
1334 SetTimer(IDT_INPUT
, 1000, nullptr);
1335 this->m_OutLogList
.ShowText(CString(MAKEINTRESOURCE(IDS_PROC_SYNC_WAINTINPUT
)));
1337 //this->FetchOutList();
1340 UINT
CSyncDlg::ProgressThread()
1342 m_startTick
= GetTickCount64();
1345 CProgressDlg::RunCmdList(this, m_GitCmdList
, list
, true, nullptr, &this->m_bAbort
, &this->m_Databuf
);
1346 InterlockedExchange(&m_bBlock
, FALSE
);
1350 LRESULT
CSyncDlg::OnProgressUpdateUI(WPARAM wParam
,LPARAM lParam
)
1354 if(wParam
== MSG_PROGRESSDLG_START
)
1357 m_ctrlAnimate
.Play(0, UINT_MAX
, UINT_MAX
);
1358 this->m_ctrlProgress
.SetPos(0);
1361 m_pTaskbarList
->SetProgressState(m_hWnd
, TBPF_NORMAL
);
1362 m_pTaskbarList
->SetProgressValue(m_hWnd
, 0, 100);
1366 if(wParam
== MSG_PROGRESSDLG_END
|| wParam
== MSG_PROGRESSDLG_FAILED
)
1368 ULONGLONG tickSpent
= GetTickCount64() - m_startTick
;
1369 CString strEndTime
= CLoglistUtils::FormatDateAndTime(CTime::GetCurrentTime(), DATE_SHORTDATE
, true, false);
1372 m_Databuf
.m_critSec
.Lock();
1374 m_Databuf
.m_critSec
.Unlock();
1377 m_ctrlAnimate
.Stop();
1378 m_ctrlProgress
.SetPos(100);
1379 //this->DialogEnableWindow(IDOK,TRUE);
1381 DWORD exitCode
= (DWORD
)lParam
;
1386 m_pTaskbarList
->SetProgressState(m_hWnd
, TBPF_ERROR
);
1387 m_pTaskbarList
->SetProgressValue(m_hWnd
, 100, 100);
1390 log
.Format(IDS_PROC_PROGRESS_GITUNCLEANEXIT
, exitCode
);
1392 err
.Format(_T("\r\n\r\n%s (%I64u ms @ %s)\r\n"), (LPCTSTR
)log
, tickSpent
, (LPCTSTR
)strEndTime
);
1393 CProgressDlg::InsertColorText(this->m_ctrlCmdOut
, err
, RGB(255,0,0));
1394 if (CRegDWORD(_T("Software\\TortoiseGit\\NoSounds"), FALSE
) == FALSE
)
1395 PlaySound((LPCTSTR
)SND_ALIAS_SYSTEMEXCLAMATION
, nullptr, SND_ALIAS_ID
| SND_ASYNC
);
1400 m_pTaskbarList
->SetProgressState(m_hWnd
, TBPF_NOPROGRESS
);
1402 temp
.LoadString(IDS_SUCCESS
);
1404 log
.Format(_T("\r\n%s (%I64u ms @ %s)\r\n"), (LPCTSTR
)temp
, tickSpent
, (LPCTSTR
)strEndTime
);
1405 CProgressDlg::InsertColorText(this->m_ctrlCmdOut
, log
, RGB(0,0,255));
1407 m_GitCmdStatus
= exitCode
;
1409 //if(wParam == MSG_PROGRESSDLG_END)
1414 ParserCmdOutput((char)lParam
);
1417 m_Databuf
.m_critSec
.Lock();
1418 for (size_t i
= m_BufStart
; i
< m_Databuf
.size(); ++i
)
1420 char c
= m_Databuf
[m_BufStart
];
1422 m_Databuf
.m_critSec
.Unlock();
1425 m_Databuf
.m_critSec
.Lock();
1428 if (m_BufStart
> 1000)
1430 m_Databuf
.erase(m_Databuf
.cbegin(), m_Databuf
.cbegin() + m_BufStart
);
1433 m_Databuf
.m_critSec
.Unlock();
1439 static std::map
<CString
, CGitHash
> * HashMapToRefMap(MAP_HASH_NAME
&map
)
1441 auto rmap
= new std::map
<CString
, CGitHash
>();
1442 for (auto mit
= map
.cbegin(); mit
!= map
.cend(); ++mit
)
1444 for (auto rit
= mit
->second
.cbegin(); rit
!= mit
->second
.cend(); ++rit
)
1446 rmap
->insert(std::make_pair(*rit
, mit
->first
));
1452 void CSyncDlg::FillNewRefMap()
1455 m_newHashMap
.clear();
1457 if (!g_Git
.m_IsUseLibGit2
)
1460 CAutoRepository
repo(g_Git
.GetGitRepository());
1463 CMessageBox::Show(m_hWnd
, CGit::GetLibGit2LastErr(_T("Could not open repository.")), _T("TortoiseGit"), MB_OK
| MB_ICONERROR
);
1467 if (CGit::GetMapHashToFriendName(repo
, m_newHashMap
))
1469 MessageBox(CGit::GetLibGit2LastErr(_T("Could not get all refs.")), _T("TortoiseGit"), MB_ICONERROR
);
1473 auto oldRefMap
= HashMapToRefMap(m_oldHashMap
);
1474 auto newRefMap
= HashMapToRefMap(m_newHashMap
);
1475 for (auto oit
= oldRefMap
->cbegin(); oit
!= oldRefMap
->cend(); ++oit
)
1478 for (auto nit
= newRefMap
->cbegin(); nit
!= newRefMap
->cend(); ++nit
)
1481 if (oit
->first
== nit
->first
)
1484 m_refList
.AddEntry(repo
, oit
->first
, &oit
->second
, &nit
->second
);
1490 m_refList
.AddEntry(repo
, oit
->first
, &oit
->second
, nullptr);
1492 for (auto nit
= newRefMap
->cbegin(); nit
!= newRefMap
->cend(); ++nit
)
1495 for (auto oit
= oldRefMap
->cbegin(); oit
!= oldRefMap
->cend(); ++oit
)
1497 if (oit
->first
== nit
->first
)
1505 m_refList
.AddEntry(repo
, nit
->first
, nullptr, &nit
->second
);
1512 void CSyncDlg::RunPostAction()
1519 if (this->m_CurrentCmd
== GIT_COMMAND_PUSH
)
1521 DWORD exitcode
= 0xFFFFFFFF;
1523 if (CHooks::Instance().PostPush(g_Git
.m_CurrentDir
, exitcode
, error
))
1528 temp
.Format(IDS_ERR_HOOKFAILED
, (LPCTSTR
)error
);
1529 CMessageBox::Show(GetSafeHwnd(), temp
, L
"TortoiseGit", MB_OK
| MB_ICONERROR
);
1534 EnableControlButton(true);
1536 this->FetchOutList(true);
1538 else if (this->m_CurrentCmd
== GIT_COMMAND_PULL
)
1540 else if (this->m_CurrentCmd
== GIT_COMMAND_FETCH
|| this->m_CurrentCmd
== GIT_COMMAND_FETCHANDREBASE
)
1542 else if (this->m_CurrentCmd
== GIT_COMMAND_SUBMODULE
)
1544 //this->m_ctrlCmdOut.SetSel(-1,-1);
1545 //this->m_ctrlCmdOut.ReplaceSel(_T("Done\r\n"));
1546 //this->m_ctrlCmdOut.SetSel(-1,-1);
1547 EnableControlButton(true);
1550 else if (this->m_CurrentCmd
== GIT_COMMAND_STASH
)
1552 else if (this->m_CurrentCmd
== GIT_COMMAND_REMOTE
)
1554 this->FetchOutList(true);
1555 EnableControlButton(true);
1557 ShowTab(IDC_REFLIST
);
1560 void CSyncDlg::ParserCmdOutput(char ch
)
1564 CProgressDlg::ParserCmdOutput(m_ctrlCmdOut
,m_ctrlProgress
,m_hWnd
,m_pTaskbarList
,m_LogText
,ch
);
1566 void CSyncDlg::OnBnClickedButtonCommit()
1568 CString cmd
= _T("/command:commit");
1569 cmd
+= _T(" /path:\"");
1570 cmd
+= g_Git
.m_CurrentDir
;
1573 CAppUtils::RunTortoiseGitProc(cmd
);
1576 void CSyncDlg::OnOK()
1580 m_ctrlURL
.SaveHistory();
1582 m_regAutoLoadPutty
= this->m_bAutoLoadPuttyKey
;
1587 void CSyncDlg::OnCancel()
1590 m_GitProgressList
.Cancel();
1591 if (m_bDone
&& !m_GitProgressList
.IsRunning())
1593 CResizableStandAloneDialog::OnCancel();
1596 if (m_GitProgressList
.IsRunning())
1597 WaitForSingleObject(m_GitProgressList
.m_pThread
->m_hThread
, 10000);
1599 if (g_Git
.m_CurrentGitPi
.hProcess
)
1601 DWORD dwConfirmKillProcess
= CRegDWORD(_T("Software\\TortoiseGit\\ConfirmKillProcess"));
1602 if (dwConfirmKillProcess
&& CMessageBox::Show(m_hWnd
, IDS_PROC_CONFIRMKILLPROCESS
, IDS_APPNAME
, MB_YESNO
| MB_ICONQUESTION
) != IDYES
)
1604 if (::GenerateConsoleCtrlEvent(CTRL_C_EVENT
, 0))
1605 ::WaitForSingleObject(g_Git
.m_CurrentGitPi
.hProcess
, 10000);
1609 CProgressDlg::KillProcessTree(g_Git
.m_CurrentGitPi
.dwProcessId
);
1612 ::WaitForSingleObject(g_Git
.m_CurrentGitPi
.hProcess
,10000);
1615 if (::WaitForSingleObject(m_pThread
->m_hThread
, 5000) == WAIT_TIMEOUT
)
1616 g_Git
.KillRelatedThreads(m_pThread
);
1619 CResizableStandAloneDialog::OnCancel();
1622 void CSyncDlg::OnBnClickedButtonSubmodule()
1626 m_ctrlCmdOut
.SetWindowTextW(_T(""));
1629 this->m_regSubmoduleButton
= (DWORD
)this->m_ctrlSubmodule
.GetCurrentEntry();
1631 this->SwitchToRun();
1633 this->m_bAbort
=false;
1634 this->m_GitCmdList
.clear();
1636 ShowTab(IDC_CMD_LOG
);
1640 switch (m_ctrlSubmodule
.GetCurrentEntry())
1643 cmd
=_T("git.exe submodule update --init");
1646 cmd
=_T("git.exe submodule init");
1649 cmd
=_T("git.exe submodule sync");
1653 m_GitCmdList
.push_back(cmd
);
1655 m_CurrentCmd
= GIT_COMMAND_SUBMODULE
;
1657 m_pThread
= AfxBeginThread(ProgressThreadEntry
, this, THREAD_PRIORITY_NORMAL
,0,CREATE_SUSPENDED
);
1660 // ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
1664 m_pThread
->m_bAutoDelete
= TRUE
;
1665 m_pThread
->ResumeThread();
1669 void CSyncDlg::OnBnClickedButtonStash()
1673 m_ctrlCmdOut
.SetWindowTextW(_T(""));
1679 m_GitCmdList
.clear();
1681 ShowTab(IDC_CMD_LOG
);
1683 m_ctrlTabCtrl
.ShowTab(IDC_IN_LOGLIST
- 1, false);
1684 m_ctrlTabCtrl
.ShowTab(IDC_IN_CHANGELIST
-1, false);
1685 m_ctrlTabCtrl
.ShowTab(IDC_IN_CONFLICT
-1, false);
1688 switch (m_ctrlStash
.GetCurrentEntry())
1691 cmd
= _T("git.exe stash save");
1694 cmd
= _T("git.exe stash pop");
1697 cmd
= _T("git.exe stash apply");
1701 m_GitCmdList
.push_back(cmd
);
1702 m_CurrentCmd
= GIT_COMMAND_STASH
;
1704 m_pThread
= AfxBeginThread(ProgressThreadEntry
, this, THREAD_PRIORITY_NORMAL
, 0, CREATE_SUSPENDED
);
1707 //ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
1711 m_pThread
->m_bAutoDelete
= TRUE
;
1712 m_pThread
->ResumeThread();
1716 void CSyncDlg::OnTimer(UINT_PTR nIDEvent
)
1718 if( nIDEvent
== IDT_INPUT
)
1720 KillTimer(IDT_INPUT
);
1721 this->FetchOutList(true);
1726 void CSyncDlg::OnLvnInLogListColumnClick(NMHDR
* /* pNMHDR */, LRESULT
*pResult
)
1731 LRESULT
CSyncDlg::OnTaskbarBtnCreated(WPARAM wParam
, LPARAM lParam
)
1733 m_pTaskbarList
.Release();
1734 m_pTaskbarList
.CoCreateInstance(CLSID_TaskbarList
);
1735 m_GitProgressList
.m_pTaskbarList
= m_pTaskbarList
;
1736 return __super::OnTaskbarButtonCreated(wParam
, lParam
);
1739 void CSyncDlg::OnBnClickedCheckForce()
1744 void CSyncDlg::OnBnClickedLog()
1746 CString cmd
= _T("/command:log");
1747 cmd
+= _T(" /path:\"");
1748 cmd
+= g_Git
.m_CurrentDir
;
1751 CAppUtils::RunTortoiseGitProc(cmd
);
1754 LRESULT
CSyncDlg::OnProgCmdFinish(WPARAM
/*wParam*/, LPARAM
/*lParam*/)
1761 void CSyncDlg::OnDestroy()
1763 m_bWantToExit
= true;
1764 __super::OnDestroy();