Fixed issue #4126: Capitalize the first letter in the Push dialog
[TortoiseGit.git] / src / TortoiseProc / PullFetchDlg.cpp
blob1e1685182636ac9eb992d7435701d081fe2834b1
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2022 - 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 // PullFetchDlg.cpp : implementation file
23 #include "stdafx.h"
24 #include "TortoiseProc.h"
25 #include "PullFetchDlg.h"
26 #include "Git.h"
27 #include "AppUtils.h"
28 #include "SelectRemoteRefDlg.h"
29 #include "MessageBox.h"
30 // CPullFetchDlg dialog
32 IMPLEMENT_DYNAMIC(CPullFetchDlg, CHorizontalResizableStandAloneDialog)
34 CPullFetchDlg::CPullFetchDlg(CWnd* pParent /*=nullptr*/)
35 : CHorizontalResizableStandAloneDialog(CPullFetchDlg::IDD, pParent)
36 , m_IsPull(TRUE)
37 , m_bRebaseActivatedInConfigForPull(false)
38 , m_bNoFF(BST_UNCHECKED)
39 , m_bRebase(BST_UNCHECKED)
40 , m_bRebasePreserveMerges(false)
41 , m_bSquash(BST_UNCHECKED)
42 , m_bNoCommit(BST_UNCHECKED)
43 , m_nDepth(1)
44 , m_bDepth(BST_UNCHECKED)
45 , m_bFFonly(BST_UNCHECKED)
46 , m_bFetchTags(BST_INDETERMINATE)
47 , m_bAllRemotes(BST_UNCHECKED)
48 , m_bPrune(BST_INDETERMINATE)
49 , m_bAutoLoad(CAppUtils::IsSSHPutty())
50 , m_bAutoLoadEnable(CAppUtils::IsSSHPutty())
51 , m_bNamedRemoteFetchAll(!!CRegDWORD(L"Software\\TortoiseGit\\NamedRemoteFetchAll", TRUE))
55 CPullFetchDlg::~CPullFetchDlg()
59 void CPullFetchDlg::DoDataExchange(CDataExchange* pDX)
61 CDialog::DoDataExchange(pDX);
62 DDX_Control(pDX, IDC_REMOTE_COMBO, this->m_Remote);
63 DDX_Control(pDX, IDC_OTHER, this->m_Other);
64 DDX_Control(pDX, IDC_REMOTE_BRANCH, this->m_RemoteBranch);
65 DDX_Control(pDX,IDC_REMOTE_MANAGE, this->m_RemoteManage);
66 DDX_Check(pDX,IDC_CHECK_NOFF, this->m_bNoFF);
67 DDX_Check(pDX,IDC_CHECK_SQUASH, this->m_bSquash);
68 DDX_Check(pDX,IDC_CHECK_NOCOMMIT, this->m_bNoCommit);
69 DDX_Check(pDX,IDC_PUTTYKEY_AUTOLOAD,m_bAutoLoad);
70 DDX_Check(pDX,IDC_CHECK_REBASE,m_bRebase);
71 DDX_Check(pDX,IDC_CHECK_PRUNE,m_bPrune);
72 DDX_Check(pDX, IDC_CHECK_DEPTH, m_bDepth);
73 DDX_Text(pDX, IDC_EDIT_DEPTH, m_nDepth);
74 DDX_Check(pDX, IDC_CHECK_FFONLY, m_bFFonly);
75 DDX_Check(pDX, IDC_CHECK_FETCHTAGS, m_bFetchTags);
79 BEGIN_MESSAGE_MAP(CPullFetchDlg, CHorizontalResizableStandAloneDialog)
80 ON_CBN_SELCHANGE(IDC_REMOTE_COMBO, &CPullFetchDlg::OnCbnSelchangeRemote)
81 ON_BN_CLICKED(IDC_REMOTE_RD, &CPullFetchDlg::OnBnClickedRd)
82 ON_BN_CLICKED(IDC_OTHER_RD, &CPullFetchDlg::OnBnClickedRd)
83 ON_BN_CLICKED(IDOK, &CPullFetchDlg::OnBnClickedOk)
84 ON_STN_CLICKED(IDC_REMOTE_MANAGE, &CPullFetchDlg::OnStnClickedRemoteManage)
85 ON_BN_CLICKED(IDC_BUTTON_BROWSE_REF, &CPullFetchDlg::OnBnClickedButtonBrowseRef)
86 ON_BN_CLICKED(IDC_CHECK_DEPTH, OnBnClickedCheckDepth)
87 ON_BN_CLICKED(IDC_CHECK_FFONLY, OnBnClickedCheckFfonly)
88 ON_BN_CLICKED(IDC_CHECK_NOFF, OnBnClickedCheckFfonly)
89 END_MESSAGE_MAP()
91 BOOL CPullFetchDlg::OnInitDialog()
93 CHorizontalResizableStandAloneDialog::OnInitDialog();
94 CAppUtils::MarkWindowAsUnpinnable(m_hWnd);
96 AdjustControlSize(IDC_REMOTE_RD);
97 AdjustControlSize(IDC_OTHER_RD);
98 AdjustControlSize(IDC_CHECK_SQUASH);
99 AdjustControlSize(IDC_CHECK_NOCOMMIT);
100 AdjustControlSize(IDC_CHECK_DEPTH);
101 AdjustControlSize(IDC_CHECK_NOFF);
102 AdjustControlSize(IDC_CHECK_FFONLY);
103 AdjustControlSize(IDC_CHECK_FETCHTAGS);
104 AdjustControlSize(IDC_PUTTYKEY_AUTOLOAD);
105 AdjustControlSize(IDC_CHECK_REBASE);
106 AdjustControlSize(IDC_CHECK_PRUNE);
108 AddAnchor(IDC_REMOTE_COMBO, TOP_LEFT, TOP_RIGHT);
109 AddAnchor(IDC_OTHER, TOP_LEFT,TOP_RIGHT);
111 AddAnchor(IDC_REMOTE_BRANCH, TOP_LEFT,TOP_RIGHT);
112 AddAnchor(IDC_BUTTON_BROWSE_REF,TOP_RIGHT);
114 AddAnchor(IDOK,BOTTOM_RIGHT);
115 AddAnchor(IDCANCEL,BOTTOM_RIGHT);
116 AddAnchor(IDC_GROUPT_REMOTE,TOP_LEFT,TOP_RIGHT);
117 AddAnchor(IDC_GROUP_OPTION,TOP_LEFT,TOP_RIGHT);
118 AddAnchor(IDC_PUTTYKEY_AUTOLOAD,BOTTOM_LEFT);
119 AddAnchor(IDC_CHECK_PRUNE,BOTTOM_LEFT);
120 AddAnchor(IDC_CHECK_REBASE,BOTTOM_LEFT);
121 AddAnchor(IDC_REMOTE_MANAGE,BOTTOM_LEFT);
122 AddAnchor(IDHELP, BOTTOM_RIGHT);
124 CString WorkingDir=g_Git.m_CurrentDir;
125 WorkingDir.Replace(L':', L'_');
127 m_RemoteReg = CRegString(L"Software\\TortoiseGit\\History\\PullRemote\\" + WorkingDir);
128 CString regkey;
129 regkey.Format(L"Software\\TortoiseGit\\TortoiseProc\\PullFetch\\%s_%d\\rebase", static_cast<LPCWSTR>(WorkingDir), m_IsPull);
130 m_regRebase=CRegDWORD(regkey,false);
131 regkey.Format(L"Software\\TortoiseGit\\TortoiseProc\\PullFetch\\%s_%d\\ffonly", static_cast<LPCWSTR>(WorkingDir), m_IsPull);
132 m_regFFonly = CRegDWORD(regkey, false);
133 regkey.Format(L"Software\\TortoiseGit\\TortoiseProc\\PullFetch\\%s_%d\\autoload", static_cast<LPCWSTR>(WorkingDir), m_IsPull);
135 m_regAutoLoadPutty = CRegDWORD(regkey,this->m_bAutoLoad);
136 m_bAutoLoad = m_regAutoLoadPutty;
138 if(!CAppUtils::IsSSHPutty())
139 m_bAutoLoad = false;
141 m_bRebase = m_regRebase;
143 CAutoRepository repo(g_Git.GetGitRepository());
144 if (!repo)
145 MessageBox(CGit::GetLibGit2LastErr(L"Could not open repository."), L"TortoiseGit", MB_OK | MB_ICONERROR);
147 // Check config branch.<name>.rebase and pull.reabse
150 if (!m_IsPull)
151 break;
152 if (!repo)
153 break;
155 if (git_repository_head_detached(repo) == 1)
156 break;
158 CAutoConfig config(true);
159 if (git_repository_config(config.GetPointer(), repo))
160 break;
162 BOOL rebase = FALSE;
163 // branch.<name>.rebase overrides pull.rebase
164 if (config.GetBOOL(L"branch." + g_Git.GetCurrentBranch() + L".rebase", rebase) == GIT_ENOTFOUND)
166 if (config.GetBOOL(L"pull.rebase", rebase) == GIT_ENOTFOUND)
167 break;
168 else
170 CString value;
171 config.GetString(L"pull.rebase", value);
172 if (value == L"merges")
174 rebase = TRUE;
175 m_bRebasePreserveMerges = true;
179 else
181 CString value;
182 config.GetString(L"branch." + g_Git.GetCurrentBranch() + L".rebase", value);
183 if (value == L"merges")
185 rebase = TRUE;
186 m_bRebasePreserveMerges = true;
189 if (!rebase)
190 break;
192 // Since rebase = true in config, means that "git.exe pull" will ALWAYS rebase without "--rebase".
193 // So, lock it, then let Fetch Rebase do the rest things.
194 m_bRebase = TRUE;
195 m_bRebaseActivatedInConfigForPull = true;
196 } while (0);
198 this->UpdateData(FALSE);
200 this->AddOthersToAnchor();
202 this->GetDlgItem(IDC_PUTTYKEY_AUTOLOAD)->EnableWindow(m_bAutoLoadEnable);
204 CheckRadioButton(IDC_REMOTE_RD,IDC_OTHER_RD,IDC_REMOTE_RD);
205 m_Remote.EnableWindow(TRUE);
206 m_Remote.SetMaxHistoryItems(0x7FFFFFFF);
207 m_Other.EnableWindow(FALSE);
208 m_RemoteBranch.SetCaseSensitive(TRUE);
209 if (!m_IsPull && m_bNamedRemoteFetchAll)
211 m_RemoteBranch.EnableWindow(FALSE);
212 GetDlgItem(IDC_BUTTON_BROWSE_REF)->EnableWindow(FALSE);
215 if(m_IsPull)
217 m_bFFonly = m_regFFonly;
218 UpdateData(FALSE);
219 OnBnClickedCheckFfonly();
221 else
223 this->GetDlgItem(IDC_GROUP_OPTION)->EnableWindow(FALSE);
224 this->GetDlgItem(IDC_CHECK_SQUASH)->EnableWindow(FALSE);
225 this->GetDlgItem(IDC_CHECK_NOFF)->EnableWindow(FALSE);
226 this->GetDlgItem(IDC_CHECK_FFONLY)->EnableWindow(FALSE);
227 this->GetDlgItem(IDC_CHECK_NOCOMMIT)->EnableWindow(FALSE);
230 if (GitAdminDir::IsBareRepo(g_Git.m_CurrentDir))
231 this->GetDlgItem(IDC_CHECK_REBASE)->EnableWindow(FALSE);
233 if (repo && git_repository_is_shallow(repo))
235 m_bDepth = TRUE;
236 UpdateData(FALSE);
238 else
240 GetDlgItem(IDC_CHECK_DEPTH)->ShowWindow(SW_HIDE);
241 DialogEnableWindow(IDC_CHECK_DEPTH, FALSE);
242 GetDlgItem(IDC_EDIT_DEPTH)->ShowWindow(SW_HIDE);
243 DialogEnableWindow(IDC_EDIT_DEPTH, FALSE);
245 OnBnClickedCheckDepth();
247 m_Other.SetCaseSensitive(TRUE);
248 m_Other.SetURLHistory(TRUE);
249 m_Other.LoadHistory(L"Software\\TortoiseGit\\History\\PullURLS", L"url");
251 m_RemoteBranch.LoadHistory(L"Software\\TortoiseGit\\History\\PullRemoteBranch", L"br");
252 m_RemoteBranch.SetCurSel(0);
254 CString sWindowTitle;
255 if(m_IsPull)
256 sWindowTitle.LoadString(IDS_PROGRS_TITLE_PULL);
257 else
258 sWindowTitle.LoadString(IDS_PROGRS_TITLE_FETCH);
260 CAppUtils::SetWindowTitle(m_hWnd, g_Git.m_CurrentDir, sWindowTitle);
262 Refresh();
264 EnableSaveRestore(L"PullFetchDlg");
265 this->m_RemoteManage.SetURL(CString());
266 SetTheme(CTheme::Instance().IsDarkTheme());
267 return TRUE;
270 void CPullFetchDlg::Refresh()
272 //Select pull-remote from current branch
273 CString currentBranch;
274 if (g_Git.GetCurrentBranchFromFile(g_Git.m_CurrentDir, currentBranch))
275 currentBranch.Empty();
277 CString pullRemote, pullBranch;
278 g_Git.GetRemoteTrackedBranch(currentBranch, pullRemote, pullBranch);
279 m_configPullRemote = pullRemote;
280 m_configPullBranch = pullBranch;
282 // determine default remote tracking branch of submodule to remote branch selection
283 CString defaultRemoteTrackingBranch;
284 if (CString parentRepoDir; CTGitPath(g_Git.m_CurrentDir).IsRegisteredSubmoduleOfParentProject(&parentRepoDir))
286 if (CAutoRepository parentRepo(parentRepoDir); parentRepo)
288 auto subModulePath = CUnicodeUtils::GetUTF8(g_Git.m_CurrentDir.Mid(parentRepoDir.GetLength() + 1));
289 subModulePath.Replace('\\', '/');
291 if (CAutoSubmodule subModule; !git_submodule_lookup(subModule.GetPointer(), parentRepo, subModulePath))
293 auto branch = git_submodule_branch(subModule);
294 if (branch)
295 defaultRemoteTrackingBranch = CUnicodeUtils::GetUnicode(branch);
300 // If both pullBranch and currentBranch are empty (i.e. detached HEAD) nothing
301 // will be added to the combo box. If pullBranch is empty and it is a submodule,
302 // its default remote tracking branch will be added.
303 if (!pullBranch.IsEmpty())
304 m_RemoteBranch.AddString(pullBranch);
305 else if (!defaultRemoteTrackingBranch.IsEmpty())
306 m_RemoteBranch.AddString(defaultRemoteTrackingBranch);
307 else
308 m_RemoteBranch.AddString(currentBranch);
310 if(pullRemote.IsEmpty())
311 pullRemote = m_RemoteReg;
313 if (!m_PreSelectRemote.IsEmpty())
314 pullRemote = m_PreSelectRemote;
316 STRING_VECTOR list;
317 m_Remote.Reset();
318 int sel=0;
319 if(!g_Git.GetRemoteList(list))
321 if (!m_IsPull && list.size() > 1)
322 m_Remote.AddString(CString(MAKEINTRESOURCE(IDS_PROC_PUSHFETCH_ALLREMOTES)));
324 for (unsigned int i = 0; i < list.size(); ++i)
326 m_Remote.AddString(list[i]);
327 if (!m_bAllRemotes && list[i] == pullRemote)
328 sel = i + (!m_IsPull && list.size() > 1 ? 1 : 0);
331 m_Remote.SetCurSel(sel);
332 OnCbnSelchangeRemote();
334 // CPullFetchDlg message handlers
336 void CPullFetchDlg::OnCbnSelchangeRemote()
338 CString remote = m_Remote.GetString();
339 if (remote.IsEmpty() || remote == CString(MAKEINTRESOURCE(IDS_PROC_PUSHFETCH_ALLREMOTES)))
341 GetDlgItem(IDC_STATIC_TAGOPT)->SetWindowText(L"");
342 GetDlgItem(IDC_STATIC_PRUNE)->SetWindowText(L"");
343 return;
346 CString key;
347 key.Format(L"remote.%s.tagopt", static_cast<LPCWSTR>(remote));
348 CString tagopt = g_Git.GetConfigValue(key);
349 if (tagopt == "--no-tags")
350 tagopt.LoadString(IDS_NONE);
351 else if (tagopt == "--tags")
352 tagopt.LoadString(IDS_ALL);
353 else
354 tagopt.LoadString(IDS_FETCH_REACHABLE);
355 CString value;
356 value.Format(L"%s: %s", static_cast<LPCWSTR>(CString(MAKEINTRESOURCE(IDS_DEFAULT))), static_cast<LPCWSTR>(tagopt));
357 GetDlgItem(IDC_STATIC_TAGOPT)->SetWindowText(value);
359 key.Format(L"remote.%s.prune", static_cast<LPCWSTR>(remote));
360 CString prune = g_Git.GetConfigValue(key);
361 if (prune.IsEmpty())
362 prune = g_Git.GetConfigValue(L"fetch.prune");
363 if (!prune.IsEmpty())
365 value.Format(L"%s: %s", static_cast<LPCWSTR>(CString(MAKEINTRESOURCE(IDS_DEFAULT))), static_cast<LPCWSTR>(prune));
366 GetDlgItem(IDC_STATIC_PRUNE)->SetWindowText(value);
368 else
369 GetDlgItem(IDC_STATIC_PRUNE)->SetWindowText(L"");
372 void CPullFetchDlg::OnBnClickedRd()
374 if( GetCheckedRadioButton(IDC_REMOTE_RD,IDC_OTHER_RD) == IDC_REMOTE_RD)
376 m_Remote.EnableWindow(TRUE);
377 m_Other.EnableWindow(FALSE);
378 DialogEnableWindow(IDC_CHECK_REBASE, TRUE);
379 m_bRebase = m_bRebaseActivatedInConfigForPull;
380 UpdateData(FALSE);
381 if (!m_IsPull && m_bNamedRemoteFetchAll)
383 m_RemoteBranch.EnableWindow(FALSE);
384 GetDlgItem(IDC_BUTTON_BROWSE_REF)->EnableWindow(FALSE);
387 if( GetCheckedRadioButton(IDC_REMOTE_RD,IDC_OTHER_RD) == IDC_OTHER_RD)
389 // similar code in PushDlg::OnBnClickedRd
390 CString clippath = CAppUtils::GetClipboardLink(m_IsPull ? L"git pull" : L"git fetch", 1);
391 if (clippath.IsEmpty())
392 clippath = CAppUtils::GetClipboardLink(!m_IsPull ? L"git pull" : L"git fetch", 1);
393 if (clippath.IsEmpty())
394 m_Other.SetCurSel(0);
395 else
397 int argSeparator = clippath.Find(' ');
398 if (argSeparator > 1 && clippath.GetLength() > argSeparator + 2)
400 CString url = clippath.Left(argSeparator);
401 if (url.GetLength() > 2 && (url[0] == L'"' && url[url.GetLength() - 1] == L'"' || url[0] == L'\'' && url[url.GetLength() - 1] == L'\''))
402 url = url.Mid(1, url.GetLength() - 2);
403 m_Other.SetWindowText(url);
404 CString branch = clippath.Mid(argSeparator + 1);
405 if (branch.GetLength() > 2 && (branch[0] == L'"' && branch[branch.GetLength() - 1] == L'"' || branch[0] == L'\'' && branch[branch.GetLength() - 1] == L'\''))
406 branch = branch.Mid(1, branch.GetLength() - 2);
407 m_RemoteBranch.SetWindowText(branch);
409 else
410 m_Other.SetWindowText(clippath);
412 m_Remote.EnableWindow(FALSE);
413 m_Other.EnableWindow(TRUE);;
414 DialogEnableWindow(IDC_CHECK_REBASE, FALSE);
415 m_bRebase = FALSE;
416 UpdateData(FALSE);
417 if(!m_IsPull)
419 m_RemoteBranch.EnableWindow(TRUE);
420 GetDlgItem(IDC_BUTTON_BROWSE_REF)->EnableWindow(TRUE);
425 void CPullFetchDlg::OnBnClickedOk()
427 this->UpdateData();
428 if( GetCheckedRadioButton(IDC_REMOTE_RD,IDC_OTHER_RD) == IDC_REMOTE_RD)
430 m_RemoteURL=m_Remote.GetString();
431 m_bAllRemotes = (m_Remote.GetCurSel() == 0 && m_Remote.GetCount() > 1 && !m_IsPull);
432 if (m_bNamedRemoteFetchAll && (!m_IsPull ||
433 (m_configPullRemote == m_RemoteURL && m_configPullBranch == m_RemoteBranch.GetString())))
434 //When fetching or when pulling from the configured tracking branch, dont explicitly set the remote branch name,
435 //because otherwise git will not update the remote tracking branches.
436 m_RemoteBranchName.Empty();
437 else
438 m_RemoteBranchName=m_RemoteBranch.GetString();
440 if( GetCheckedRadioButton(IDC_REMOTE_RD,IDC_OTHER_RD) == IDC_OTHER_RD)
442 m_RemoteURL = m_Other.GetString();
443 m_RemoteBranchName=m_RemoteBranch.GetString();
445 // only store URL in history if it's value was used
446 m_Other.SaveHistory();
449 if (m_bRebase && m_RemoteBranch.GetString().IsEmpty() && m_IsPull)
451 CMessageBox::Show(GetSafeHwnd(), IDS_PROC_PULL_EMPTYBRANCH, IDS_APPNAME, MB_ICONEXCLAMATION);
452 return;
455 m_RemoteReg = m_Remote.GetString();
457 m_RemoteBranch.SaveHistory();
458 this->m_regRebase=this->m_bRebase;
459 m_regFFonly = m_bFFonly;
461 m_regAutoLoadPutty = m_bAutoLoad;
463 this->OnOK();
466 void CPullFetchDlg::OnStnClickedRemoteManage()
468 CAppUtils::LaunchRemoteSetting();
469 Refresh();
472 void CPullFetchDlg::OnBnClickedButtonBrowseRef()
474 CSelectRemoteRefDlg dlg;
475 if (GetCheckedRadioButton(IDC_REMOTE_RD, IDC_OTHER_RD) == IDC_REMOTE_RD)
476 dlg.m_sRemote = m_Remote.GetString();
477 else if (GetCheckedRadioButton(IDC_REMOTE_RD, IDC_OTHER_RD) == IDC_OTHER_RD)
478 dlg.m_sRemote = m_Other.GetString();
479 else
481 ATLASSERT(false);
482 return;
484 if (!dlg.DoModal() == IDOK && !dlg.m_sRemoteBranch.IsEmpty())
485 return;
486 m_RemoteBranch.AddString(dlg.m_sRemoteBranch, 0);
489 void CPullFetchDlg::OnBnClickedCheckDepth()
491 UpdateData(TRUE);
492 GetDlgItem(IDC_EDIT_DEPTH)->EnableWindow(m_bDepth);
495 void CPullFetchDlg::OnBnClickedCheckFfonly()
497 UpdateData();
498 if (m_bNoFF)
500 m_bFFonly = FALSE;
501 GetDlgItem(IDC_CHECK_FFONLY)->EnableWindow(FALSE);
503 else
504 GetDlgItem(IDC_CHECK_FFONLY)->EnableWindow(TRUE);
505 if (m_bFFonly)
507 m_bNoFF = FALSE;
508 GetDlgItem(IDC_CHECK_NOFF)->EnableWindow(FALSE);
510 else
511 GetDlgItem(IDC_CHECK_NOFF)->EnableWindow(TRUE);
512 UpdateData(FALSE);