about summary refs log tree commit diff
path: root/third_party/git/git-gui/lib
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/git/git-gui/lib')
-rw-r--r--third_party/git/git-gui/lib/blame.tcl24
-rw-r--r--third_party/git/git-gui/lib/branch.tcl2
-rw-r--r--third_party/git/git-gui/lib/checkout_op.tcl21
-rw-r--r--third_party/git/git-gui/lib/choose_repository.tcl120
-rw-r--r--third_party/git/git-gui/lib/chord.tcl158
-rw-r--r--third_party/git/git-gui/lib/commit.tcl4
-rw-r--r--third_party/git/git-gui/lib/console.tcl2
-rw-r--r--third_party/git/git-gui/lib/diff.tcl129
-rw-r--r--third_party/git/git-gui/lib/index.tcl533
-rw-r--r--third_party/git/git-gui/lib/merge.tcl14
-rw-r--r--third_party/git/git-gui/lib/status_bar.tcl231
11 files changed, 252 insertions, 986 deletions
diff --git a/third_party/git/git-gui/lib/blame.tcl b/third_party/git/git-gui/lib/blame.tcl
index 62ec08366768..a1aeb8b96e2d 100644
--- a/third_party/git/git-gui/lib/blame.tcl
+++ b/third_party/git/git-gui/lib/blame.tcl
@@ -24,7 +24,6 @@ field w_cviewer  ; # pane showing commit message
 field finder     ; # find mini-dialog frame
 field gotoline   ; # line goto mini-dialog frame
 field status     ; # status mega-widget instance
-field status_operation ; # operation displayed by status mega-widget
 field old_height ; # last known height of $w.file_pane
 
 
@@ -275,7 +274,6 @@ constructor new {i_commit i_path i_jump} {
 	pack $w_cviewer -expand 1 -fill both
 
 	set status [::status_bar::new $w.status]
-	set status_operation {}
 
 	menu $w.ctxm -tearoff 0
 	$w.ctxm add command \
@@ -604,23 +602,16 @@ method _exec_blame {cur_w cur_d options cur_s} {
 	} else {
 		lappend options $commit
 	}
-
-	# We may recurse in from another call to _exec_blame and already have
-	# a status operation.
-	if {$status_operation == {}} {
-		set status_operation [$status start \
-			$cur_s \
-			[mc "lines annotated"]]
-	} else {
-		$status_operation restart $cur_s
-	}
-
 	lappend options -- $path
 	set fd [eval git_read --nice blame $options]
 	fconfigure $fd -blocking 0 -translation lf -encoding utf-8
 	fileevent $fd readable [cb _read_blame $fd $cur_w $cur_d]
 	set current_fd $fd
 	set blame_lines 0
+
+	$status start \
+		$cur_s \
+		[mc "lines annotated"]
 }
 
 method _read_blame {fd cur_w cur_d} {
@@ -815,11 +806,10 @@ method _read_blame {fd cur_w cur_d} {
 				[mc "Loading original location annotations..."]
 		} else {
 			set current_fd {}
-			$status_operation stop [mc "Annotation complete."]
-			set status_operation {}
+			$status stop [mc "Annotation complete."]
 		}
 	} else {
-		$status_operation update $blame_lines $total_lines
+		$status update $blame_lines $total_lines
 	}
 } ifdeleted { catch {close $fd} }
 
@@ -1134,7 +1124,7 @@ method _blameparent {} {
 			set diffcmd [list diff-tree --unified=0 $cparent $cmit -- $new_path]
 		}
 		if {[catch {set fd [eval git_read $diffcmd]} err]} {
-			$status_operation stop [mc "Unable to display parent"]
+			$status stop [mc "Unable to display parent"]
 			error_popup [strcat [mc "Error loading diff:"] "\n\n$err"]
 			return
 		}
diff --git a/third_party/git/git-gui/lib/branch.tcl b/third_party/git/git-gui/lib/branch.tcl
index 8b0c4858890f..777eeb79c135 100644
--- a/third_party/git/git-gui/lib/branch.tcl
+++ b/third_party/git/git-gui/lib/branch.tcl
@@ -8,7 +8,6 @@ proc load_all_heads {} {
 	set rh_len [expr {[string length $rh] + 1}]
 	set all_heads [list]
 	set fd [git_read for-each-ref --format=%(refname) $rh]
-	fconfigure $fd -translation binary -encoding utf-8
 	while {[gets $fd line] > 0} {
 		if {!$some_heads_tracking || ![is_tracking_branch $line]} {
 			lappend all_heads [string range $line $rh_len end]
@@ -25,7 +24,6 @@ proc load_all_tags {} {
 		--sort=-taggerdate \
 		--format=%(refname) \
 		refs/tags]
-	fconfigure $fd -translation binary -encoding utf-8
 	while {[gets $fd line] > 0} {
 		if {![regsub ^refs/tags/ $line {} name]} continue
 		lappend all_tags $name
diff --git a/third_party/git/git-gui/lib/checkout_op.tcl b/third_party/git/git-gui/lib/checkout_op.tcl
index 21ea768d8036..9e7412c446f7 100644
--- a/third_party/git/git-gui/lib/checkout_op.tcl
+++ b/third_party/git/git-gui/lib/checkout_op.tcl
@@ -341,9 +341,9 @@ method _readtree {} {
 	global HEAD
 
 	set readtree_d {}
-	set status_bar_operation [$::main_status start \
+	$::main_status start \
 		[mc "Updating working directory to '%s'..." [_name $this]] \
-		[mc "files checked out"]]
+		[mc "files checked out"]
 
 	set fd [git_read --stderr read-tree \
 		-m \
@@ -354,27 +354,26 @@ method _readtree {} {
 		$new_hash \
 		]
 	fconfigure $fd -blocking 0 -translation binary
-	fileevent $fd readable [cb _readtree_wait $fd $status_bar_operation]
+	fileevent $fd readable [cb _readtree_wait $fd]
 }
 
-method _readtree_wait {fd status_bar_operation} {
+method _readtree_wait {fd} {
 	global current_branch
 
 	set buf [read $fd]
-	$status_bar_operation update_meter $buf
+	$::main_status update_meter $buf
 	append readtree_d $buf
 
 	fconfigure $fd -blocking 1
 	if {![eof $fd]} {
 		fconfigure $fd -blocking 0
-		$status_bar_operation stop
 		return
 	}
 
 	if {[catch {close $fd}]} {
 		set err $readtree_d
 		regsub {^fatal: } $err {} err
-		$status_bar_operation stop [mc "Aborted checkout of '%s' (file level merging is required)." [_name $this]]
+		$::main_status stop [mc "Aborted checkout of '%s' (file level merging is required)." [_name $this]]
 		warn_popup [strcat [mc "File level merge required."] "
 
 $err
@@ -385,12 +384,12 @@ $err
 		return
 	}
 
-	$status_bar_operation stop
+	$::main_status stop
 	_after_readtree $this
 }
 
 method _after_readtree {} {
-	global commit_type HEAD MERGE_HEAD PARENT
+	global selected_commit_type commit_type HEAD MERGE_HEAD PARENT
 	global current_branch is_detached
 	global ui_comm
 
@@ -491,12 +490,12 @@ method _update_repo_state {} {
 	#    amend mode our file lists are accurate and we can avoid
 	#    the rescan.
 	#
-	global commit_type_is_amend commit_type HEAD MERGE_HEAD PARENT
+	global selected_commit_type commit_type HEAD MERGE_HEAD PARENT
 	global ui_comm
 
 	unlock_index
 	set name [_name $this]
-	set commit_type_is_amend 0
+	set selected_commit_type new
 	if {[string match amend* $commit_type]} {
 		$ui_comm delete 0.0 end
 		$ui_comm edit reset
diff --git a/third_party/git/git-gui/lib/choose_repository.tcl b/third_party/git/git-gui/lib/choose_repository.tcl
index e54f3e66d8f0..80f5a59bbbfc 100644
--- a/third_party/git/git-gui/lib/choose_repository.tcl
+++ b/third_party/git/git-gui/lib/choose_repository.tcl
@@ -9,18 +9,6 @@ field w_body      ; # Widget holding the center content
 field w_next      ; # Next button
 field w_quit      ; # Quit button
 field o_cons      ; # Console object (if active)
-
-# Status mega-widget instance during _do_clone2 (used by _copy_files and
-# _link_files). Widget is destroyed before _do_clone2 calls
-# _do_clone_checkout
-field o_status
-
-# Operation displayed by status mega-widget during _do_clone_checkout =>
-# _readtree_wait => _postcheckout_wait => _do_clone_submodules =>
-# _do_validate_submodule_cloning. The status mega-widget is a different
-# instance than that stored in $o_status in earlier operations.
-field o_status_op
-
 field w_types     ; # List of type buttons in clone
 field w_recentlist ; # Listbox containing recent repositories
 field w_localpath  ; # Entry widget bound to local_path
@@ -671,12 +659,12 @@ method _do_clone2 {} {
 
 	switch -exact -- $clone_type {
 	hardlink {
-		set o_status [status_bar::two_line $w_body]
+		set o_cons [status_bar::two_line $w_body]
 		pack $w_body -fill x -padx 10 -pady 10
 
-		set status_op [$o_status start \
+		$o_cons start \
 			[mc "Counting objects"] \
-			[mc "buckets"]]
+			[mc "buckets"]
 		update
 
 		if {[file exists [file join $objdir info alternates]]} {
@@ -701,7 +689,6 @@ method _do_clone2 {} {
 			} err]} {
 				catch {cd $pwd}
 				_clone_failed $this [mc "Unable to copy objects/info/alternates: %s" $err]
-				$status_op stop
 				return
 			}
 		}
@@ -713,7 +700,7 @@ method _do_clone2 {} {
 			-directory [file join $objdir] ??]
 		set bcnt [expr {[llength $buckets] + 2}]
 		set bcur 1
-		$status_op update $bcur $bcnt
+		$o_cons update $bcur $bcnt
 		update
 
 		file mkdir [file join .git objects pack]
@@ -721,7 +708,7 @@ method _do_clone2 {} {
 			-directory [file join $objdir pack] *] {
 			lappend tolink [file join pack $i]
 		}
-		$status_op update [incr bcur] $bcnt
+		$o_cons update [incr bcur] $bcnt
 		update
 
 		foreach i $buckets {
@@ -730,10 +717,10 @@ method _do_clone2 {} {
 				-directory [file join $objdir $i] *] {
 				lappend tolink [file join $i $j]
 			}
-			$status_op update [incr bcur] $bcnt
+			$o_cons update [incr bcur] $bcnt
 			update
 		}
-		$status_op stop
+		$o_cons stop
 
 		if {$tolink eq {}} {
 			info_popup [strcat \
@@ -760,8 +747,6 @@ method _do_clone2 {} {
 		if {!$i} return
 
 		destroy $w_body
-
-		set o_status {}
 	}
 	full {
 		set o_cons [console::embed \
@@ -796,9 +781,9 @@ method _do_clone2 {} {
 }
 
 method _copy_files {objdir tocopy} {
-	set status_op [$o_status start \
+	$o_cons start \
 		[mc "Copying objects"] \
-		[mc "KiB"]]
+		[mc "KiB"]
 	set tot 0
 	set cmp 0
 	foreach p $tocopy {
@@ -813,7 +798,7 @@ method _copy_files {objdir tocopy} {
 
 				while {![eof $f_in]} {
 					incr cmp [fcopy $f_in $f_cp -size 16384]
-					$status_op update \
+					$o_cons update \
 						[expr {$cmp / 1024}] \
 						[expr {$tot / 1024}]
 					update
@@ -823,19 +808,17 @@ method _copy_files {objdir tocopy} {
 				close $f_cp
 			} err]} {
 			_clone_failed $this [mc "Unable to copy object: %s" $err]
-			$status_op stop
 			return 0
 		}
 	}
-	$status_op stop
 	return 1
 }
 
 method _link_files {objdir tolink} {
 	set total [llength $tolink]
-	set status_op [$o_status start \
+	$o_cons start \
 		[mc "Linking objects"] \
-		[mc "objects"]]
+		[mc "objects"]
 	for {set i 0} {$i < $total} {} {
 		set p [lindex $tolink $i]
 		if {[catch {
@@ -844,17 +827,15 @@ method _link_files {objdir tolink} {
 					[file join $objdir $p]
 			} err]} {
 			_clone_failed $this [mc "Unable to hardlink object: %s" $err]
-			$status_op stop
 			return 0
 		}
 
 		incr i
 		if {$i % 5 == 0} {
-			$status_op update $i $total
+			$o_cons update $i $total
 			update
 		}
 	}
-	$status_op stop
 	return 1
 }
 
@@ -977,26 +958,11 @@ method _do_clone_checkout {HEAD} {
 		return
 	}
 
-	set status [status_bar::two_line $w_body]
+	set o_cons [status_bar::two_line $w_body]
 	pack $w_body -fill x -padx 10 -pady 10
-
-	# We start the status operation here.
-	#
-	# This function calls _readtree_wait as a callback.
-	#
-	# _readtree_wait in turn either calls _do_clone_submodules directly,
-	# or calls _postcheckout_wait as a callback which then calls
-	# _do_clone_submodules.
-	#
-	# _do_clone_submodules calls _do_validate_submodule_cloning.
-	#
-	# _do_validate_submodule_cloning stops the status operation.
-	#
-	# There are no other calls into this chain from other code.
-
-	set o_status_op [$status start \
+	$o_cons start \
 		[mc "Creating working directory"] \
-		[mc "files"]]
+		[mc "files"]
 
 	set readtree_err {}
 	set fd [git_read --stderr read-tree \
@@ -1010,9 +976,33 @@ method _do_clone_checkout {HEAD} {
 	fileevent $fd readable [cb _readtree_wait $fd]
 }
 
+method _do_validate_submodule_cloning {ok} {
+	if {$ok} {
+		$o_cons done $ok
+		set done 1
+	} else {
+		_clone_failed $this [mc "Cannot clone submodules."]
+	}
+}
+
+method _do_clone_submodules {} {
+	if {$recursive eq {true}} {
+		destroy $w_body
+		set o_cons [console::embed \
+			$w_body \
+			[mc "Cloning submodules"]]
+		pack $w_body -fill both -expand 1 -padx 10
+		$o_cons exec \
+			[list git submodule update --init --recursive] \
+			[cb _do_validate_submodule_cloning]
+	} else {
+		set done 1
+	}
+}
+
 method _readtree_wait {fd} {
 	set buf [read $fd]
-	$o_status_op update_meter $buf
+	$o_cons update_meter $buf
 	append readtree_err $buf
 
 	fconfigure $fd -blocking 1
@@ -1060,34 +1050,6 @@ method _postcheckout_wait {fd_ph} {
 	fconfigure $fd_ph -blocking 0
 }
 
-method _do_clone_submodules {} {
-	if {$recursive eq {true}} {
-		$o_status_op stop
-		set o_status_op {}
-
-		destroy $w_body
-
-		set o_cons [console::embed \
-			$w_body \
-			[mc "Cloning submodules"]]
-		pack $w_body -fill both -expand 1 -padx 10
-		$o_cons exec \
-			[list git submodule update --init --recursive] \
-			[cb _do_validate_submodule_cloning]
-	} else {
-		set done 1
-	}
-}
-
-method _do_validate_submodule_cloning {ok} {
-	if {$ok} {
-		$o_cons done $ok
-		set done 1
-	} else {
-		_clone_failed $this [mc "Cannot clone submodules."]
-	}
-}
-
 ######################################################################
 ##
 ## Open Existing Repository
diff --git a/third_party/git/git-gui/lib/chord.tcl b/third_party/git/git-gui/lib/chord.tcl
deleted file mode 100644
index e21e7d3d0b79..000000000000
--- a/third_party/git/git-gui/lib/chord.tcl
+++ /dev/null
@@ -1,158 +0,0 @@
-# Simple Chord for Tcl
-#
-# A "chord" is a method with more than one entrypoint and only one body, such
-# that the body runs only once all the entrypoints have been called by
-# different asynchronous tasks. In this implementation, the chord is defined
-# dynamically for each invocation. A SimpleChord object is created, supplying
-# body script to be run when the chord is completed, and then one or more notes
-# are added to the chord. Each note can be called like a proc, and returns
-# immediately if the chord isn't yet complete. When the last remaining note is
-# called, the body runs before the note returns.
-#
-# The SimpleChord class has a constructor that takes the body script, and a
-# method add_note that returns a note object. Since the body script does not
-# run in the context of the procedure that defined it, a mechanism is provided
-# for injecting variables into the chord for use by the body script. The
-# activation of a note is idempotent; multiple calls have the same effect as
-# a simple call.
-#
-# If you are invoking asynchronous operations with chord notes as completion
-# callbacks, and there is a possibility that earlier operations could complete
-# before later ones are started, it is a good practice to create a "common"
-# note on the chord that prevents it from being complete until you're certain
-# you've added all the notes you need.
-#
-# Example:
-#
-#   # Turn off the UI while running a couple of async operations.
-#   lock_ui
-#
-#   set chord [SimpleChord::new {
-#     unlock_ui
-#     # Note: $notice here is not referenced in the calling scope
-#     if {$notice} { info_popup $notice }
-#   }
-#
-#   # Configure a note to keep the chord from completing until
-#   # all operations have been initiated.
-#   set common_note [$chord add_note]
-#
-#   # Activate notes in 'after' callbacks to other operations
-#   set newnote [$chord add_note]
-#   async_operation $args [list $newnote activate]
-#
-#   # Communicate with the chord body
-#   if {$condition} {
-#     # This sets $notice in the same context that the chord body runs in.
-#     $chord eval { set notice "Something interesting" }
-#   }
-#
-#   # Activate the common note, making the chord eligible to complete
-#   $common_note activate
-#
-# At this point, the chord will complete at some unknown point in the future.
-# The common note might have been the first note activated, or the async
-# operations might have completed synchronously and the common note is the
-# last one, completing the chord before this code finishes, or anything in
-# between. The purpose of the chord is to not have to worry about the order.
-
-# SimpleChord class:
-#   Represents a procedure that conceptually has multiple entrypoints that must
-#   all be called before the procedure executes. Each entrypoint is called a
-#   "note". The chord is only "completed" when all the notes are "activated".
-class SimpleChord {
-	field notes
-	field body
-	field is_completed
-	field eval_ns
-
-	# Constructor:
-	#   set chord [SimpleChord::new {body}]
-	#     Creates a new chord object with the specified body script. The
-	#     body script is evaluated at most once, when a note is activated
-	#     and the chord has no other non-activated notes.
-	constructor new {i_body} {
-		set notes [list]
-		set body $i_body
-		set is_completed 0
-		set eval_ns "[namespace qualifiers $this]::eval"
-		return $this
-	}
-
-	# Method:
-	#   $chord eval {script}
-	#     Runs the specified script in the same context (namespace) in which
-	#     the chord body will be evaluated. This can be used to set variable
-	#     values for the chord body to use.
-	method eval {script} {
-		namespace eval $eval_ns $script
-	}
-
-	# Method:
-	#   set note [$chord add_note]
-	#     Adds a new note to the chord, an instance of ChordNote. Raises an
-	#     error if the chord is already completed, otherwise the chord is
-	#     updated so that the new note must also be activated before the
-	#     body is evaluated.
-	method add_note {} {
-		if {$is_completed} { error "Cannot add a note to a completed chord" }
-
-		set note [ChordNote::new $this]
-
-		lappend notes $note
-
-		return $note
-	}
-
-	# This method is for internal use only and is intentionally undocumented.
-	method notify_note_activation {} {
-		if {!$is_completed} {
-			foreach note $notes {
-				if {![$note is_activated]} { return }
-			}
-
-			set is_completed 1
-
-			namespace eval $eval_ns $body
-			delete_this
-		}
-	}
-}
-
-# ChordNote class:
-#   Represents a note within a chord, providing a way to activate it. When the
-#   final note of the chord is activated (this can be any note in the chord,
-#   with all other notes already previously activated in any order), the chord's
-#   body is evaluated.
-class ChordNote {
-	field chord
-	field is_activated
-
-	# Constructor:
-	#   Instances of ChordNote are created internally by calling add_note on
-	#   SimpleChord objects.
-	constructor new {c} {
-		set chord $c
-		set is_activated 0
-		return $this
-	}
-
-	# Method:
-	#   [$note is_activated]
-	#     Returns true if this note has already been activated.
-	method is_activated {} {
-		return $is_activated
-	}
-
-	# Method:
-	#   $note activate
-	#     Activates the note, if it has not already been activated, and
-	#     completes the chord if there are no other notes awaiting
-	#     activation. Subsequent calls will have no further effect.
-	method activate {} {
-		if {!$is_activated} {
-			set is_activated 1
-			$chord notify_note_activation
-		}
-	}
-}
diff --git a/third_party/git/git-gui/lib/commit.tcl b/third_party/git/git-gui/lib/commit.tcl
index b516aa299069..75ea965dacd7 100644
--- a/third_party/git/git-gui/lib/commit.tcl
+++ b/third_party/git/git-gui/lib/commit.tcl
@@ -333,7 +333,7 @@ proc commit_writetree {curHEAD msg_p} {
 proc commit_committree {fd_wt curHEAD msg_p} {
 	global HEAD PARENT MERGE_HEAD commit_type commit_author
 	global current_branch
-	global ui_comm commit_type_is_amend
+	global ui_comm selected_commit_type
 	global file_states selected_paths rescan_active
 	global repo_config
 	global env
@@ -467,8 +467,8 @@ A rescan will be automatically started now.
 
 	# -- Update in memory status
 	#
+	set selected_commit_type new
 	set commit_type normal
-	set commit_type_is_amend 0
 	set HEAD $cmt_id
 	set PARENT $cmt_id
 	set MERGE_HEAD [list]
diff --git a/third_party/git/git-gui/lib/console.tcl b/third_party/git/git-gui/lib/console.tcl
index bb6b9c889e20..1f3248ffd113 100644
--- a/third_party/git/git-gui/lib/console.tcl
+++ b/third_party/git/git-gui/lib/console.tcl
@@ -203,8 +203,6 @@ method done {ok} {
 			focus $w.ok
 		}
 	}
-
-	bind $w <Key-Escape> "destroy $w;break"
 }
 
 method _sb_set {sb orient first last} {
diff --git a/third_party/git/git-gui/lib/diff.tcl b/third_party/git/git-gui/lib/diff.tcl
index 871ad488c2a1..68c4a6c7366f 100644
--- a/third_party/git/git-gui/lib/diff.tcl
+++ b/third_party/git/git-gui/lib/diff.tcl
@@ -55,7 +55,7 @@ proc reshow_diff {{after {}}} {
 
 proc force_diff_encoding {enc} {
 	global current_diff_path
-
+	
 	if {$current_diff_path ne {}} {
 		force_path_encoding $current_diff_path $enc
 		reshow_diff
@@ -270,6 +270,19 @@ proc show_other_diff {path w m cont_info} {
 	}
 }
 
+proc get_conflict_marker_size {path} {
+	set size 7
+	catch {
+		set fd_rc [eval [list git_read check-attr "conflict-marker-size" -- $path]]
+		set ret [gets $fd_rc line]
+		close $fd_rc
+		if {$ret > 0} {
+			regexp {.*: conflict-marker-size: (\d+)$} $line line size
+		}
+	}
+	return $size
+}
+
 proc start_show_diff {cont_info {add_opts {}}} {
 	global file_states file_lists
 	global is_3way_diff is_submodule_diff diff_active repo_config
@@ -285,7 +298,7 @@ proc start_show_diff {cont_info {add_opts {}}} {
 	set is_submodule_diff 0
 	set diff_active 1
 	set current_diff_header {}
-	set conflict_size [gitattr $path conflict-marker-size 7]
+	set conflict_size [get_conflict_marker_size $path]
 
 	set cmd [list]
 	if {$w eq $ui_index} {
@@ -347,10 +360,6 @@ proc start_show_diff {cont_info {add_opts {}}} {
 	}
 
 	set ::current_diff_inheader 1
-	# Detect pre-image lines of the diff3 conflict-style. They are just
-	# '++' lines which is not bijective. Thus, we need to maintain a state
-	# across lines.
-	set ::conflict_in_pre_image 0
 	fconfigure $fd \
 		-blocking 0 \
 		-encoding [get_path_encoding $path] \
@@ -453,23 +462,11 @@ proc read_diff {fd conflict_size cont_info} {
 			{--} {set tags d_--}
 			{++} {
 				set regexp [string map [list %conflict_size $conflict_size]\
-								{^\+\+([<>=|]){%conflict_size}(?: |$)}]
+								{^\+\+([<>=]){%conflict_size}(?: |$)}]
 				if {[regexp $regexp $line _g op]} {
 					set is_conflict_diff 1
 					set line [string replace $line 0 1 {  }]
 					set tags d$op
-
-					# The ||| conflict-marker marks the start of the pre-image.
-					# All those lines are also prefixed with '++'. Thus we need
-					# to maintain this state.
-					set ::conflict_in_pre_image [expr {$op eq {|}}]
-				} elseif {$::conflict_in_pre_image} {
-					# This is a pre-image line. It is the one which both sides
-					# are based on. As it has also the '++' line start, it is
-					# normally shown as 'added'. Invert this to '--' to make
-					# it a 'removed' line.
-					set line [string replace $line 0 1 {--}]
-					set tags d_--
 				} else {
 					set tags d_++
 				}
@@ -570,31 +567,24 @@ proc read_diff {fd conflict_size cont_info} {
 	}
 }
 
-proc apply_or_revert_hunk {x y revert} {
+proc apply_hunk {x y} {
 	global current_diff_path current_diff_header current_diff_side
-	global ui_diff ui_index file_states last_revert last_revert_enc
+	global ui_diff ui_index file_states
 
 	if {$current_diff_path eq {} || $current_diff_header eq {}} return
 	if {![lock_index apply_hunk]} return
 
-	set apply_cmd {apply --whitespace=nowarn}
+	set apply_cmd {apply --cached --whitespace=nowarn}
 	set mi [lindex $file_states($current_diff_path) 0]
 	if {$current_diff_side eq $ui_index} {
 		set failed_msg [mc "Failed to unstage selected hunk."]
-		lappend apply_cmd --reverse --cached
+		lappend apply_cmd --reverse
 		if {[string index $mi 0] ne {M}} {
 			unlock_index
 			return
 		}
 	} else {
-		if {$revert} {
-			set failed_msg [mc "Failed to revert selected hunk."]
-			lappend apply_cmd --reverse
-		} else {
-			set failed_msg [mc "Failed to stage selected hunk."]
-			lappend apply_cmd --cached
-		}
-
+		set failed_msg [mc "Failed to stage selected hunk."]
 		if {[string index $mi 1] ne {M}} {
 			unlock_index
 			return
@@ -613,40 +603,29 @@ proc apply_or_revert_hunk {x y revert} {
 		set e_lno end
 	}
 
-	set wholepatch "$current_diff_header[$ui_diff get $s_lno $e_lno]"
-
 	if {[catch {
 		set enc [get_path_encoding $current_diff_path]
 		set p [eval git_write $apply_cmd]
 		fconfigure $p -translation binary -encoding $enc
-		puts -nonewline $p $wholepatch
+		puts -nonewline $p $current_diff_header
+		puts -nonewline $p [$ui_diff get $s_lno $e_lno]
 		close $p} err]} {
 		error_popup "$failed_msg\n\n$err"
 		unlock_index
 		return
 	}
 
-	if {$revert} {
-		# Save a copy of this patch for undoing reverts.
-		set last_revert $wholepatch
-		set last_revert_enc $enc
-	}
-
 	$ui_diff conf -state normal
 	$ui_diff delete $s_lno $e_lno
 	$ui_diff conf -state disabled
 
-	# Check if the hunk was the last one in the file.
 	if {[$ui_diff get 1.0 end] eq "\n"} {
 		set o _
 	} else {
 		set o ?
 	}
 
-	# Update the status flags.
-	if {$revert} {
-		set mi [string index $mi 0]$o
-	} elseif {$current_diff_side eq $ui_index} {
+	if {$current_diff_side eq $ui_index} {
 		set mi ${o}M
 	} elseif {[string index $mi 0] eq {_}} {
 		set mi M$o
@@ -661,9 +640,9 @@ proc apply_or_revert_hunk {x y revert} {
 	}
 }
 
-proc apply_or_revert_range_or_line {x y revert} {
+proc apply_range_or_line {x y} {
 	global current_diff_path current_diff_header current_diff_side
-	global ui_diff ui_index file_states last_revert
+	global ui_diff ui_index file_states
 
 	set selected [$ui_diff tag nextrange sel 0.0]
 
@@ -681,27 +660,19 @@ proc apply_or_revert_range_or_line {x y revert} {
 	if {$current_diff_path eq {} || $current_diff_header eq {}} return
 	if {![lock_index apply_hunk]} return
 
-	set apply_cmd {apply --whitespace=nowarn}
+	set apply_cmd {apply --cached --whitespace=nowarn}
 	set mi [lindex $file_states($current_diff_path) 0]
 	if {$current_diff_side eq $ui_index} {
 		set failed_msg [mc "Failed to unstage selected line."]
 		set to_context {+}
-		lappend apply_cmd --reverse --cached
+		lappend apply_cmd --reverse
 		if {[string index $mi 0] ne {M}} {
 			unlock_index
 			return
 		}
 	} else {
-		if {$revert} {
-			set failed_msg [mc "Failed to revert selected line."]
-			set to_context {+}
-			lappend apply_cmd --reverse
-		} else {
-			set failed_msg [mc "Failed to stage selected line."]
-			set to_context {-}
-			lappend apply_cmd --cached
-		}
-
+		set failed_msg [mc "Failed to stage selected line."]
+		set to_context {-}
 		if {[string index $mi 1] ne {M}} {
 			unlock_index
 			return
@@ -859,47 +830,7 @@ proc apply_or_revert_range_or_line {x y revert} {
 		puts -nonewline $p $wholepatch
 		close $p} err]} {
 		error_popup "$failed_msg\n\n$err"
-		unlock_index
-		return
-	}
-
-	if {$revert} {
-		# Save a copy of this patch for undoing reverts.
-		set last_revert $current_diff_header$wholepatch
-		set last_revert_enc $enc
-	}
-
-	unlock_index
-}
-
-# Undo the last line/hunk reverted. When hunks and lines are reverted, a copy
-# of the diff applied is saved. Re-apply that diff to undo the revert.
-#
-# Right now, we only use a single variable to hold the copy, and not a
-# stack/deque for simplicity, so multiple undos are not possible. Maybe this
-# can be added if the need for something like this is felt in the future.
-proc undo_last_revert {} {
-	global last_revert current_diff_path current_diff_header
-	global last_revert_enc
-
-	if {$last_revert eq {}} return
-	if {![lock_index apply_hunk]} return
-
-	set apply_cmd {apply --whitespace=nowarn}
-	set failed_msg [mc "Failed to undo last revert."]
-
-	if {[catch {
-		set enc $last_revert_enc
-		set p [eval git_write $apply_cmd]
-		fconfigure $p -translation binary -encoding $enc
-		puts -nonewline $p $last_revert
-		close $p} err]} {
-		error_popup "$failed_msg\n\n$err"
-		unlock_index
-		return
 	}
 
-	set last_revert {}
-
 	unlock_index
 }
diff --git a/third_party/git/git-gui/lib/index.tcl b/third_party/git/git-gui/lib/index.tcl
index 1fc5b42300d6..b588db11d9fc 100644
--- a/third_party/git/git-gui/lib/index.tcl
+++ b/third_party/git/git-gui/lib/index.tcl
@@ -7,74 +7,67 @@ proc _delete_indexlock {} {
 	}
 }
 
-proc close_and_unlock_index {fd after} {
-	if {![catch {_close_updateindex $fd} err]} {
+proc _close_updateindex {fd after} {
+	global use_ttk NS
+	fconfigure $fd -blocking 1
+	if {[catch {close $fd} err]} {
+		set w .indexfried
+		Dialog $w
+		wm withdraw $w
+		wm title $w [strcat "[appname] ([reponame]): " [mc "Index Error"]]
+		wm geometry $w "+[winfo rootx .]+[winfo rooty .]"
+		set s [mc "Updating the Git index failed.  A rescan will be automatically started to resynchronize git-gui."]
+		text $w.msg -yscrollcommand [list $w.vs set] \
+			-width [string length $s] -relief flat \
+			-borderwidth 0 -highlightthickness 0 \
+			-background [get_bg_color $w]
+		$w.msg tag configure bold -font font_uibold -justify center
+		${NS}::scrollbar $w.vs -command [list $w.msg yview]
+		$w.msg insert end $s bold \n\n$err {}
+		$w.msg configure -state disabled
+
+		${NS}::button $w.continue \
+			-text [mc "Continue"] \
+			-command [list destroy $w]
+		${NS}::button $w.unlock \
+			-text [mc "Unlock Index"] \
+			-command "destroy $w; _delete_indexlock"
+		grid $w.msg - $w.vs -sticky news
+		grid $w.unlock $w.continue - -sticky se -padx 2 -pady 2
+		grid columnconfigure $w 0 -weight 1
+		grid rowconfigure $w 0 -weight 1
+
+		wm protocol $w WM_DELETE_WINDOW update
+		bind $w.continue <Visibility> "
+			grab $w
+			focus %W
+		"
+		wm deiconify $w
+		tkwait window $w
+
+		$::main_status stop
 		unlock_index
-		uplevel #0 $after
-	} else {
-		rescan_on_error $err $after
+		rescan $after 0
+		return
 	}
-}
 
-proc _close_updateindex {fd} {
-	fconfigure $fd -blocking 1
-	close $fd
-}
-
-proc rescan_on_error {err {after {}}} {
-	global use_ttk NS
-
-	set w .indexfried
-	Dialog $w
-	wm withdraw $w
-	wm title $w [strcat "[appname] ([reponame]): " [mc "Index Error"]]
-	wm geometry $w "+[winfo rootx .]+[winfo rooty .]"
-	set s [mc "Updating the Git index failed.  A rescan will be automatically started to resynchronize git-gui."]
-	text $w.msg -yscrollcommand [list $w.vs set] \
-		-width [string length $s] -relief flat \
-		-borderwidth 0 -highlightthickness 0 \
-		-background [get_bg_color $w]
-	$w.msg tag configure bold -font font_uibold -justify center
-	${NS}::scrollbar $w.vs -command [list $w.msg yview]
-	$w.msg insert end $s bold \n\n$err {}
-	$w.msg configure -state disabled
-
-	${NS}::button $w.continue \
-		-text [mc "Continue"] \
-		-command [list destroy $w]
-	${NS}::button $w.unlock \
-		-text [mc "Unlock Index"] \
-		-command "destroy $w; _delete_indexlock"
-	grid $w.msg - $w.vs -sticky news
-	grid $w.unlock $w.continue - -sticky se -padx 2 -pady 2
-	grid columnconfigure $w 0 -weight 1
-	grid rowconfigure $w 0 -weight 1
-
-	wm protocol $w WM_DELETE_WINDOW update
-	bind $w.continue <Visibility> "
-		grab $w
-		focus %W
-	"
-	wm deiconify $w
-	tkwait window $w
-
-	$::main_status stop_all
+	$::main_status stop
 	unlock_index
-	rescan [concat $after [list ui_ready]] 0
+	uplevel #0 $after
 }
 
-proc update_indexinfo {msg path_list after} {
+proc update_indexinfo {msg pathList after} {
 	global update_index_cp
 
 	if {![lock_index update]} return
 
 	set update_index_cp 0
-	set path_list [lsort $path_list]
-	set total_cnt [llength $path_list]
-	set batch [expr {int($total_cnt * .01) + 1}]
+	set pathList [lsort $pathList]
+	set totalCnt [llength $pathList]
+	set batch [expr {int($totalCnt * .01) + 1}]
 	if {$batch > 25} {set batch 25}
 
-	set status_bar_operation [$::main_status start $msg [mc "files"]]
+	$::main_status start $msg [mc "files"]
 	set fd [git_write update-index -z --index-info]
 	fconfigure $fd \
 		-blocking 0 \
@@ -85,29 +78,26 @@ proc update_indexinfo {msg path_list after} {
 	fileevent $fd writable [list \
 		write_update_indexinfo \
 		$fd \
-		$path_list \
-		$total_cnt \
+		$pathList \
+		$totalCnt \
 		$batch \
-		$status_bar_operation \
 		$after \
 		]
 }
 
-proc write_update_indexinfo {fd path_list total_cnt batch status_bar_operation \
-	after} {
+proc write_update_indexinfo {fd pathList totalCnt batch after} {
 	global update_index_cp
 	global file_states current_diff_path
 
-	if {$update_index_cp >= $total_cnt} {
-		$status_bar_operation stop
-		close_and_unlock_index $fd $after
+	if {$update_index_cp >= $totalCnt} {
+		_close_updateindex $fd $after
 		return
 	}
 
 	for {set i $batch} \
-		{$update_index_cp < $total_cnt && $i > 0} \
+		{$update_index_cp < $totalCnt && $i > 0} \
 		{incr i -1} {
-		set path [lindex $path_list $update_index_cp]
+		set path [lindex $pathList $update_index_cp]
 		incr update_index_cp
 
 		set s $file_states($path)
@@ -129,21 +119,21 @@ proc write_update_indexinfo {fd path_list total_cnt batch status_bar_operation \
 		display_file $path $new
 	}
 
-	$status_bar_operation update $update_index_cp $total_cnt
+	$::main_status update $update_index_cp $totalCnt
 }
 
-proc update_index {msg path_list after} {
+proc update_index {msg pathList after} {
 	global update_index_cp
 
 	if {![lock_index update]} return
 
 	set update_index_cp 0
-	set path_list [lsort $path_list]
-	set total_cnt [llength $path_list]
-	set batch [expr {int($total_cnt * .01) + 1}]
+	set pathList [lsort $pathList]
+	set totalCnt [llength $pathList]
+	set batch [expr {int($totalCnt * .01) + 1}]
 	if {$batch > 25} {set batch 25}
 
-	set status_bar_operation [$::main_status start $msg [mc "files"]]
+	$::main_status start $msg [mc "files"]
 	set fd [git_write update-index --add --remove -z --stdin]
 	fconfigure $fd \
 		-blocking 0 \
@@ -154,29 +144,26 @@ proc update_index {msg path_list after} {
 	fileevent $fd writable [list \
 		write_update_index \
 		$fd \
-		$path_list \
-		$total_cnt \
+		$pathList \
+		$totalCnt \
 		$batch \
-		$status_bar_operation \
 		$after \
 		]
 }
 
-proc write_update_index {fd path_list total_cnt batch status_bar_operation \
-	after} {
+proc write_update_index {fd pathList totalCnt batch after} {
 	global update_index_cp
 	global file_states current_diff_path
 
-	if {$update_index_cp >= $total_cnt} {
-		$status_bar_operation stop
-		close_and_unlock_index $fd $after
+	if {$update_index_cp >= $totalCnt} {
+		_close_updateindex $fd $after
 		return
 	}
 
 	for {set i $batch} \
-		{$update_index_cp < $total_cnt && $i > 0} \
+		{$update_index_cp < $totalCnt && $i > 0} \
 		{incr i -1} {
-		set path [lindex $path_list $update_index_cp]
+		set path [lindex $pathList $update_index_cp]
 		incr update_index_cp
 
 		switch -glob -- [lindex $file_states($path) 0] {
@@ -203,21 +190,21 @@ proc write_update_index {fd path_list total_cnt batch status_bar_operation \
 		display_file $path $new
 	}
 
-	$status_bar_operation update $update_index_cp $total_cnt
+	$::main_status update $update_index_cp $totalCnt
 }
 
-proc checkout_index {msg path_list after capture_error} {
+proc checkout_index {msg pathList after} {
 	global update_index_cp
 
 	if {![lock_index update]} return
 
 	set update_index_cp 0
-	set path_list [lsort $path_list]
-	set total_cnt [llength $path_list]
-	set batch [expr {int($total_cnt * .01) + 1}]
+	set pathList [lsort $pathList]
+	set totalCnt [llength $pathList]
+	set batch [expr {int($totalCnt * .01) + 1}]
 	if {$batch > 25} {set batch 25}
 
-	set status_bar_operation [$::main_status start $msg [mc "files"]]
+	$::main_status start $msg [mc "files"]
 	set fd [git_write checkout-index \
 		--index \
 		--quiet \
@@ -234,45 +221,26 @@ proc checkout_index {msg path_list after capture_error} {
 	fileevent $fd writable [list \
 		write_checkout_index \
 		$fd \
-		$path_list \
-		$total_cnt \
+		$pathList \
+		$totalCnt \
 		$batch \
-		$status_bar_operation \
 		$after \
-		$capture_error \
 		]
 }
 
-proc write_checkout_index {fd path_list total_cnt batch status_bar_operation \
-	after capture_error} {
+proc write_checkout_index {fd pathList totalCnt batch after} {
 	global update_index_cp
 	global file_states current_diff_path
 
-	if {$update_index_cp >= $total_cnt} {
-		$status_bar_operation stop
-
-		# We do not unlock the index directly here because this
-		# operation expects to potentially run in parallel with file
-		# deletions scheduled by revert_helper. We're done with the
-		# update index, so we close it, but actually unlocking the index
-		# and dealing with potential errors is deferred to the chord
-		# body that runs when all async operations are completed.
-		#
-		# (See after_chord in revert_helper.)
-
-		if {[catch {_close_updateindex $fd} err]} {
-			uplevel #0 $capture_error [list $err]
-		}
-
-		uplevel #0 $after
-
+	if {$update_index_cp >= $totalCnt} {
+		_close_updateindex $fd $after
 		return
 	}
 
 	for {set i $batch} \
-		{$update_index_cp < $total_cnt && $i > 0} \
+		{$update_index_cp < $totalCnt && $i > 0} \
 		{incr i -1} {
-		set path [lindex $path_list $update_index_cp]
+		set path [lindex $pathList $update_index_cp]
 		incr update_index_cp
 		switch -glob -- [lindex $file_states($path) 0] {
 		U? {continue}
@@ -285,7 +253,7 @@ proc write_checkout_index {fd path_list total_cnt batch status_bar_operation \
 		}
 	}
 
-	$status_bar_operation update $update_index_cp $total_cnt
+	$::main_status update $update_index_cp $totalCnt
 }
 
 proc unstage_helper {txt paths} {
@@ -293,7 +261,7 @@ proc unstage_helper {txt paths} {
 
 	if {![lock_index begin-update]} return
 
-	set path_list [list]
+	set pathList [list]
 	set after {}
 	foreach path $paths {
 		switch -glob -- [lindex $file_states($path) 0] {
@@ -301,19 +269,19 @@ proc unstage_helper {txt paths} {
 		M? -
 		T? -
 		D? {
-			lappend path_list $path
+			lappend pathList $path
 			if {$path eq $current_diff_path} {
 				set after {reshow_diff;}
 			}
 		}
 		}
 	}
-	if {$path_list eq {}} {
+	if {$pathList eq {}} {
 		unlock_index
 	} else {
 		update_indexinfo \
 			$txt \
-			$path_list \
+			$pathList \
 			[concat $after [list ui_ready]]
 	}
 }
@@ -337,7 +305,7 @@ proc add_helper {txt paths} {
 
 	if {![lock_index begin-update]} return
 
-	set path_list [list]
+	set pathList [list]
 	set after {}
 	foreach path $paths {
 		switch -glob -- [lindex $file_states($path) 0] {
@@ -353,19 +321,19 @@ proc add_helper {txt paths} {
 		?M -
 		?D -
 		?T {
-			lappend path_list $path
+			lappend pathList $path
 			if {$path eq $current_diff_path} {
 				set after {reshow_diff;}
 			}
 		}
 		}
 	}
-	if {$path_list eq {}} {
+	if {$pathList eq {}} {
 		unlock_index
 	} else {
 		update_index \
 			$txt \
-			$path_list \
+			$pathList \
 			[concat $after {ui_status [mc "Ready to commit."]}]
 	}
 }
@@ -420,303 +388,66 @@ proc do_add_all {} {
 	add_helper [mc "Adding all changed files"] $paths
 }
 
-# Copied from TclLib package "lambda".
-proc lambda {arguments body args} {
-	return [list ::apply [list $arguments $body] {*}$args]
-}
-
 proc revert_helper {txt paths} {
 	global file_states current_diff_path
 
 	if {![lock_index begin-update]} return
 
-	# Common "after" functionality that waits until multiple asynchronous
-	# operations are complete (by waiting for them to activate their notes
-	# on the chord).
-	#
-	# The asynchronous operations are each indicated below by a comment
-	# before the code block that starts the async operation.
-	set after_chord [SimpleChord::new {
-		if {[string trim $err] != ""} {
-			rescan_on_error $err
-		} else {
-			unlock_index
-			if {$should_reshow_diff} { reshow_diff }
-			ui_ready
-		}
-	}]
-
-	$after_chord eval { set should_reshow_diff 0 }
-
-	# This function captures an error for processing when after_chord is
-	# completed. (The chord is curried into the lambda function.)
-	set capture_error [lambda \
-		{chord error} \
-		{ $chord eval [list set err $error] } \
-		$after_chord]
-
-	# We don't know how many notes we're going to create (it's dynamic based
-	# on conditional paths below), so create a common note that will delay
-	# the chord's completion until we activate it, and then activate it
-	# after all the other notes have been created.
-	set after_common_note [$after_chord add_note]
-
-	set path_list [list]
-	set untracked_list [list]
-
+	set pathList [list]
+	set after {}
 	foreach path $paths {
 		switch -glob -- [lindex $file_states($path) 0] {
 		U? {continue}
-		?O {
-			lappend untracked_list $path
-		}
 		?M -
 		?T -
 		?D {
-			lappend path_list $path
+			lappend pathList $path
 			if {$path eq $current_diff_path} {
-				$after_chord eval { set should_reshow_diff 1 }
+				set after {reshow_diff;}
 			}
 		}
 		}
 	}
 
-	set path_cnt [llength $path_list]
-	set untracked_cnt [llength $untracked_list]
-
-	# Asynchronous operation: revert changes by checking them out afresh
-	# from the index.
-	if {$path_cnt > 0} {
-		# Split question between singular and plural cases, because
-		# such distinction is needed in some languages. Previously, the
-		# code used "Revert changes in" for both, but that can't work
-		# in languages where 'in' must be combined with word from
-		# rest of string (in different way for both cases of course).
-		#
-		# FIXME: Unfortunately, even that isn't enough in some languages
-		# as they have quite complex plural-form rules. Unfortunately,
-		# msgcat doesn't seem to support that kind of string
-		# translation.
-		#
-		if {$path_cnt == 1} {
-			set query [mc \
-				"Revert changes in file %s?" \
-				[short_path [lindex $path_list]] \
-				]
-		} else {
-			set query [mc \
-				"Revert changes in these %i files?" \
-				$path_cnt]
-		}
-
-		set reply [tk_dialog \
-			.confirm_revert \
-			"[appname] ([reponame])" \
-			"$query
-
-[mc "Any unstaged changes will be permanently lost by the revert."]" \
-			question \
-			1 \
-			[mc "Do Nothing"] \
-			[mc "Revert Changes"] \
-			]
-
-		if {$reply == 1} {
-			set note [$after_chord add_note]
-			checkout_index \
-				$txt \
-				$path_list \
-				[list $note activate] \
-				$capture_error
-		}
-	}
-
-	# Asynchronous operation: Deletion of untracked files.
-	if {$untracked_cnt > 0} {
-		# Split question between singular and plural cases, because
-		# such distinction is needed in some languages.
-		#
-		# FIXME: Unfortunately, even that isn't enough in some languages
-		# as they have quite complex plural-form rules. Unfortunately,
-		# msgcat doesn't seem to support that kind of string
-		# translation.
-		#
-		if {$untracked_cnt == 1} {
-			set query [mc \
-				"Delete untracked file %s?" \
-				[short_path [lindex $untracked_list]] \
-				]
-		} else {
-			set query [mc \
-				"Delete these %i untracked files?" \
-				$untracked_cnt \
-				]
-		}
-
-		set reply [tk_dialog \
-			.confirm_revert \
-			"[appname] ([reponame])" \
-			"$query
-
-[mc "Files will be permanently deleted."]" \
-			question \
-			1 \
-			[mc "Do Nothing"] \
-			[mc "Delete Files"] \
-			]
-
-		if {$reply == 1} {
-			$after_chord eval { set should_reshow_diff 1 }
 
-			set note [$after_chord add_note]
-			delete_files $untracked_list [list $note activate]
-		}
-	}
-
-	# Activate the common note. If no other notes were created, this
-	# completes the chord. If other notes were created, then this common
-	# note prevents a race condition where the chord might complete early.
-	$after_common_note activate
-}
-
-# Delete all of the specified files, performing deletion in batches to allow the
-# UI to remain responsive and updated.
-proc delete_files {path_list after} {
-	# Enable progress bar status updates
-	set status_bar_operation [$::main_status \
-		start \
-		[mc "Deleting"] \
-		[mc "files"]]
-
-	set path_index 0
-	set deletion_errors [list]
-	set batch_size 50
-
-	delete_helper \
-		$path_list \
-		$path_index \
-		$deletion_errors \
-		$batch_size \
-		$status_bar_operation \
-		$after
-}
-
-# Helper function to delete a list of files in batches. Each call deletes one
-# batch of files, and then schedules a call for the next batch after any UI
-# messages have been processed.
-proc delete_helper {path_list path_index deletion_errors batch_size \
-	status_bar_operation after} {
-	global file_states
-
-	set path_cnt [llength $path_list]
-
-	set batch_remaining $batch_size
-
-	while {$batch_remaining > 0} {
-		if {$path_index >= $path_cnt} { break }
-
-		set path [lindex $path_list $path_index]
-
-		set deletion_failed [catch {file delete -- $path} deletion_error]
-
-		if {$deletion_failed} {
-			lappend deletion_errors [list "$deletion_error"]
-		} else {
-			remove_empty_directories [file dirname $path]
-
-			# Don't assume the deletion worked. Remove the file from
-			# the UI, but only if it no longer exists.
-			if {![path_exists $path]} {
-				unset file_states($path)
-				display_file $path __
-			}
-		}
-
-		incr path_index 1
-		incr batch_remaining -1
-	}
-
-	# Update the progress bar to indicate that this batch has been
-	# completed. The update will be visible when this procedure returns
-	# and allows the UI thread to process messages.
-	$status_bar_operation update $path_index $path_cnt
-
-	if {$path_index < $path_cnt} {
-		# The Tcler's Wiki lists this as the best practice for keeping
-		# a UI active and processing messages during a long-running
-		# operation.
-
-		after idle [list after 0 [list \
-			delete_helper \
-			$path_list \
-			$path_index \
-			$deletion_errors \
-			$batch_size \
-			$status_bar_operation \
-			$after
-			]]
+	# Split question between singular and plural cases, because
+	# such distinction is needed in some languages. Previously, the
+	# code used "Revert changes in" for both, but that can't work
+	# in languages where 'in' must be combined with word from
+	# rest of string (in different way for both cases of course).
+	#
+	# FIXME: Unfortunately, even that isn't enough in some languages
+	# as they have quite complex plural-form rules. Unfortunately,
+	# msgcat doesn't seem to support that kind of string translation.
+	#
+	set n [llength $pathList]
+	if {$n == 0} {
+		unlock_index
+		return
+	} elseif {$n == 1} {
+		set query [mc "Revert changes in file %s?" [short_path [lindex $pathList]]]
 	} else {
-		# Finish the status bar operation.
-		$status_bar_operation stop
-
-		# Report error, if any, based on how many deletions failed.
-		set deletion_error_cnt [llength $deletion_errors]
-
-		if {($deletion_error_cnt > 0)
-		 && ($deletion_error_cnt <= [MAX_VERBOSE_FILES_IN_DELETION_ERROR])} {
-			set error_text [mc "Encountered errors deleting files:\n"]
-
-			foreach deletion_error $deletion_errors {
-				append error_text "* [lindex $deletion_error 0]\n"
-			}
-
-			error_popup $error_text
-		} elseif {$deletion_error_cnt == $path_cnt} {
-			error_popup [mc \
-				"None of the %d selected files could be deleted." \
-				$path_cnt \
-				]
-		} elseif {$deletion_error_cnt > 1} {
-			error_popup [mc \
-				"%d of the %d selected files could not be deleted." \
-				$deletion_error_cnt \
-				$path_cnt \
-				]
-		}
-
-		uplevel #0 $after
+		set query [mc "Revert changes in these %i files?" $n]
 	}
-}
 
-proc MAX_VERBOSE_FILES_IN_DELETION_ERROR {} { return 10; }
-
-# This function is from the TCL documentation:
-#
-#   https://wiki.tcl-lang.org/page/file+exists
-#
-# [file exists] returns false if the path does exist but is a symlink to a path
-# that doesn't exist. This proc returns true if the path exists, regardless of
-# whether it is a symlink and whether it is broken.
-proc path_exists {name} {
-	expr {![catch {file lstat $name finfo}]}
-}
-
-# Remove as many empty directories as we can starting at the specified path,
-# walking up the directory tree. If we encounter a directory that is not
-# empty, or if a directory deletion fails, then we stop the operation and
-# return to the caller. Even if this procedure fails to delete any
-# directories at all, it does not report failure.
-proc remove_empty_directories {directory_path} {
-	set parent_path [file dirname $directory_path]
-
-	while {$parent_path != $directory_path} {
-		set contents [glob -nocomplain -dir $directory_path *]
+	set reply [tk_dialog \
+		.confirm_revert \
+		"[appname] ([reponame])" \
+		"$query
 
-		if {[llength $contents] > 0} { break }
-		if {[catch {file delete -- $directory_path}]} { break }
-
-		set directory_path $parent_path
-		set parent_path [file dirname $directory_path]
+[mc "Any unstaged changes will be permanently lost by the revert."]" \
+		question \
+		1 \
+		[mc "Do Nothing"] \
+		[mc "Revert Changes"] \
+		]
+	if {$reply == 1} {
+		checkout_index \
+			$txt \
+			$pathList \
+			[concat $after [list ui_ready]]
+	} else {
+		unlock_index
 	}
 }
 
@@ -735,19 +466,19 @@ proc do_revert_selection {} {
 }
 
 proc do_select_commit_type {} {
-	global commit_type commit_type_is_amend
+	global commit_type selected_commit_type
 
-	if {$commit_type_is_amend == 0
+	if {$selected_commit_type eq {new}
 		&& [string match amend* $commit_type]} {
 		create_new_commit
-	} elseif {$commit_type_is_amend == 1
+	} elseif {$selected_commit_type eq {amend}
 		&& ![string match amend* $commit_type]} {
 		load_last_commit
 
 		# The amend request was rejected...
 		#
 		if {![string match amend* $commit_type]} {
-			set commit_type_is_amend 0
+			set selected_commit_type new
 		}
 	}
 }
diff --git a/third_party/git/git-gui/lib/merge.tcl b/third_party/git/git-gui/lib/merge.tcl
index 664803cf3fd1..9f253db5b37e 100644
--- a/third_party/git/git-gui/lib/merge.tcl
+++ b/third_party/git/git-gui/lib/merge.tcl
@@ -241,27 +241,23 @@ Continue with resetting the current changes?"]
 	if {[ask_popup $op_question] eq {yes}} {
 		set fd [git_read --stderr read-tree --reset -u -v HEAD]
 		fconfigure $fd -blocking 0 -translation binary
-		set status_bar_operation [$::main_status \
-			start \
-			[mc "Aborting"] \
-			[mc "files reset"]]
-		fileevent $fd readable [namespace code [list \
-			_reset_wait $fd $status_bar_operation]]
+		fileevent $fd readable [namespace code [list _reset_wait $fd]]
+		$::main_status start [mc "Aborting"] [mc "files reset"]
 	} else {
 		unlock_index
 	}
 }
 
-proc _reset_wait {fd status_bar_operation} {
+proc _reset_wait {fd} {
 	global ui_comm
 
-	$status_bar_operation update_meter [read $fd]
+	$::main_status update_meter [read $fd]
 
 	fconfigure $fd -blocking 1
 	if {[eof $fd]} {
 		set fail [catch {close $fd} err]
+		$::main_status stop
 		unlock_index
-		$status_bar_operation stop
 
 		$ui_comm delete 0.0 end
 		$ui_comm edit modified false
diff --git a/third_party/git/git-gui/lib/status_bar.tcl b/third_party/git/git-gui/lib/status_bar.tcl
index d32b14142ff8..02111a1742f9 100644
--- a/third_party/git/git-gui/lib/status_bar.tcl
+++ b/third_party/git/git-gui/lib/status_bar.tcl
@@ -1,42 +1,16 @@
 # git-gui status bar mega-widget
 # Copyright (C) 2007 Shawn Pearce
 
-# The status_bar class manages the entire status bar. It is possible for
-# multiple overlapping asynchronous operations to want to display status
-# simultaneously. Each one receives a status_bar_operation when it calls the
-# start method, and the status bar combines all active operations into the
-# line of text it displays. Most of the time, there will be at most one
-# ongoing operation.
-#
-# Note that the entire status bar can be either in single-line or two-line
-# mode, depending on the constructor. Multiple active operations are only
-# supported for single-line status bars.
-
 class status_bar {
 
-field allow_multiple ; # configured at construction
-
 field w         ; # our own window path
 field w_l       ; # text widget we draw messages into
 field w_c       ; # canvas we draw a progress bar into
 field c_pack    ; # script to pack the canvas with
-
-field baseline_text   ; # text to show if there are no operations
-field status_bar_text ; # combined text for all operations
-
-field operations ; # list of current ongoing operations
-
-# The status bar can display a progress bar, updated when consumers call the
-# update method on their status_bar_operation. When there are multiple
-# operations, the status bar shows the combined status of all operations.
-#
-# When an overlapping operation completes, the progress bar is going to
-# abruptly have one fewer operation in the calculation, causing a discontinuity.
-# Therefore, whenever an operation completes, if it is not the last operation,
-# this counter is increased, and the progress bar is calculated as though there
-# were still another operation at 100%. When the last operation completes, this
-# is reset to 0.
-field completed_operation_count
+field status  {}; # single line of text we show
+field prefix  {}; # text we format into status
+field units   {}; # unit of progress
+field meter   {}; # current core git progress meter (if active)
 
 constructor new {path} {
 	global use_ttk NS
@@ -44,19 +18,12 @@ constructor new {path} {
 	set w_l $w.l
 	set w_c $w.c
 
-	# Standard single-line status bar: Permit overlapping operations
-	set allow_multiple 1
-
-	set baseline_text ""
-	set operations [list]
-	set completed_operation_count 0
-
 	${NS}::frame $w
 	if {!$use_ttk} {
 		$w configure -borderwidth 1 -relief sunken
 	}
 	${NS}::label $w_l \
-		-textvariable @status_bar_text \
+		-textvariable @status \
 		-anchor w \
 		-justify left
 	pack $w_l -side left
@@ -77,16 +44,9 @@ constructor two_line {path} {
 	set w_l $w.l
 	set w_c $w.c
 
-	# Two-line status bar: Only one ongoing operation permitted.
-	set allow_multiple 0
-
-	set baseline_text ""
-	set operations [list]
-	set completed_operation_count 0
-
 	${NS}::frame $w
 	${NS}::label $w_l \
-		-textvariable @status_bar_text \
+		-textvariable @status \
 		-anchor w \
 		-justify left
 	pack $w_l -anchor w -fill x
@@ -96,7 +56,7 @@ constructor two_line {path} {
 	return $this
 }
 
-method ensure_canvas {} {
+method start {msg uds} {
 	if {[winfo exists $w_c]} {
 		$w_c coords bar 0 0 0 20
 	} else {
@@ -108,170 +68,31 @@ method ensure_canvas {} {
 		$w_c create rectangle 0 0 0 20 -tags bar -fill navy
 		eval $c_pack
 	}
-}
-
-method show {msg} {
-	$this ensure_canvas
-	set baseline_text $msg
-	$this refresh
-}
-
-method start {msg {uds {}}} {
-	set baseline_text ""
-
-	if {!$allow_multiple && [llength $operations]} {
-		return [lindex $operations 0]
-	}
-
-	$this ensure_canvas
-
-	set operation [status_bar_operation::new $this $msg $uds]
-
-	lappend operations $operation
-
-	$this refresh
-
-	return $operation
-}
-
-method refresh {} {
-	set new_text ""
-
-	set total [expr $completed_operation_count * 100]
-	set have $total
-
-	foreach operation $operations {
-		if {$new_text != ""} {
-			append new_text " / "
-		}
-
-		append new_text [$operation get_status]
-
-		set total [expr $total + 100]
-		set have [expr $have + [$operation get_progress]]
-	}
-
-	if {$new_text == ""} {
-		set new_text $baseline_text
-	}
-
-	set status_bar_text $new_text
-
-	if {[winfo exists $w_c]} {
-		set pixel_width 0
-		if {$have > 0} {
-			set pixel_width [expr {[winfo width $w_c] * $have / $total}]
-		}
-
-		$w_c coords bar 0 0 $pixel_width 20
-	}
-}
-
-method stop {operation stop_msg} {
-	set idx [lsearch $operations $operation]
-
-	if {$idx >= 0} {
-		set operations [lreplace $operations $idx $idx]
-		set completed_operation_count [expr \
-			$completed_operation_count + 1]
-
-		if {[llength $operations] == 0} {
-			set completed_operation_count 0
-
-			destroy $w_c
-			if {$stop_msg ne {}} {
-				set baseline_text $stop_msg
-			}
-		}
-
-		$this refresh
-	}
-}
-
-method stop_all {{stop_msg {}}} {
-	# This makes the operation's call to stop a no-op.
-	set operations_copy $operations
-	set operations [list]
-
-	foreach operation $operations_copy {
-		$operation stop
-	}
-
-	if {$stop_msg ne {}} {
-		set baseline_text $stop_msg
-	}
-
-	$this refresh
-}
-
-method _delete {current} {
-	if {$current eq $w} {
-		delete_this
-	}
-}
-
-}
-
-# The status_bar_operation class tracks a single consumer's ongoing status bar
-# activity, with the context that there are a few situations where multiple
-# overlapping asynchronous operations might want to display status information
-# simultaneously. Instances of status_bar_operation are created by calling
-# start on the status_bar, and when the caller is done with its stauts bar
-# operation, it calls stop on the operation.
-
-class status_bar_operation {
-
-field status_bar; # reference back to the status_bar that owns this object
-
-field is_active;
-
-field status   {}; # single line of text we show
-field progress {}; # current progress (0 to 100)
-field prefix   {}; # text we format into status
-field units    {}; # unit of progress
-field meter    {}; # current core git progress meter (if active)
-
-constructor new {owner msg uds} {
-	set status_bar $owner
 
 	set status $msg
-	set progress 0
 	set prefix $msg
 	set units  $uds
 	set meter  {}
-
-	set is_active 1
-
-	return $this
 }
 
-method get_is_active {} { return $is_active }
-method get_status {} { return $status }
-method get_progress {} { return $progress }
-
 method update {have total} {
-	if {!$is_active} { return }
-
-	set progress 0
-
+	set pdone 0
+	set cdone 0
 	if {$total > 0} {
-		set progress [expr {100 * $have / $total}]
+		set pdone [expr {100 * $have / $total}]
+		set cdone [expr {[winfo width $w_c] * $have / $total}]
 	}
 
 	set prec [string length [format %i $total]]
-
 	set status [mc "%s ... %*i of %*i %s (%3i%%)" \
 		$prefix \
 		$prec $have \
 		$prec $total \
-		$units $progress]
-
-	$status_bar refresh
+		$units $pdone]
+	$w_c coords bar 0 0 $cdone 20
 }
 
 method update_meter {buf} {
-	if {!$is_active} { return }
-
 	append meter $buf
 	set r [string last "\r" $meter]
 	if {$r == -1} {
@@ -288,25 +109,23 @@ method update_meter {buf} {
 	}
 }
 
-method stop {{stop_msg {}}} {
-	if {$is_active} {
-		set is_active 0
-		$status_bar stop $this $stop_msg
+method stop {{msg {}}} {
+	destroy $w_c
+	if {$msg ne {}} {
+		set status $msg
 	}
 }
 
-method restart {msg} {
-	if {!$is_active} { return }
-
-	set status $msg
-	set prefix $msg
-	set meter {}
-	$status_bar refresh
+method show {msg {test {}}} {
+	if {$test eq {} || $status eq $test} {
+		set status $msg
+	}
 }
 
-method _delete {} {
-	stop
-	delete_this
+method _delete {current} {
+	if {$current eq $w} {
+		delete_this
+	}
 }
 
 }