Skip to content

Commit 2284168

Browse files
jeremypwJeremy Woottenzeebok
authored
Confirm overwriting uncommitted changes on branch change (#1524)
* Add confirm overwrite uncommitted dialog * Include uncommitted diff in dialog --------- Co-authored-by: Jeremy Wootten <jeremy@Proteus-EL07R6-9b3c42bb.localdomain> Co-authored-by: Ryan Kornheisl <ryan@skarva.tech>
1 parent f77f5f5 commit 2284168

5 files changed

Lines changed: 116 additions & 4 deletions

File tree

po/POTFILES

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ src/Dialogs/GlobalSearchDialog.vala
55
src/Dialogs/NewBranchDialog.vala
66
src/Dialogs/PreferencesDialog.vala
77
src/Dialogs/RestoreConfirmationDialog.vala
8+
src/Dialogs/OverwriteUncommittedConfirmationDialog.vala
89
src/FolderManager/File.vala
910
src/FolderManager/FileItem.vala
1011
src/FolderManager/FileView.vala
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright 2025 elementary, Inc. (https://elementary.io)
3+
*
4+
* This program is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU Lesser General Public
6+
* License version 3 as published by the Free Software Foundation.
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+
* General Public License for more details.
12+
*
13+
* You should have received a copy of the GNU Lesser General Public
14+
* License along with this program; if not, write to the
15+
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16+
* Boston, MA 02110-1301 USA
17+
*/
18+
19+
public class Scratch.Dialogs.OverwriteUncommittedConfirmationDialog : Granite.MessageDialog {
20+
21+
public string branch_name { get; construct; }
22+
public OverwriteUncommittedConfirmationDialog (
23+
Gtk.Window parent,
24+
string new_branch_name,
25+
string details
26+
) {
27+
Object (
28+
buttons: Gtk.ButtonsType.NONE,
29+
transient_for: parent,
30+
branch_name: new_branch_name
31+
);
32+
33+
show_error_details (details);
34+
}
35+
36+
construct {
37+
modal = true;
38+
image_icon = new ThemedIcon ("dialog-stop");
39+
40+
primary_text = _("There are uncommitted changes in the current branch");
41+
///TRANSLATORS '%s' is a placeholder for the name of the branch to be checked out
42+
secondary_text = _("Uncommitted changes will be permanently lost if <b>'%s'</b> is checked out now.\n\n<i>It is recommended that uncommitted changes are stashed, committed, or reverted before proceeding </i>").printf (branch_name);
43+
44+
var proceed_button = (Gtk.Button) add_button (_("Checkout and Overwrite"), Gtk.ResponseType.ACCEPT);
45+
proceed_button.get_style_context ().add_class (Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION);
46+
var cancel_button = add_button (_("Do not Checkout"), Gtk.ResponseType.REJECT);
47+
cancel_button.get_style_context ().add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION);
48+
}
49+
}

src/FolderManager/ProjectFolderItem.vala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ namespace Scratch.FolderManager {
349349
private void handle_change_branch_action (GLib.Variant? parameter) {
350350
var branch_name = parameter.get_string ();
351351
try {
352-
monitored_repo.change_branch (branch_name);
352+
monitored_repo.change_local_branch (branch_name);
353353
} catch (GLib.Error e) {
354354
warning ("Failed to change branch to %s. %s", branch_name, e.message);
355355
}

src/Services/MonitoredRepository.vala

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,17 +186,43 @@ namespace Scratch.Services {
186186
return true;
187187
}
188188

189-
public void change_branch (string new_branch_name) throws Error {
189+
public void change_local_branch (string new_branch_name) throws Error {
190190
var branch = git_repo.lookup_branch (new_branch_name, Ggit.BranchType.LOCAL);
191-
git_repo.set_head (((Ggit.Ref)branch).get_name ());
191+
checkout_branch (branch);
192+
}
193+
194+
private void checkout_branch (Ggit.Branch new_head_branch, bool confirm = true) throws Error {
195+
if (confirm && has_uncommitted) {
196+
confirm_checkout_branch (new_head_branch);
197+
return;
198+
}
199+
200+
git_repo.set_head (((Ggit.Ref) new_head_branch).get_name ());
192201
var options = new Ggit.CheckoutOptions () {
193202
//Ensure documents match checked out branch (deal with potential conflicts/losses beforehand)
194203
strategy = Ggit.CheckoutStrategy.FORCE
195204
};
196205

197206
git_repo.checkout_head (options);
198207

199-
branch_name = new_branch_name;
208+
branch_name = new_head_branch.get_name ();
209+
}
210+
211+
private void confirm_checkout_branch (Ggit.Branch new_head_branch) {
212+
var parent = ((Gtk.Application)(GLib.Application.get_default ())).get_active_window ();
213+
var dialog = new Scratch.Dialogs.OverwriteUncommittedConfirmationDialog (
214+
parent,
215+
new_head_branch.get_name (),
216+
get_project_diff ()
217+
);
218+
dialog.response.connect ((res) => {
219+
dialog.destroy ();
220+
if (res == Gtk.ResponseType.ACCEPT) {
221+
checkout_branch (new_head_branch, false);
222+
}
223+
});
224+
225+
dialog.present ();
200226
}
201227

202228
public void create_new_branch (string name) throws Error {
@@ -264,6 +290,41 @@ namespace Scratch.Services {
264290
return git_repo.path_is_ignored (path);
265291
}
266292

293+
public string get_project_diff () throws GLib.Error {
294+
var sb = new StringBuilder ("");
295+
var repo_diff_list = new Ggit.Diff.index_to_workdir (git_repo, null, null);
296+
repo_diff_list.print (Ggit.DiffFormatType.PATCH, (delta, hunk, line) => {
297+
unowned var file_diff = delta.get_old_file ();
298+
if (file_diff == null) {
299+
return 0;
300+
}
301+
302+
if (line != null) {
303+
var delta_type = line.get_origin ();
304+
string prefix = "?";
305+
switch (delta_type) {
306+
case Ggit.DiffLineType.ADDITION:
307+
prefix = "+";
308+
break;
309+
case Ggit.DiffLineType.DELETION:
310+
prefix = "-";
311+
break;
312+
case Ggit.DiffLineType.CONTEXT:
313+
prefix = " ";
314+
break;
315+
default:
316+
break;
317+
}
318+
//TODO Add color according to linetype
319+
sb.append (prefix + line.get_text ());
320+
}
321+
return 0;
322+
});
323+
324+
return sb.str;
325+
}
326+
327+
267328
private bool refreshing = false;
268329
public void refresh_diff (string file_path, ref Gee.HashMap<int, VCStatus> line_status_map) {
269330
if (refreshing) {

src/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ code_files = files(
2020
'Utils.vala',
2121
'Dialogs/PreferencesDialog.vala',
2222
'Dialogs/RestoreConfirmationDialog.vala',
23+
'Dialogs/OverwriteUncommittedConfirmationDialog.vala',
2324
'Dialogs/GlobalSearchDialog.vala',
2425
'Dialogs/NewBranchDialog.vala',
2526
'FolderManager/File.vala',

0 commit comments

Comments
 (0)