git-gui: Verify we should actually perform a commit when asked to do so.
authorShawn O. Pearce <spearce@spearce.org>
Tue, 7 Nov 2006 01:03:36 +0000 (20:03 -0500)
committerShawn O. Pearce <spearce@spearce.org>
Tue, 7 Nov 2006 08:05:16 +0000 (03:05 -0500)
A user shouldn't perform a commit if any of the following are true:

* The repository state has changed since the last rescan.
* There are no files updated in the index to commit.
* There are unmerged stages still in the index.
* The commit message has not been provided.
* The pre-commit hook is executable and declined.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
git-gui
diff --git a/git-gui b/git-gui
index 168062e67b54b5e3dbb57f282e2f68d303368909..0b941c3ffb8a320e0e8c86413d7a3463d71c51ba 100755 (executable)
--- a/git-gui
+++ b/git-gui
@@ -599,15 +599,62 @@ proc error_popup {msg} {
 }
 
 proc show_msg {w top msg} {
-       message $w.m -text $msg -justify center -aspect 400
+       global gitdir
+
+       message $w.m -text $msg -justify left -aspect 400
        pack $w.m -side top -fill x -padx 20 -pady 20
        button $w.ok -text OK -command "destroy $top"
-       pack $w.ok -side bottom -fill x
+       pack $w.ok -side bottom
        bind $top <Visibility> "grab $top; focus $top"
        bind $top <Key-Return> "destroy $top"
+       wm title $top "error: git-ui ([file normalize [file dirname $gitdir]])"
        tkwait window $top
 }
 
+proc hook_failed_popup {hook msg} {
+       global gitdir mainfont difffont
+
+       set w .hookfail
+       toplevel $w
+       wm transient $w .
+
+       frame $w.m
+       label $w.m.l1 -text "$hook hook failed:" \
+               -anchor w \
+               -justify left \
+               -font [concat $mainfont bold]
+       text $w.m.t \
+               -background white -borderwidth 1 \
+               -relief sunken \
+               -width 80 -height 10 \
+               -font $difffont \
+               -yscrollcommand [list $w.m.sby set]
+       label $w.m.l2 \
+               -text {You must correct the above errors before committing.} \
+               -anchor w \
+               -justify left \
+               -font [concat $mainfont bold]
+       scrollbar $w.m.sby -command [list $w.m.t yview]
+       pack $w.m.l1 -side top -fill x
+       pack $w.m.l2 -side bottom -fill x
+       pack $w.m.sby -side right -fill y
+       pack $w.m.t -side left -fill both -expand 1
+       pack $w.m -side top -fill both -expand 1 -padx 5 -pady 10
+
+       $w.m.t insert 1.0 $msg
+       $w.m.t conf -state disabled
+
+       button $w.ok -text OK \
+               -width 15 \
+               -command "destroy $w"
+       pack $w.ok -side bottom
+
+       bind $w <Visibility> "grab $w; focus $w"
+       bind $w <Key-Return> "destroy $w"
+       wm title $w "error: git-ui ([file normalize [file dirname $gitdir]])"
+       tkwait window $w
+}
+
 ######################################################################
 ##
 ## ui commands
@@ -693,6 +740,94 @@ proc do_signoff {} {
        }
 }
 
+proc do_commit {} {
+       global tcl_platform HEAD gitdir commit_type file_states
+       global ui_comm
+
+       # -- Our in memory state should match the repository.
+       #
+       if {[catch {set curHEAD [exec git rev-parse --verify HEAD]}]} {
+               set cur_type initial
+       } else {
+               set cur_type normal
+       }
+       if {$commit_type != $commit_type || $HEAD != $curHEAD} {
+               error_popup {Last scanned state does not match repository state.
+
+Its highly likely that another Git program modified the
+repository since our last scan.  A rescan is required
+before committing.
+}
+               update_status
+               return
+       }
+
+       # -- At least one file should differ in the index.
+       #
+       set files_ready 0
+       foreach path [array names file_states] {
+               set s $file_states($path)
+               switch -glob -- [lindex $s 0] {
+               _* {continue}
+               A* -
+               D* -
+               M* {set files_ready 1; break}
+               U* {
+                       error_popup "Unmerged files cannot be committed.
+
+File $path has merge conflicts.
+You must resolve them and check the file in before committing.
+"
+                       return
+               }
+               default {
+                       error_popup "Unknown file state [lindex $s 0] detected.
+
+File $path cannot be committed by this program.
+"
+               }
+               }
+       }
+       if {!$files_ready} {
+               error_popup {No checked-in files to commit.
+
+You must check-in at least 1 file before you can commit.
+}
+               return
+       }
+
+       # -- A message is required.
+       #
+       set msg [string trim [$ui_comm get 1.0 end]]
+       if {$msg == {}} {
+               error_popup {Please supply a commit message.
+
+A good commit message has the following format:
+
+- First line: Describe in one sentance what you did.
+- Second line: Blank
+- Remaining lines: Describe why this change is good.
+}
+               return
+       }
+
+       # -- Ask the pre-commit hook for the go-ahead.
+       #
+       set pchook [file join $gitdir hooks pre-commit]
+       if {$tcl_platform(platform) == {windows} && [file exists $pchook]} {
+               set pchook [list sh -c \
+                       "if test -x \"$pchook\"; then exec \"$pchook\"; fi"]
+       } elseif {[file executable $pchook]} {
+               set pchook [list $pchook]
+       } else {
+               set pchook {}
+       }
+       if {$pchook != {} && [catch {eval exec $pchook} err]} {
+               hook_failed_popup pre-commit $err
+               return
+       }
+}
+
 # shift == 1: left click
 #          3: right click  
 proc click {w x y shift wx wy} {