Prepare release and bump version numbers to 2.17.0.2
[TortoiseGit.git] / src / TortoiseProc / Settings / SettingGitRemote.cpp
blobd945e66cdcf8ca363f331f0f47dd6e1598378411
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2021, 2023-2024 - 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.
19 // SettingGitRemote.cpp : implementation file
22 #include "stdafx.h"
23 #include "TortoiseProc.h"
24 #include "SettingGitRemote.h"
25 #include "Settings.h"
26 #include "GitAdminDir.h"
27 #include "MessageBox.h"
28 #include "AppUtils.h"
29 #include "Git.h"
30 #include "HistoryCombo.h"
32 // CSettingGitRemote dialog
34 IMPLEMENT_DYNAMIC(CSettingGitRemote, ISettingsPropPage)
36 CSettingGitRemote::CSettingGitRemote()
37 : ISettingsPropPage(CSettingGitRemote::IDD)
38 , m_bNoFetch(false)
39 , m_bPrune(2)
40 , m_bPushDefault(FALSE)
44 CSettingGitRemote::~CSettingGitRemote()
48 void CSettingGitRemote::DoDataExchange(CDataExchange* pDX)
50 CPropertyPage::DoDataExchange(pDX);
51 DDX_Control(pDX, IDC_LIST_REMOTE, m_ctrlRemoteList);
52 DDX_Text(pDX, IDC_EDIT_REMOTE, m_strRemote);
53 DDX_Text(pDX, IDC_EDIT_URL, m_strUrl);
54 DDX_Text(pDX, IDC_EDIT_PUSHURL, m_strPushUrl);
55 DDX_Text(pDX, IDC_EDIT_PUTTY_KEY, m_strPuttyKeyfile);
56 DDX_Control(pDX, IDC_COMBO_TAGOPT, m_ctrlTagOpt);
57 DDX_Check(pDX, IDC_CHECK_PRUNE, m_bPrune);
58 DDX_Check(pDX, IDC_CHECK_PUSHDEFAULT, m_bPushDefault);
61 BEGIN_MESSAGE_MAP(CSettingGitRemote, CPropertyPage)
62 ON_WM_TIMER()
63 ON_BN_CLICKED(IDC_BUTTON_BROWSE, &CSettingGitRemote::OnBnClickedButtonBrowse)
64 ON_BN_CLICKED(IDC_BUTTON_ADD, &CSettingGitRemote::OnBnClickedButtonAdd)
65 ON_LBN_SELCHANGE(IDC_LIST_REMOTE, &CSettingGitRemote::OnLbnSelchangeListRemote)
66 ON_EN_CHANGE(IDC_EDIT_REMOTE, &CSettingGitRemote::OnEnChangeEditRemote)
67 ON_EN_CHANGE(IDC_EDIT_URL, &CSettingGitRemote::OnEnChangeEditUrl)
68 ON_EN_CHANGE(IDC_EDIT_PUSHURL, &CSettingGitRemote::OnEnChangeEditPushUrl)
69 ON_EN_CHANGE(IDC_EDIT_PUTTY_KEY, &CSettingGitRemote::OnEnChangeEditPuttyKey)
70 ON_CBN_SELCHANGE(IDC_COMBO_TAGOPT, &CSettingGitRemote::OnCbnSelchangeComboTagOpt)
71 ON_BN_CLICKED(IDC_CHECK_PRUNE, &CSettingGitRemote::OnBnClickedCheckprune)
72 ON_BN_CLICKED(IDC_CHECK_PUSHDEFAULT, &CSettingGitRemote::OnBnClickedCheckpushdefault)
73 ON_BN_CLICKED(IDC_BUTTON_REMOVE, &CSettingGitRemote::OnBnClickedButtonRemove)
74 ON_BN_CLICKED(IDC_BUTTON_RENAME_REMOTE, &CSettingGitRemote::OnBnClickedButtonRenameRemote)
75 END_MESSAGE_MAP()
77 static void ShowEditBalloon(HWND hDlg, UINT nIdControl, UINT nIdText, UINT nIdTitle, int nIcon = TTI_WARNING)
79 CString text(MAKEINTRESOURCE(nIdText));
80 CString title(MAKEINTRESOURCE(nIdTitle));
81 EDITBALLOONTIP bt;
82 bt.cbStruct = sizeof(bt);
83 bt.pszText = text;
84 bt.pszTitle = title;
85 bt.ttiIcon = nIcon;
86 SendDlgItemMessage(hDlg, nIdControl, EM_SHOWBALLOONTIP, 0, reinterpret_cast<LPARAM>(&bt));
89 #define TIMER_PREFILL 1
91 BOOL CSettingGitRemote::OnInitDialog()
93 ISettingsPropPage::OnInitDialog();
95 AdjustControlSize(IDC_CHECK_PRUNE);
96 AdjustControlSize(IDC_CHECK_PUSHDEFAULT);
98 STRING_VECTOR remotes;
99 if (g_Git.GetRemoteList(remotes) != 0)
100 MessageBox(g_Git.GetGitLastErr(L"Could not load remotes."), L"TortoiseGit", MB_ICONERROR);
102 m_ctrlRemoteList.ResetContent();
103 for (size_t i = 0; i < remotes.size(); i++)
104 m_ctrlRemoteList.AddString(remotes[i]);
106 m_ctrlTagOpt.AddString(CString(MAKEINTRESOURCE(IDS_FETCH_REACHABLE)));
107 m_ctrlTagOpt.AddString(CString(MAKEINTRESOURCE(IDS_NONE)));
108 m_ctrlTagOpt.AddString(CString(MAKEINTRESOURCE(IDS_ALL)));
109 m_ctrlTagOpt.SetCurSel(0);
112 CString tmp;
113 tmp.Format(IDS_GITCONFIG_SETTING, L"remote.pushdefault");
114 m_tooltips.AddTool(IDC_CHECK_PUSHDEFAULT, tmp);
115 tmp.Format(IDS_GITCONFIG_SETTING, L"remote.<name>.prune");
116 CString guide;
117 guide.LoadString(IDS_PRUNE_OPTION_GUIDE);
118 tmp += L"\n" + guide;
119 m_tooltips.AddTool(IDC_CHECK_PRUNE, tmp);
120 tmp.Format(IDS_GITCONFIG_SETTING, L"remote<name>.tagopt");
121 m_tooltips.AddTool(IDC_COMBO_TAGOPT, tmp);
124 //this->GetDlgItem(IDC_EDIT_REMOTE)->EnableWindow(FALSE);
125 this->UpdateData(FALSE);
127 SetTimer(TIMER_PREFILL, 1000, nullptr);
128 return TRUE;
130 // CSettingGitRemote message handlers
132 void CSettingGitRemote::OnTimer(UINT_PTR nIDEvent)
134 if (nIDEvent == TIMER_PREFILL)
136 if (m_strRemote.IsEmpty() && m_ctrlRemoteList.GetCount() == 0)
137 ShowEditBalloon(IDC_EDIT_URL, IDS_B_T_PREFILL_ORIGIN, IDS_HINT, TTI_INFO);
139 KillTimer(TIMER_PREFILL);
143 void CSettingGitRemote::OnBnClickedButtonBrowse()
145 UpdateData();
146 CString filename = m_strPuttyKeyfile;
147 if (!PathFileExists(filename))
148 filename.Empty();
149 if (!CAppUtils::FileOpenSave(filename, nullptr, 0, IDS_PUTTYKEYFILEFILTER, true, GetSafeHwnd()))
150 return;
152 m_strPuttyKeyfile = filename;
153 UpdateData(FALSE);
154 OnEnChangeEditPuttyKey();
157 void CSettingGitRemote::OnBnClickedButtonAdd()
159 this->UpdateData();
161 if(m_strRemote.IsEmpty())
163 CMessageBox::Show(GetSafeHwnd(), IDS_PROC_GITCONFIG_REMOTEEMPTY, IDS_APPNAME, MB_OK | MB_ICONERROR);
164 return;
166 if(m_strUrl.IsEmpty())
168 CMessageBox::Show(GetSafeHwnd(), IDS_PROC_GITCONFIG_URLEMPTY, IDS_APPNAME, MB_OK | MB_ICONERROR);
169 return;
172 m_ChangedMask = REMOTE_NAME | REMOTE_URL | REMOTE_PUTTYKEY | REMOTE_TAGOPT | REMOTE_PRUNE | REMOTE_PUSHDEFAULT | REMOTE_PUSHURL;
173 if(IsRemoteExist(m_strRemote))
175 CString msg;
176 msg.Format(IDS_PROC_GITCONFIG_OVERWRITEREMOTE, static_cast<LPCWSTR>(m_strRemote));
177 if (CMessageBox::Show(GetSafeHwnd(), msg, L"TortoiseGit", MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2) == IDYES)
178 m_ChangedMask &= ~REMOTE_NAME;
179 else
180 return;
183 this->OnApply();
186 BOOL CSettingGitRemote::IsRemoteExist(const CString& remote)
188 CString str;
189 for(int i=0;i<m_ctrlRemoteList.GetCount();i++)
191 m_ctrlRemoteList.GetText(i,str);
192 if(str == remote)
193 return true;
195 return false;
198 struct CheckRefspecStruct
200 CStringA remote;
201 bool result;
204 static int CheckRemoteCollideWithRefspec(const git_config_entry *entry, void * payload)
206 auto crs = reinterpret_cast<CheckRefspecStruct*>(payload);
207 crs->result = false;
208 if ("remote." + crs->remote + ".fetch" == entry->name)
209 return 0;
210 CStringA value = CStringA(entry->value);
211 CStringA match = ":refs/remotes/" + crs->remote;
212 int pos = value.Find(match);
213 if (pos < 0)
214 return 0;
215 if ((pos + match.GetLength() == value.GetLength()) || (value[pos + match.GetLength()] == '/'))
217 crs->result = true;
218 return GIT_EUSER;
220 return 0;
223 bool CSettingGitRemote::IsRemoteCollideWithRefspec(CString remote)
225 CheckRefspecStruct crs = { CUnicodeUtils::GetUTF8(remote), false };
226 CAutoConfig config(true);
227 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitLocalConfig()), GIT_CONFIG_LEVEL_LOCAL, g_Git.GetGitRepository(), FALSE);
228 for (const auto pattern : { "remote\\..*\\.fetch", "svn-remote\\..*\\.fetch", "svn-remote\\..*\\.branches", "svn-remote\\..*\\.tags" })
230 git_config_foreach_match(config, pattern, CheckRemoteCollideWithRefspec, &crs);
231 if (crs.result)
232 return true;
234 return false;
237 void CSettingGitRemote::OnLbnSelchangeListRemote()
239 CWaitCursor wait;
241 if(m_ChangedMask)
243 if (CMessageBox::Show(GetSafeHwnd(), IDS_PROC_GITCONFIG_SAVEREMOTE, IDS_APPNAME, 1, IDI_QUESTION, IDS_SAVEBUTTON, IDS_DISCARDBUTTON) == 1)
244 OnApply();
246 SetModified(FALSE);
248 int index = this->m_ctrlRemoteList.GetCurSel();
249 if(index<0)
251 m_strUrl.Empty();
252 m_strPushUrl.Empty();
253 m_strRemote.Empty();
254 m_strPuttyKeyfile.Empty();
255 this->UpdateData(FALSE);
256 return;
258 m_ctrlRemoteList.GetText(index, m_strRemote);
260 CString cmd, output;
261 cmd.Format(L"remote.%s.url", static_cast<LPCWSTR>(m_strRemote));
262 m_strUrl = g_Git.GetConfigValue(cmd);
264 cmd.Format(L"remote.%s.pushurl", static_cast<LPCWSTR>(m_strRemote));
265 m_strPushUrl = g_Git.GetConfigValue(cmd);
267 cmd.Format(L"remote.%s.puttykeyfile", static_cast<LPCWSTR>(m_strRemote));
269 this->m_strPuttyKeyfile = g_Git.GetConfigValue(cmd);
271 m_ChangedMask=0;
274 cmd.Format(L"remote.%s.tagopt", static_cast<LPCWSTR>(m_strRemote));
275 CString tagopt = g_Git.GetConfigValue(cmd);
276 index = 0;
277 if (tagopt == "--no-tags")
278 index = 1;
279 else if (tagopt == "--tags")
280 index = 2;
281 m_ctrlTagOpt.SetCurSel(index);
283 CString pushDefault = g_Git.GetConfigValue(L"remote.pushdefault");
284 m_bPushDefault = pushDefault == m_strRemote ? TRUE : FALSE;
285 cmd.Format(L"remote.%s.prune", static_cast<LPCWSTR>(m_strRemote));
286 CString prune = g_Git.GetConfigValue(cmd);
287 m_bPrune = prune == L"true" ? TRUE : prune == L"false" ? FALSE : 2;
289 GetDlgItem(IDC_BUTTON_ADD)->EnableWindow(TRUE);
290 GetDlgItem(IDC_BUTTON_REMOVE)->EnableWindow(TRUE);
291 GetDlgItem(IDC_BUTTON_RENAME_REMOTE)->EnableWindow(TRUE);
292 this->UpdateData(FALSE);
295 void CSettingGitRemote::OnEnChangeEditRemote()
297 m_ChangedMask|=REMOTE_NAME;
299 this->UpdateData();
301 if (IsRemoteCollideWithRefspec(m_strRemote))
302 ShowEditBalloon(IDC_EDIT_REMOTE, IDS_B_T_REMOTE_NAME_COLLIDE, IDS_HINT, TTI_WARNING);
303 if( (!this->m_strRemote.IsEmpty())&&(!this->m_strUrl.IsEmpty()) )
304 this->SetModified();
307 void CSettingGitRemote::OnEnChangeEditUrl()
309 m_ChangedMask|=REMOTE_URL;
311 this->UpdateData();
313 if (m_strRemote.IsEmpty() && !m_strUrl.IsEmpty() && m_ctrlRemoteList.GetCount() == 0)
315 GetDlgItem(IDC_EDIT_REMOTE)->SetWindowText(L"origin");
316 OnEnChangeEditRemote();
319 if( (!this->m_strRemote.IsEmpty())&&(!this->m_strUrl.IsEmpty()) )
320 this->SetModified();
323 void CSettingGitRemote::OnEnChangeEditPushUrl()
325 m_ChangedMask |= REMOTE_PUSHURL;
327 this->UpdateData();
329 if (!this->m_strRemote.IsEmpty())
330 this->SetModified();
333 void CSettingGitRemote::OnEnChangeEditPuttyKey()
335 m_ChangedMask|=REMOTE_PUTTYKEY;
337 this->UpdateData();
338 if (!this->m_strUrl.IsEmpty())
339 this->SetModified();
342 void CSettingGitRemote::OnCbnSelchangeComboTagOpt()
344 m_ChangedMask |= REMOTE_TAGOPT;
346 this->UpdateData();
347 this->SetModified();
350 void CSettingGitRemote::OnBnClickedCheckprune()
352 m_ChangedMask |= REMOTE_PRUNE;
354 this->UpdateData();
355 this->SetModified();
358 void CSettingGitRemote::OnBnClickedCheckpushdefault()
360 m_ChangedMask |= REMOTE_PUSHDEFAULT;
361 UpdateData();
362 SetModified();
365 BOOL CSettingGitRemote::Save(CString key,CString value)
367 CString cmd,out;
369 cmd.Format(L"remote.%s.%s", static_cast<LPCWSTR>(m_strRemote), static_cast<LPCWSTR>(key));
370 if (value.IsEmpty())
372 // don't check result code. it fails if the entry not exist
373 g_Git.UnsetConfigValue(cmd, CONFIG_LOCAL);
374 if (!g_Git.GetConfigValue(cmd).IsEmpty())
376 CString msg;
377 msg.FormatMessage(IDS_PROC_SAVECONFIGFAILED, static_cast<LPCWSTR>(cmd), static_cast<LPCWSTR>(value));
378 CMessageBox::Show(GetSafeHwnd(), msg, L"TortoiseGit", MB_OK | MB_ICONERROR);
379 return FALSE;
381 return TRUE;
384 if (g_Git.SetConfigValue(cmd, value, CONFIG_LOCAL))
386 CString msg;
387 msg.FormatMessage(IDS_PROC_SAVECONFIGFAILED, static_cast<LPCWSTR>(cmd), static_cast<LPCWSTR>(value));
388 CMessageBox::Show(GetSafeHwnd(), msg, L"TortoiseGit", MB_OK | MB_ICONERROR);
389 return FALSE;
391 return TRUE;
394 BOOL CSettingGitRemote::SaveGeneral(CString key, CString value)
396 if (value.IsEmpty())
398 // don't check result code. it fails if the entry not exist
399 g_Git.UnsetConfigValue(key, CONFIG_LOCAL);
400 if (!g_Git.GetConfigValue(key).IsEmpty())
402 CString msg;
403 msg.FormatMessage(IDS_PROC_SAVECONFIGFAILED, static_cast<LPCWSTR>(key), static_cast<LPCWSTR>(value));
404 CMessageBox::Show(GetSafeHwnd(), msg, L"TortoiseGit", MB_OK | MB_ICONERROR);
405 return FALSE;
407 return TRUE;
410 if (g_Git.SetConfigValue(key, value, CONFIG_LOCAL))
412 CString msg;
413 msg.FormatMessage(IDS_PROC_SAVECONFIGFAILED, static_cast<LPCWSTR>(key), static_cast<LPCWSTR>(value));
414 CMessageBox::Show(GetSafeHwnd(), msg, L"TortoiseGit", MB_OK | MB_ICONERROR);
415 return FALSE;
418 return TRUE;
421 BOOL CSettingGitRemote::OnApply()
423 CWaitCursor wait;
424 this->UpdateData();
426 if (m_ChangedMask & REMOTE_PUSHDEFAULT)
428 if (!m_strRemote.Trim().IsEmpty() && m_bPushDefault)
430 if (!SaveGeneral(L"remote.pushdefault", m_strRemote.Trim()))
431 return FALSE;
433 if (!m_bPushDefault && m_strRemote.Trim() == g_Git.GetConfigValue(L"remote.pushdefault"))
435 if (!SaveGeneral(L"remote.pushdefault", L""))
436 return FALSE;
439 m_ChangedMask &= ~REMOTE_PUSHDEFAULT;
442 if (m_ChangedMask && m_strRemote.Trim().IsEmpty())
444 CMessageBox::Show(GetSafeHwnd(), IDS_PROC_GITCONFIG_REMOTEEMPTY, IDS_APPNAME, MB_OK | MB_ICONERROR);
445 return FALSE;
448 if(m_ChangedMask & REMOTE_NAME)
450 //Add Remote
451 if(m_strRemote.IsEmpty())
453 CMessageBox::Show(GetSafeHwnd(), IDS_PROC_GITCONFIG_REMOTEEMPTY, IDS_APPNAME, MB_OK | MB_ICONERROR);
454 return FALSE;
456 if(m_strUrl.IsEmpty())
458 CMessageBox::Show(GetSafeHwnd(), IDS_PROC_GITCONFIG_URLEMPTY, IDS_APPNAME, MB_OK | MB_ICONERROR);
459 return FALSE;
462 if (m_ctrlRemoteList.GetCount() > 0)
464 // tagopt not --no-tags
465 if (m_ctrlTagOpt.GetCurSel() != 1)
467 if (CMessageBox::ShowCheck(GetSafeHwnd(), IDS_PROC_GITCONFIG_ASKTAGOPT, IDS_APPNAME, MB_YESNO | MB_ICONQUESTION, L"TagOptNoTagsWarning", IDS_MSGBOX_DONOTSHOWAGAIN) == IDYES)
469 m_ctrlTagOpt.SetCurSel(1);
470 m_ChangedMask |= REMOTE_TAGOPT;
475 CString endOfOptions;
476 if (CGit::ms_LastMsysGitVersion >= ConvertVersionToInt(2, 38, 0))
477 endOfOptions = L" --";
479 m_strUrl.Replace(L'\\', L'/');
480 CString cmd,out;
481 cmd.Format(L"git.exe remote add%s \"%s\" \"%s\"", static_cast<LPCWSTR>(endOfOptions), static_cast<LPCWSTR>(m_strRemote), static_cast<LPCWSTR>(m_strUrl));
482 if (g_Git.Run(cmd, &out, CP_UTF8))
484 CMessageBox::Show(GetSafeHwnd(), out, L"TorotiseGit", MB_OK | MB_ICONERROR);
485 return FALSE;
487 m_ChangedMask &= ~REMOTE_URL;
489 m_ctrlRemoteList.SetCurSel(m_ctrlRemoteList.AddString(m_strRemote));
490 GetDlgItem(IDC_BUTTON_ADD)->EnableWindow(TRUE);
491 GetDlgItem(IDC_BUTTON_RENAME_REMOTE)->EnableWindow(TRUE);
492 if (!m_bNoFetch && CMessageBox::Show(GetSafeHwnd(), IDS_SETTINGS_FETCH_ADDEDREMOTE, IDS_APPNAME, MB_ICONQUESTION | MB_YESNO) == IDYES)
493 CCommonAppUtils::RunTortoiseGitProc(L"/command:fetch /path:\"" + g_Git.m_CurrentDir + L"\" /remote:\"" + m_strRemote + L'"');
495 if(m_ChangedMask & REMOTE_URL)
497 m_strUrl.Replace(L'\\', L'/');
498 if (!Save(L"url", m_strUrl))
499 return FALSE;
502 if(m_ChangedMask & REMOTE_PUTTYKEY)
504 if (!Save(L"puttykeyfile", m_strPuttyKeyfile))
505 return FALSE;
508 if (m_ChangedMask & REMOTE_TAGOPT)
510 CString tagopt;
511 int index = m_ctrlTagOpt.GetCurSel();
512 if (index == 1)
513 tagopt = "--no-tags";
514 else if (index == 2)
515 tagopt = "--tags";
516 if (!Save(L"tagopt", tagopt))
517 return FALSE;
520 if (m_ChangedMask & REMOTE_PRUNE)
522 if (!Save(L"prune", m_bPrune == TRUE ? L"true" : m_bPrune == FALSE ? L"false" : L""))
523 return FALSE;
526 if (m_ChangedMask & REMOTE_PUSHURL)
528 m_strPushUrl.Replace(L'\\', L'/');
529 if (!Save(L"pushurl", m_strPushUrl))
530 return FALSE;
533 SetModified(FALSE);
535 m_ChangedMask = 0;
536 return ISettingsPropPage::OnApply();
539 void CleanupSyncRemotes(const CString& remote)
541 CString workingDir = g_Git.m_CurrentDir;
542 workingDir.Replace(L':', L'_');
543 CHistoryCombo::RemoveEntryFromHistory(L"Software\\TortoiseGit\\History\\SyncURL\\" + workingDir, L"url", remote);
546 void CSettingGitRemote::OnBnClickedButtonRemove()
548 int index = m_ctrlRemoteList.GetCurSel();
549 if(index>=0)
551 CString str;
552 m_ctrlRemoteList.GetText(index,str);
553 CString msg;
554 msg.Format(IDS_WARN_REMOVE, static_cast<LPCWSTR>(str));
555 if (CMessageBox::Show(GetSafeHwnd(), msg, L"TortoiseGit", MB_YESNO | MB_ICONQUESTION) == IDYES)
557 CString endOfOptions;
558 if (CGit::ms_LastMsysGitVersion >= ConvertVersionToInt(2, 38, 0))
559 endOfOptions = L" --";
561 CString cmd,out;
562 cmd.Format(L"git.exe remote rm%s \"%s\"", static_cast<LPCWSTR>(endOfOptions), static_cast<LPCWSTR>(str));
563 if (g_Git.Run(cmd, &out, CP_UTF8))
565 CMessageBox::Show(GetSafeHwnd(), out, L"TortoiseGit", MB_OK | MB_ICONERROR);
566 return;
569 CleanupSyncRemotes(str);
570 m_ctrlRemoteList.DeleteString(index);
571 OnLbnSelchangeListRemote();
576 void CSettingGitRemote::OnBnClickedButtonRenameRemote()
578 int sel = m_ctrlRemoteList.GetCurSel();
579 if (sel >= 0)
581 CString oldRemote, newRemote;
582 m_ctrlRemoteList.GetText(sel, oldRemote);
583 GetDlgItem(IDC_EDIT_REMOTE)->GetWindowText(newRemote);
585 CString endOfOptions;
586 if (CGit::ms_LastMsysGitVersion >= ConvertVersionToInt(2, 38, 0))
587 endOfOptions = L" --";
589 CString cmd, out;
590 cmd.Format(L"git.exe remote rename%s \"%s\" \"%s\"", static_cast<LPCWSTR>(endOfOptions), static_cast<LPCWSTR>(oldRemote), static_cast<LPCWSTR>(newRemote));
591 if (g_Git.Run(cmd, &out, CP_UTF8))
593 CMessageBox::Show(GetSafeHwnd(), out, L"TortoiseGit", MB_OK | MB_ICONERROR);
594 return;
597 CleanupSyncRemotes(oldRemote);
598 m_ctrlRemoteList.DeleteString(sel);
599 m_ctrlRemoteList.SetCurSel(m_ctrlRemoteList.AddString(newRemote));
600 m_ChangedMask &= ~REMOTE_NAME;
601 if (!m_ChangedMask)
602 this->SetModified(FALSE);