aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShawn O. Pearce <spearce@spearce.org>2007-05-28 12:52:57 -0400
committerShawn O. Pearce <spearce@spearce.org>2007-05-28 17:50:42 -0400
commit61f82ce79abe965c466bb7d3d1d89ae631fbbd24 (patch)
treef8aee7d20c68b5df4464b6b1ae981b513ee55f64
parentf60fdd0eaaaf92882f3e6aeb19bb85482fab6d39 (diff)
downloadgit-61f82ce79abe965c466bb7d3d1d89ae631fbbd24.tar.gz
git-61f82ce79abe965c466bb7d3d1d89ae631fbbd24.tar.xz
git-gui: Allow users to rename branches through 'branch -m'
Git's native command line interface has had branch renaming support for quite a while, through the -m/-M options to the git-branch command line tool. This is an extremely useful feature as users may decide that the name of their current branch is not an adequate description, or was just entered incorrectly when it was created. Even though most people would consider git-branch to be a Porcelain tool I'm using it here in git-gui as it is the only code that implements the rather complex set of logic needed to successfully rename a branch in Git. Currently that is along the lines of: *) Backup the ref *) Backup the reflog *) Delete the old ref *) Create the new ref *) Move the backed up reflog to the new ref *) Record the rename event in the reflog *) If the current branch was renamed, update HEAD *) If HEAD changed, record the rename event in the HEAD reflog *) Rename the [branch "$name"] section in the config file Since that is some rather ugly set of functionality to implement and get right, and some of it isn't easily accessible through the raw plumbing layer I'm just cheating by relying on the Porcelain. Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
-rwxr-xr-xgit-gui.sh14
-rw-r--r--lib/branch_rename.tcl137
2 files changed, 151 insertions, 0 deletions
diff --git a/git-gui.sh b/git-gui.sh
index d640b143f..755f0643b 100755
--- a/git-gui.sh
+++ b/git-gui.sh
@@ -200,6 +200,15 @@ proc is_config_true {name} {
}
}
+proc get_config {name} {
+ global repo_config
+ if {[catch {set v $repo_config($name)}]} {
+ return {}
+ } else {
+ return $v
+ }
+}
+
proc load_config {include_global} {
global repo_config global_config default_config
@@ -1420,6 +1429,11 @@ if {[is_enabled branch]} {
lappend disable_on_lock [list .mbar.branch entryconf \
[.mbar.branch index last] -state]
+ .mbar.branch add command -label {Rename...} \
+ -command branch_rename::dialog
+ lappend disable_on_lock [list .mbar.branch entryconf \
+ [.mbar.branch index last] -state]
+
.mbar.branch add command -label {Delete...} \
-command do_delete_branch
lappend disable_on_lock [list .mbar.branch entryconf \
diff --git a/lib/branch_rename.tcl b/lib/branch_rename.tcl
new file mode 100644
index 000000000..54c72b980
--- /dev/null
+++ b/lib/branch_rename.tcl
@@ -0,0 +1,137 @@
+# git-gui branch rename support
+# Copyright (C) 2007 Shawn Pearce
+
+class branch_rename {
+
+field w
+field oldname
+field newname
+
+constructor dialog {} {
+ global all_heads current_branch
+
+ make_toplevel top w
+ wm title $top "[appname] ([reponame]): Rename Branch"
+ if {$top ne {.}} {
+ wm geometry $top "+[winfo rootx .]+[winfo rooty .]"
+ }
+
+ set oldname $current_branch
+ set newname [get_config gui.newbranchtemplate]
+
+ label $w.header -text {Rename Branch} -font font_uibold
+ pack $w.header -side top -fill x
+
+ frame $w.buttons
+ button $w.buttons.rename -text Rename \
+ -default active \
+ -command [cb _rename]
+ pack $w.buttons.rename -side right
+ button $w.buttons.cancel -text {Cancel} \
+ -command [list destroy $w]
+ pack $w.buttons.cancel -side right -padx 5
+ pack $w.buttons -side bottom -fill x -pady 10 -padx 10
+
+ frame $w.rename
+ label $w.rename.oldname_l -text {Branch:}
+ eval tk_optionMenu $w.rename.oldname_m @oldname $all_heads
+
+ label $w.rename.newname_l -text {New Name:}
+ entry $w.rename.newname_t \
+ -borderwidth 1 \
+ -relief sunken \
+ -width 40 \
+ -textvariable @newname \
+ -validate key \
+ -validatecommand {
+ if {%d == 1 && [regexp {[~^:?*\[\0- ]} %S]} {return 0}
+ return 1
+ }
+
+ grid $w.rename.oldname_l $w.rename.oldname_m -sticky w -padx {0 5}
+ grid $w.rename.newname_l $w.rename.newname_t -sticky we -padx {0 5}
+ grid columnconfigure $w.rename 1 -weight 1
+ pack $w.rename -anchor nw -fill x -pady 5 -padx 5
+
+ bind $w <Key-Return> [cb _rename]
+ bind $w <Key-Escape> [list destroy $w]
+ bind $w <Visibility> "
+ grab $w
+ $w.rename.newname_t icursor end
+ focus $w.rename.newname_t
+ "
+ bind $w.header <Destroy> [list delete_this $this]
+ tkwait window $w
+}
+
+method _rename {} {
+ global all_heads current_branch
+
+ if {$oldname eq {}} {
+ tk_messageBox \
+ -icon error \
+ -type ok \
+ -title [wm title $w] \
+ -parent $w \
+ -message "Please select a branch to rename."
+ focus $w.rename.oldname_m
+ return
+ }
+ if {$newname eq {}
+ || $newname eq [get_config gui.newbranchtemplate]} {
+ tk_messageBox \
+ -icon error \
+ -type ok \
+ -title [wm title $w] \
+ -parent $w \
+ -message "Please supply a branch name."
+ focus $w.rename.newname_t
+ return
+ }
+ if {![catch {git show-ref --verify -- "refs/heads/$newname"}]} {
+ tk_messageBox \
+ -icon error \
+ -type ok \
+ -title [wm title $w] \
+ -parent $w \
+ -message "Branch '$newname' already exists."
+ focus $w.rename.newname_t
+ return
+ }
+ if {[catch {git check-ref-format "heads/$newname"}]} {
+ tk_messageBox \
+ -icon error \
+ -type ok \
+ -title [wm title $w] \
+ -parent $w \
+ -message "We do not like '$newname' as a branch name."
+ focus $w.rename.newname_t
+ return
+ }
+
+ if {[catch {git branch -m $oldname $newname} err]} {
+ tk_messageBox \
+ -icon error \
+ -type ok \
+ -title [wm title $w] \
+ -parent $w \
+ -message "Failed to rename '$oldname'.\n\n$err"
+ return
+ }
+
+ set oldidx [lsearch -exact -sorted $all_heads $oldname]
+ if {$oldidx >= 0} {
+ set all_heads [lreplace $all_heads $oldidx $oldidx]
+ }
+ lappend all_heads $newname
+ set all_heads [lsort $all_heads]
+ populate_branch_menu
+
+ if {$current_branch eq $oldname} {
+ set current_branch $newname
+ }
+
+ destroy $w
+}
+
+}