diff --git a/git-gui.sh b/git-gui.sh
index 9fa467ab9f25c2283a56810b80b40267ed0648e7..85be9833a020f72f7836492d90535b39d24d5c07 100755 (executable)
--- a/git-gui.sh
+++ b/git-gui.sh
__ -
A_ -
M_ -
- DD {
+ D_ {
unset file_states($path)
catch {unset selected_paths($path)}
}
AM -
AD -
MM -
- MD -
- DM {
+ MD {
set file_states($path) [list \
_[string index $m 1] \
[lindex $s 1] \
proc display_all_files {} {
global ui_index ui_workdir
global file_states file_lists
- global last_clicked selected_paths
+ global last_clicked
$ui_index conf -state normal
$ui_workdir conf -state normal
set info [lindex $s 2]
if {$info eq {}} continue
- puts -nonewline $fd $info
- puts -nonewline $fd "\t"
- puts -nonewline $fd $path
- puts -nonewline $fd "\0"
+ puts -nonewline $fd "$info\t$path\0"
display_file $path $new
}
incr update_index_cp
switch -glob -- [lindex $file_states($path) 0] {
- AD -
- MD -
- UD -
- _D {set new DD}
-
- _M -
- MM -
- UM -
- U_ -
- M_ {set new M_}
-
+ AD {set new __}
+ ?D {set new D_}
_O -
- AM -
- A_ {set new A_}
-
+ AM {set new A_}
+ U_ -
+ ?M {set new M_}
?? {continue}
}
-
- puts -nonewline $fd $path
- puts -nonewline $fd "\0"
+ puts -nonewline $fd "$path\0"
display_file $path $new
}
{incr i -1} {
set path [lindex $pathList $update_index_cp]
incr update_index_cp
-
switch -glob -- [lindex $file_states($path) 0] {
- AM -
- AD {set new A_}
- MM -
- MD {set new M_}
- _M -
- _D {set new __}
- ?? {continue}
+ U? {continue}
+ ?M -
+ ?D {
+ puts -nonewline $fd "$path\0"
+ display_file $path ?_
+ }
}
-
- puts -nonewline $fd $path
- puts -nonewline $fd "\0"
- display_file $path $new
}
set ui_status_value [format \
set all_heads [lsort $all_heads]
}
-proc populate_branch_menu {m} {
+proc populate_branch_menu {} {
global all_heads disable_on_lock
+ set m .mbar.branch
+ set last [$m index last]
+ for {set i 0} {$i <= $last} {incr i} {
+ if {[$m type $i] eq {separator}} {
+ $m delete $i last
+ set new_dol [list]
+ foreach a $disable_on_lock {
+ if {[lindex $a 0] ne $m || [lindex $a 2] < $i} {
+ lappend new_dol $a
+ }
+ }
+ set disable_on_lock $new_dol
+ break
+ }
+ }
+
$m add separator
foreach b $all_heads {
$m add radiobutton \
}
}
+proc do_create_branch_action {w} {
+ global all_heads null_sha1
+ global create_branch_checkout create_branch_revtype create_branch_head
+
+ set newbranch [string trim [$w.name.t get 0.0 end]]
+ if {![catch {exec git show-ref --verify -- "refs/heads/$newbranch"}]} {
+ tk_messageBox \
+ -icon error \
+ -type ok \
+ -title [wm title $w] \
+ -parent $w \
+ -message "Branch '$newbranch' already exists."
+ focus $w.name.t
+ return
+ }
+ if {[catch {exec git check-ref-format "heads/$newbranch"}]} {
+ tk_messageBox \
+ -icon error \
+ -type ok \
+ -title [wm title $w] \
+ -parent $w \
+ -message "We do not like '$newbranch' as a branch name."
+ focus $w.name.t
+ return
+ }
+
+ set rev {}
+ switch -- $create_branch_revtype {
+ head {set rev $create_branch_head}
+ expression {set rev [string trim [$w.from.exp.t get 0.0 end]]}
+ }
+ if {[catch {set cmt [exec git rev-parse --verify "${rev}^0"]}]} {
+ tk_messageBox \
+ -icon error \
+ -type ok \
+ -title [wm title $w] \
+ -parent $w \
+ -message "Invalid starting revision: $rev"
+ return
+ }
+ set cmd [list git update-ref]
+ lappend cmd -m
+ lappend cmd "branch: Created from $rev"
+ lappend cmd "refs/heads/$newbranch"
+ lappend cmd $cmt
+ lappend cmd $null_sha1
+ if {[catch {eval exec $cmd} err]} {
+ tk_messageBox \
+ -icon error \
+ -type ok \
+ -title [wm title $w] \
+ -parent $w \
+ -message "Failed to create '$newbranch'.\n\n$err"
+ return
+ }
+
+ lappend all_heads $newbranch
+ set all_heads [lsort $all_heads]
+ populate_branch_menu
+ destroy $w
+}
+
proc do_create_branch {} {
- error "NOT IMPLEMENTED"
+ global all_heads current_branch
+ global create_branch_checkout create_branch_revtype create_branch_head
+
+ set create_branch_checkout true
+ set create_branch_revtype head
+ set create_branch_head $current_branch
+
+ set w .branch_editor
+ toplevel $w
+ wm geometry $w "+[winfo rootx .]+[winfo rooty .]"
+
+ label $w.header -text {Create New Branch} \
+ -font font_uibold
+ pack $w.header -side top -fill x
+
+ frame $w.buttons
+ button $w.buttons.create -text Create \
+ -font font_ui \
+ -default active \
+ -command [list do_create_branch_action $w]
+ pack $w.buttons.create -side right
+ button $w.buttons.cancel -text {Cancel} \
+ -font font_ui \
+ -command [list destroy $w]
+ pack $w.buttons.cancel -side right -padx 5
+ pack $w.buttons -side bottom -fill x -pady 10 -padx 10
+
+ labelframe $w.name \
+ -text {Branch Description} \
+ -font font_ui
+ label $w.name.l -text {Name:} -font font_ui
+ text $w.name.t \
+ -height 1 \
+ -width 40 \
+ -font font_ui
+ bind $w.name.t <Shift-Key-Tab> "focus $w.postActions.checkout;break"
+ bind $w.name.t <Key-Tab> "focus $w.from.exp.t;break"
+ bind $w.name.t <Key-Return> "do_create_branch_action $w;break"
+ bind $w.name.t <Key> {
+ if {{%K} ne {BackSpace}
+ && {%K} ne {Tab}
+ && {%K} ne {Escape}
+ && {%K} ne {Return}} {
+ if {%k <= 32} break
+ if {[string first %A {~^:?*[}] >= 0} break
+ }
+ }
+ pack $w.name.l -side left -padx 5
+ pack $w.name.t -side left -fill x -expand 1
+ pack $w.name -anchor nw -fill x -pady 5 -padx 5
+
+ labelframe $w.from \
+ -text {Starting Revision} \
+ -font font_ui
+ frame $w.from.head
+ radiobutton $w.from.head.r \
+ -text {Local Branch:} \
+ -value head \
+ -variable create_branch_revtype \
+ -font font_ui
+ eval tk_optionMenu $w.from.head.m create_branch_head $all_heads
+ pack $w.from.head.r -side left
+ pack $w.from.head.m -side left
+ frame $w.from.exp
+ radiobutton $w.from.exp.r \
+ -text {Revision Expression:} \
+ -value expression \
+ -variable create_branch_revtype \
+ -font font_ui
+ text $w.from.exp.t \
+ -height 1 \
+ -width 50 \
+ -font font_ui
+ bind $w.from.exp.t <Shift-Key-Tab> "focus $w.name.t;break"
+ bind $w.from.exp.t <Key-Tab> "focus $w.postActions.checkout;break"
+ bind $w.from.exp.t <Key-Return> "do_create_branch_action $w;break"
+ pack $w.from.exp.r -side left
+ pack $w.from.exp.t -side left -fill x -expand 1
+ pack $w.from.head -padx 5 -fill x -expand 1
+ pack $w.from.exp -padx 5 -fill x -expand 1
+ pack $w.from -anchor nw -fill x -pady 5 -padx 5
+
+ labelframe $w.postActions \
+ -text {Post Creation Actions} \
+ -font font_ui
+ checkbutton $w.postActions.checkout \
+ -text {Checkout after creation} \
+ -offvalue false \
+ -onvalue true \
+ -variable create_branch_checkout \
+ -font font_ui
+ pack $w.postActions.checkout -anchor nw
+ pack $w.postActions -anchor nw -fill x -pady 5 -padx 5
+
+ bind $w <Visibility> "grab $w; focus $w.name.t"
+ bind $w <Key-Escape> "destroy $w"
+ bind $w <Key-Return> "do_create_branch_action $w;break"
+ wm title $w "[appname] ([reponame]): Create Branch"
+ tkwait window $w
+}
+
+proc do_delete_branch_action {w} {
+ global all_heads
+ global delete_branch_checkhead delete_branch_head
+
+ set to_delete [list]
+ set msg {Are you sure you want to delete the following branches?
+
+}
+ foreach i [$w.list.l curselection] {
+ set b [$w.list.l get $i]
+ if {[catch {set o [exec git rev-parse --verify $b]}]} continue
+ if {$delete_branch_checkhead} {
+ if {[catch {set m [exec git merge-base $o $delete_branch_head]}]} continue
+ if {$o ne $m} continue
+ }
+ lappend to_delete [list $b $o]
+ append msg " - $b\n"
+ }
+ if {$to_delete eq {}} {
+ tk_messageBox \
+ -icon info \
+ -type ok \
+ -title [wm title $w] \
+ -parent $w \
+ -message {No branches are able to be deleted.
+
+This is likely because you did not select any branches,
+or all selected branches are not completely merged.
+}
+ return
+ }
+ append msg {
+It can be difficult to recover deleted branches.
+
+Delete the above branches?}
+ if {[tk_messageBox \
+ -icon warning \
+ -type yesno \
+ -title [wm title $w] \
+ -parent $w \
+ -message $msg] ne yes} {
+ return
+ }
+
+ set failed {}
+ foreach i $to_delete {
+ set b [lindex $i 0]
+ set o [lindex $i 1]
+ if {[catch {exec git update-ref -d "refs/heads/$b" $o} err]} {
+ append failed " - $b: $err\n"
+ } else {
+ set x [lsearch -sorted $all_heads $b]
+ if {$x >= 0} {
+ set all_heads [lreplace $all_heads $x $x]
+ }
+ }
+ }
+
+ if {$failed ne {}} {
+ tk_messageBox \
+ -icon error \
+ -type ok \
+ -title [wm title $w] \
+ -parent $w \
+ -message "Failed to delete branches:\n$failed"
+ }
+
+ set all_heads [lsort $all_heads]
+ populate_branch_menu
+ destroy $w
}
proc do_delete_branch {} {
- error "NOT IMPLEMENTED"
+ global all_heads tracking_branches current_branch
+ global delete_branch_checkhead delete_branch_head
+
+ set delete_branch_checkhead 1
+ set delete_branch_head $current_branch
+
+ set w .branch_editor
+ toplevel $w
+ wm geometry $w "+[winfo rootx .]+[winfo rooty .]"
+
+ label $w.header -text {Delete Local Branch} \
+ -font font_uibold
+ pack $w.header -side top -fill x
+
+ frame $w.buttons
+ button $w.buttons.create -text Delete \
+ -font font_ui \
+ -command [list do_delete_branch_action $w]
+ pack $w.buttons.create -side right
+ button $w.buttons.cancel -text {Cancel} \
+ -font font_ui \
+ -command [list destroy $w]
+ pack $w.buttons.cancel -side right -padx 5
+ pack $w.buttons -side bottom -fill x -pady 10 -padx 10
+
+ labelframe $w.list \
+ -text {Local Branches} \
+ -font font_ui
+ listbox $w.list.l \
+ -height 10 \
+ -width 50 \
+ -selectmode extended \
+ -font font_ui
+ foreach h $all_heads {
+ if {$h ne $current_branch} {
+ $w.list.l insert end $h
+ }
+ }
+ pack $w.list.l -fill both -pady 5 -padx 5
+ pack $w.list -fill both -pady 5 -padx 5
+
+ set all_trackings [list]
+ foreach b [array names tracking_branches] {
+ regsub ^refs/(heads|remotes)/ $b {} b
+ lappend all_trackings $b
+ }
+
+ labelframe $w.validate \
+ -text {Only Delete If} \
+ -font font_ui
+ frame $w.validate.head
+ checkbutton $w.validate.head.r \
+ -text {Already Merged Into:} \
+ -variable delete_branch_checkhead \
+ -font font_ui
+ eval tk_optionMenu $w.validate.head.m delete_branch_head \
+ $all_heads \
+ [lsort -unique $all_trackings]
+ pack $w.validate.head.r -side left
+ pack $w.validate.head.m -side left
+ pack $w.validate.head -padx 5 -fill x -expand 1
+ pack $w.validate -anchor nw -fill x -pady 5 -padx 5
+
+ bind $w <Visibility> "grab $w; focus $w"
+ bind $w <Key-Escape> "destroy $w"
+ wm title $w "[appname] ([reponame]): Delete Branch"
+ tkwait window $w
}
proc switch_branch {b} {
set max_status_desc 0
foreach i {
{__ "Unmodified"}
- {_M "Modified"}
- {M_ "Added to commit"}
- {MM "Partially added"}
- {MD "Added (but gone)"}
- {_O "Untracked"}
- {A_ "Added by commit"}
- {AM "Partially added"}
- {AD "Added (but gone)"}
+ {_M "Modified, not staged"}
+ {M_ "Staged for commit"}
+ {MM "Portions staged for commit"}
+ {MD "Staged for commit, missing"}
+
+ {_O "Untracked, not staged"}
+ {A_ "Staged for commit"}
+ {AM "Portions staged for commit"}
+ {AD "Staged for commit, missing"}
{_D "Missing"}
- {DD "Removed by commit"}
- {D_ "Removed by commit"}
- {DO "Removed (still exists)"}
- {DM "Removed (but modified)"}
-
- {UD "Merge conflicts"}
- {UM "Merge conflicts"}
- {U_ "Merge conflicts"}
+ {D_ "Staged for removal"}
+ {DO "Staged for removal, still present"}
+
+ {U_ "Requires merge resolution"}
+ {UM "Requires merge resolution"}
+ {UD "Requires merge resolution"}
} {
if {$max_status_desc < [string length [lindex $i 1]]} {
set max_status_desc [string length [lindex $i 1]]
rescan {set ui_status_value {Ready.}}
}
-proc remove_helper {txt paths} {
+proc unstage_helper {txt paths} {
global file_states current_diff
if {![lock_index begin-update]} return
}
}
-proc do_remove_selection {} {
+proc do_unstage_selection {} {
global current_diff selected_paths
if {[array size selected_paths] > 0} {
- remove_helper \
- {Removing selected files from commit} \
+ unstage_helper \
+ {Unstaging selected files from commit} \
[array names selected_paths]
} elseif {$current_diff ne {}} {
- remove_helper \
- "Removing [short_path $current_diff] from commit" \
+ unstage_helper \
+ "Unstaging [short_path $current_diff] from commit" \
[list $current_diff]
}
}
-proc include_helper {txt paths} {
+proc add_helper {txt paths} {
global file_states current_diff
if {![lock_index begin-update]} return
set after {}
foreach path $paths {
switch -glob -- [lindex $file_states($path) 0] {
- AM -
- AD -
- MM -
- MD -
- U? -
- _M -
- _D -
- _O {
+ _O -
+ ?M -
+ ?D -
+ U? {
lappend pathList $path
if {$path eq $current_diff} {
set after {reshow_diff;}
}
}
-proc do_include_selection {} {
+proc do_add_selection {} {
global current_diff selected_paths
if {[array size selected_paths] > 0} {
- include_helper \
+ add_helper \
{Adding selected files} \
[array names selected_paths]
} elseif {$current_diff ne {}} {
- include_helper \
+ add_helper \
"Adding [short_path $current_diff]" \
[list $current_diff]
}
}
-proc do_include_all {} {
+proc do_add_all {} {
global file_states
set paths [list]
foreach path [array names file_states] {
- switch -- [lindex $file_states($path) 0] {
- AM -
- AD -
- MM -
- MD -
- _M -
- _D {lappend paths $path}
+ switch -glob -- [lindex $file_states($path) 0] {
+ U? {continue}
+ ?M -
+ ?D {lappend paths $path}
}
}
- include_helper \
- {Adding all modified files} \
- $paths
+ add_helper {Adding all changed files} $paths
}
proc revert_helper {txt paths} {
set after {}
foreach path $paths {
switch -glob -- [lindex $file_states($path) 0] {
- AM -
- AD -
- MM -
- MD -
- _M -
- _D {
+ U? {continue}
+ ?M -
+ ?D {
lappend pathList $path
if {$path eq $current_diff} {
set after {reshow_diff;}
button $w.buttons.cancel -text {Cancel} \
-font font_ui \
-command [list destroy $w]
- pack $w.buttons.cancel -side right
+ pack $w.buttons.cancel -side right -padx 5
pack $w.buttons -side bottom -fill x -pady 10 -padx 10
labelframe $w.repo -text "[reponame] Repository" \
} else {
set after {}
}
- switch -glob -- [lindex $file_states($path) 0] {
- A_ -
- M_ -
- DD -
- DO -
- DM {
+ if {$w eq $ui_index} {
update_indexinfo \
- "Removing [short_path $path] from commit" \
+ "Unstaging [short_path $path] from commit" \
[list $path] \
[concat $after {set ui_status_value {Ready.}}]
- }
- ?? {
+ } elseif {$w eq $ui_workdir} {
update_index \
"Adding [short_path $path]" \
[list $path] \
[concat $after {set ui_status_value {Ready.}}]
}
- }
} else {
show_diff $path $w $lno
}
}
proc add_one_to_selection {w x y} {
- global file_lists
- global last_clicked selected_paths
+ global file_lists last_clicked selected_paths
- set pos [split [$w index @$x,$y] .]
- set lno [lindex $pos 0]
- set col [lindex $pos 1]
+ set lno [lindex [split [$w index @$x,$y] .] 0]
set path [lindex $file_lists($w) [expr {$lno - 1}]]
if {$path eq {}} {
set last_clicked {}
return
}
+ if {$last_clicked ne {}
+ && [lindex $last_clicked 0] ne $w} {
+ array unset selected_paths
+ [lindex $last_clicked 0] tag remove in_sel 0.0 end
+ }
+
set last_clicked [list $w $lno]
if {[catch {set in_sel $selected_paths($path)}]} {
set in_sel 0
}
proc add_range_to_selection {w x y} {
- global file_lists
- global last_clicked selected_paths
+ global file_lists last_clicked selected_paths
if {[lindex $last_clicked 0] ne $w} {
toggle_or_diff $w $x $y
return
}
- set pos [split [$w index @$x,$y] .]
- set lno [lindex $pos 0]
+ set lno [lindex [split [$w index @$x,$y] .] 0]
set lc [lindex $last_clicked 1]
if {$lc < $lno} {
set begin $lc
.mbar.branch add command -label {Create...} \
-command do_create_branch \
+ -accelerator $M1T-N \
-font font_ui
lappend disable_on_lock [list .mbar.branch entryconf \
[.mbar.branch index last] -state]
[list .mbar.commit entryconf [.mbar.commit index last] -state]
.mbar.commit add command -label {Add To Commit} \
- -command do_include_selection \
+ -command do_add_selection \
-font font_ui
lappend disable_on_lock \
[list .mbar.commit entryconf [.mbar.commit index last] -state]
.mbar.commit add command -label {Add All To Commit} \
- -command do_include_all \
+ -command do_add_all \
-accelerator $M1T-I \
-font font_ui
lappend disable_on_lock \
[list .mbar.commit entryconf [.mbar.commit index last] -state]
-.mbar.commit add command -label {Remove From Commit} \
- -command do_remove_selection \
+.mbar.commit add command -label {Unstage From Commit} \
+ -command do_unstage_selection \
-font font_ui
lappend disable_on_lock \
[list .mbar.commit entryconf [.mbar.commit index last] -state]
{.vpane.lower.commarea.buttons.rescan conf -state}
button .vpane.lower.commarea.buttons.incall -text {Add All} \
- -command do_include_all \
+ -command do_add_all \
-font font_ui
pack .vpane.lower.commarea.buttons.incall -side top -fill x
lappend disable_on_lock \
# -- Key Bindings
#
bind $ui_comm <$M1B-Key-Return> {do_commit;break}
-bind $ui_comm <$M1B-Key-i> {do_include_all;break}
-bind $ui_comm <$M1B-Key-I> {do_include_all;break}
+bind $ui_comm <$M1B-Key-i> {do_add_all;break}
+bind $ui_comm <$M1B-Key-I> {do_add_all;break}
bind $ui_comm <$M1B-Key-x> {tk_textCut %W;break}
bind $ui_comm <$M1B-Key-X> {tk_textCut %W;break}
bind $ui_comm <$M1B-Key-c> {tk_textCopy %W;break}
bind $ui_diff <Key-Left> {catch {%W xview scroll -1 units};break}
bind $ui_diff <Key-Right> {catch {%W xview scroll 1 units};break}
+if {!$single_commit} {
+ bind . <$M1B-Key-n> do_create_branch
+ bind . <$M1B-Key-N> do_create_branch
+}
+
bind . <Destroy> do_quit
bind all <Key-F5> do_rescan
bind all <$M1B-Key-r> do_rescan
bind all <$M1B-Key-R> do_rescan
bind . <$M1B-Key-s> do_signoff
bind . <$M1B-Key-S> do_signoff
-bind . <$M1B-Key-i> do_include_all
-bind . <$M1B-Key-I> do_include_all
+bind . <$M1B-Key-i> do_add_all
+bind . <$M1B-Key-I> do_add_all
bind . <$M1B-Key-Return> do_commit
bind all <$M1B-Key-q> do_quit
bind all <$M1B-Key-Q> do_quit
load_all_remotes
load_all_heads
- populate_branch_menu .mbar.branch
+ populate_branch_menu
populate_fetch_menu .mbar.fetch
populate_pull_menu .mbar.pull
populate_push_menu .mbar.push