Merge commit 'git-gui/master'
* commit 'git-gui/master': (36 commits) git-gui: Change prior tree SHA-1 verification to use git_read git-gui: Include a space in Cygwin shortcut command lines git-gui: Use sh.exe in Cygwin shortcuts git-gui: Paper bag fix for Cygwin shortcut creation git-gui: Improve the Windows and Mac OS X shortcut creators git-gui: Teach console widget to use git_read git-gui: Perform our own magic shbang detection on Windows git-gui: Treat `git version` as `git --version` git-gui: Assume unfound commands are known by git wrapper git-gui: Correct gitk installation location git-gui: Always use absolute path to all git executables git-gui: Show a progress meter for checking out files git-gui: Change the main window progress bar to use status_bar git-gui: Extract blame viewer status bar into mega-widget git-gui: Allow double-click in checkout dialog to start checkout git-gui: Default selection to first matching ref git-gui: Unabbreviate commit SHA-1s prior to display git-gui: Refactor branch switch to support detached head git-gui: Refactor our ui_status_value update technique git-gui: Better handling of detached HEAD ...
This commit is contained in:
@ -2,573 +2,37 @@
|
||||
# Copyright (C) 2006, 2007 Shawn Pearce
|
||||
|
||||
proc load_all_heads {} {
|
||||
global all_heads
|
||||
global some_heads_tracking
|
||||
|
||||
set rh refs/heads
|
||||
set rh_len [expr {[string length $rh] + 1}]
|
||||
set all_heads [list]
|
||||
set fd [open "| git for-each-ref --format=%(refname) refs/heads" r]
|
||||
set fd [git_read for-each-ref --format=%(refname) $rh]
|
||||
while {[gets $fd line] > 0} {
|
||||
if {[is_tracking_branch $line]} continue
|
||||
if {![regsub ^refs/heads/ $line {} name]} continue
|
||||
lappend all_heads $name
|
||||
if {!$some_heads_tracking || ![is_tracking_branch $line]} {
|
||||
lappend all_heads [string range $line $rh_len end]
|
||||
}
|
||||
}
|
||||
close $fd
|
||||
|
||||
set all_heads [lsort $all_heads]
|
||||
return [lsort $all_heads]
|
||||
}
|
||||
|
||||
proc load_all_tags {} {
|
||||
set all_tags [list]
|
||||
set fd [open "| git for-each-ref --format=%(refname) refs/tags" r]
|
||||
set fd [git_read for-each-ref \
|
||||
--sort=-taggerdate \
|
||||
--format=%(refname) \
|
||||
refs/tags]
|
||||
while {[gets $fd line] > 0} {
|
||||
if {![regsub ^refs/tags/ $line {} name]} continue
|
||||
lappend all_tags $name
|
||||
}
|
||||
close $fd
|
||||
|
||||
return [lsort $all_tags]
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
if {$all_heads ne {}} {
|
||||
$m add separator
|
||||
}
|
||||
foreach b $all_heads {
|
||||
$m add radiobutton \
|
||||
-label $b \
|
||||
-command [list switch_branch $b] \
|
||||
-variable current_branch \
|
||||
-value $b
|
||||
lappend disable_on_lock \
|
||||
[list $m entryconf [$m index last] -state]
|
||||
}
|
||||
}
|
||||
|
||||
proc do_create_branch_action {w} {
|
||||
global all_heads null_sha1 repo_config
|
||||
global create_branch_checkout create_branch_revtype
|
||||
global create_branch_head create_branch_trackinghead
|
||||
global create_branch_name create_branch_revexp
|
||||
global create_branch_tag
|
||||
|
||||
set newbranch $create_branch_name
|
||||
if {$newbranch eq {}
|
||||
|| $newbranch eq $repo_config(gui.newbranchtemplate)} {
|
||||
tk_messageBox \
|
||||
-icon error \
|
||||
-type ok \
|
||||
-title [wm title $w] \
|
||||
-parent $w \
|
||||
-message "Please supply a branch name."
|
||||
focus $w.desc.name_t
|
||||
return
|
||||
}
|
||||
if {![catch {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.desc.name_t
|
||||
return
|
||||
}
|
||||
if {[catch {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.desc.name_t
|
||||
return
|
||||
}
|
||||
|
||||
set rev {}
|
||||
switch -- $create_branch_revtype {
|
||||
head {set rev $create_branch_head}
|
||||
tracking {set rev $create_branch_trackinghead}
|
||||
tag {set rev $create_branch_tag}
|
||||
expression {set rev $create_branch_revexp}
|
||||
}
|
||||
if {[catch {set cmt [git rev-parse --verify "${rev}^0"]}]} {
|
||||
tk_messageBox \
|
||||
-icon error \
|
||||
-type ok \
|
||||
-title [wm title $w] \
|
||||
-parent $w \
|
||||
-message "Invalid starting revision: $rev"
|
||||
return
|
||||
}
|
||||
if {[catch {
|
||||
git update-ref \
|
||||
-m "branch: Created from $rev" \
|
||||
"refs/heads/$newbranch" \
|
||||
$cmt \
|
||||
$null_sha1
|
||||
} 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
|
||||
if {$create_branch_checkout} {
|
||||
switch_branch $newbranch
|
||||
}
|
||||
return $all_tags
|
||||
}
|
||||
|
||||
proc radio_selector {varname value args} {
|
||||
upvar #0 $varname var
|
||||
set var $value
|
||||
}
|
||||
|
||||
trace add variable create_branch_head write \
|
||||
[list radio_selector create_branch_revtype head]
|
||||
trace add variable create_branch_trackinghead write \
|
||||
[list radio_selector create_branch_revtype tracking]
|
||||
trace add variable create_branch_tag write \
|
||||
[list radio_selector create_branch_revtype tag]
|
||||
|
||||
trace add variable delete_branch_head write \
|
||||
[list radio_selector delete_branch_checktype head]
|
||||
trace add variable delete_branch_trackinghead write \
|
||||
[list radio_selector delete_branch_checktype tracking]
|
||||
|
||||
proc do_create_branch {} {
|
||||
global all_heads current_branch repo_config
|
||||
global create_branch_checkout create_branch_revtype
|
||||
global create_branch_head create_branch_trackinghead
|
||||
global create_branch_name create_branch_revexp
|
||||
global create_branch_tag
|
||||
|
||||
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 \
|
||||
-default active \
|
||||
-command [list do_create_branch_action $w]
|
||||
pack $w.buttons.create -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
|
||||
|
||||
labelframe $w.desc -text {Branch Description}
|
||||
label $w.desc.name_l -text {Name:}
|
||||
entry $w.desc.name_t \
|
||||
-borderwidth 1 \
|
||||
-relief sunken \
|
||||
-width 40 \
|
||||
-textvariable create_branch_name \
|
||||
-validate key \
|
||||
-validatecommand {
|
||||
if {%d == 1 && [regexp {[~^:?*\[\0- ]} %S]} {return 0}
|
||||
return 1
|
||||
}
|
||||
grid $w.desc.name_l $w.desc.name_t -sticky we -padx {0 5}
|
||||
grid columnconfigure $w.desc 1 -weight 1
|
||||
pack $w.desc -anchor nw -fill x -pady 5 -padx 5
|
||||
|
||||
labelframe $w.from -text {Starting Revision}
|
||||
if {$all_heads ne {}} {
|
||||
radiobutton $w.from.head_r \
|
||||
-text {Local Branch:} \
|
||||
-value head \
|
||||
-variable create_branch_revtype
|
||||
eval tk_optionMenu $w.from.head_m create_branch_head $all_heads
|
||||
grid $w.from.head_r $w.from.head_m -sticky w
|
||||
}
|
||||
set all_trackings [all_tracking_branches]
|
||||
if {$all_trackings ne {}} {
|
||||
set create_branch_trackinghead [lindex $all_trackings 0]
|
||||
radiobutton $w.from.tracking_r \
|
||||
-text {Tracking Branch:} \
|
||||
-value tracking \
|
||||
-variable create_branch_revtype
|
||||
eval tk_optionMenu $w.from.tracking_m \
|
||||
create_branch_trackinghead \
|
||||
$all_trackings
|
||||
grid $w.from.tracking_r $w.from.tracking_m -sticky w
|
||||
}
|
||||
set all_tags [load_all_tags]
|
||||
if {$all_tags ne {}} {
|
||||
set create_branch_tag [lindex $all_tags 0]
|
||||
radiobutton $w.from.tag_r \
|
||||
-text {Tag:} \
|
||||
-value tag \
|
||||
-variable create_branch_revtype
|
||||
eval tk_optionMenu $w.from.tag_m create_branch_tag $all_tags
|
||||
grid $w.from.tag_r $w.from.tag_m -sticky w
|
||||
}
|
||||
radiobutton $w.from.exp_r \
|
||||
-text {Revision Expression:} \
|
||||
-value expression \
|
||||
-variable create_branch_revtype
|
||||
entry $w.from.exp_t \
|
||||
-borderwidth 1 \
|
||||
-relief sunken \
|
||||
-width 50 \
|
||||
-textvariable create_branch_revexp \
|
||||
-validate key \
|
||||
-validatecommand {
|
||||
if {%d == 1 && [regexp {\s} %S]} {return 0}
|
||||
if {%d == 1 && [string length %S] > 0} {
|
||||
set create_branch_revtype expression
|
||||
}
|
||||
return 1
|
||||
}
|
||||
grid $w.from.exp_r $w.from.exp_t -sticky we -padx {0 5}
|
||||
grid columnconfigure $w.from 1 -weight 1
|
||||
pack $w.from -anchor nw -fill x -pady 5 -padx 5
|
||||
|
||||
labelframe $w.postActions -text {Post Creation Actions}
|
||||
checkbutton $w.postActions.checkout \
|
||||
-text {Checkout after creation} \
|
||||
-variable create_branch_checkout
|
||||
pack $w.postActions.checkout -anchor nw
|
||||
pack $w.postActions -anchor nw -fill x -pady 5 -padx 5
|
||||
|
||||
set create_branch_checkout 1
|
||||
set create_branch_head $current_branch
|
||||
set create_branch_revtype head
|
||||
set create_branch_name $repo_config(gui.newbranchtemplate)
|
||||
set create_branch_revexp {}
|
||||
|
||||
bind $w <Visibility> "
|
||||
grab $w
|
||||
$w.desc.name_t icursor end
|
||||
focus $w.desc.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_checktype delete_branch_head delete_branch_trackinghead
|
||||
|
||||
set check_rev {}
|
||||
switch -- $delete_branch_checktype {
|
||||
head {set check_rev $delete_branch_head}
|
||||
tracking {set check_rev $delete_branch_trackinghead}
|
||||
always {set check_rev {:none}}
|
||||
}
|
||||
if {$check_rev eq {:none}} {
|
||||
set check_cmt {}
|
||||
} elseif {[catch {set check_cmt [git rev-parse --verify "${check_rev}^0"]}]} {
|
||||
tk_messageBox \
|
||||
-icon error \
|
||||
-type ok \
|
||||
-title [wm title $w] \
|
||||
-parent $w \
|
||||
-message "Invalid check revision: $check_rev"
|
||||
return
|
||||
}
|
||||
|
||||
set to_delete [list]
|
||||
set not_merged [list]
|
||||
foreach i [$w.list.l curselection] {
|
||||
set b [$w.list.l get $i]
|
||||
if {[catch {set o [git rev-parse --verify $b]}]} continue
|
||||
if {$check_cmt ne {}} {
|
||||
if {$b eq $check_rev} continue
|
||||
if {[catch {set m [git merge-base $o $check_cmt]}]} continue
|
||||
if {$o ne $m} {
|
||||
lappend not_merged $b
|
||||
continue
|
||||
}
|
||||
}
|
||||
lappend to_delete [list $b $o]
|
||||
}
|
||||
if {$not_merged ne {}} {
|
||||
set msg "The following branches are not completely merged into $check_rev:
|
||||
|
||||
- [join $not_merged "\n - "]"
|
||||
tk_messageBox \
|
||||
-icon info \
|
||||
-type ok \
|
||||
-title [wm title $w] \
|
||||
-parent $w \
|
||||
-message $msg
|
||||
}
|
||||
if {$to_delete eq {}} return
|
||||
if {$delete_branch_checktype eq {always}} {
|
||||
set msg {Recovering deleted branches is difficult.
|
||||
|
||||
Delete the selected 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 {git update-ref -d "refs/heads/$b" $o} err]} {
|
||||
append failed " - $b: $err\n"
|
||||
} else {
|
||||
set x [lsearch -sorted -exact $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 {} {
|
||||
global all_heads tracking_branches current_branch
|
||||
global delete_branch_checktype delete_branch_head delete_branch_trackinghead
|
||||
|
||||
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 \
|
||||
-command [list do_delete_branch_action $w]
|
||||
pack $w.buttons.create -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
|
||||
|
||||
labelframe $w.list -text {Local Branches}
|
||||
listbox $w.list.l \
|
||||
-height 10 \
|
||||
-width 70 \
|
||||
-selectmode extended \
|
||||
-yscrollcommand [list $w.list.sby set]
|
||||
foreach h $all_heads {
|
||||
if {$h ne $current_branch} {
|
||||
$w.list.l insert end $h
|
||||
}
|
||||
}
|
||||
scrollbar $w.list.sby -command [list $w.list.l yview]
|
||||
pack $w.list.sby -side right -fill y
|
||||
pack $w.list.l -side left -fill both -expand 1
|
||||
pack $w.list -fill both -expand 1 -pady 5 -padx 5
|
||||
|
||||
labelframe $w.validate -text {Delete Only If}
|
||||
radiobutton $w.validate.head_r \
|
||||
-text {Merged Into Local Branch:} \
|
||||
-value head \
|
||||
-variable delete_branch_checktype
|
||||
eval tk_optionMenu $w.validate.head_m delete_branch_head $all_heads
|
||||
grid $w.validate.head_r $w.validate.head_m -sticky w
|
||||
set all_trackings [all_tracking_branches]
|
||||
if {$all_trackings ne {}} {
|
||||
set delete_branch_trackinghead [lindex $all_trackings 0]
|
||||
radiobutton $w.validate.tracking_r \
|
||||
-text {Merged Into Tracking Branch:} \
|
||||
-value tracking \
|
||||
-variable delete_branch_checktype
|
||||
eval tk_optionMenu $w.validate.tracking_m \
|
||||
delete_branch_trackinghead \
|
||||
$all_trackings
|
||||
grid $w.validate.tracking_r $w.validate.tracking_m -sticky w
|
||||
}
|
||||
radiobutton $w.validate.always_r \
|
||||
-text {Always (Do not perform merge checks)} \
|
||||
-value always \
|
||||
-variable delete_branch_checktype
|
||||
grid $w.validate.always_r -columnspan 2 -sticky w
|
||||
grid columnconfigure $w.validate 1 -weight 1
|
||||
pack $w.validate -anchor nw -fill x -pady 5 -padx 5
|
||||
|
||||
set delete_branch_head $current_branch
|
||||
set delete_branch_checktype head
|
||||
|
||||
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 {new_branch} {
|
||||
global HEAD commit_type current_branch repo_config
|
||||
|
||||
if {![lock_index switch]} return
|
||||
|
||||
# -- Our in memory state should match the repository.
|
||||
#
|
||||
repository_state curType curHEAD curMERGE_HEAD
|
||||
if {[string match amend* $commit_type]
|
||||
&& $curType eq {normal}
|
||||
&& $curHEAD eq $HEAD} {
|
||||
} elseif {$commit_type ne $curType || $HEAD ne $curHEAD} {
|
||||
info_popup {Last scanned state does not match repository state.
|
||||
|
||||
Another Git program has modified this repository since the last scan. A rescan must be performed before the current branch can be changed.
|
||||
|
||||
The rescan will be automatically started now.
|
||||
}
|
||||
unlock_index
|
||||
rescan {set ui_status_value {Ready.}}
|
||||
return
|
||||
}
|
||||
|
||||
# -- Don't do a pointless switch.
|
||||
#
|
||||
if {$current_branch eq $new_branch} {
|
||||
unlock_index
|
||||
return
|
||||
}
|
||||
|
||||
if {$repo_config(gui.trustmtime) eq {true}} {
|
||||
switch_branch_stage2 {} $new_branch
|
||||
} else {
|
||||
set ui_status_value {Refreshing file status...}
|
||||
set cmd [list git update-index]
|
||||
lappend cmd -q
|
||||
lappend cmd --unmerged
|
||||
lappend cmd --ignore-missing
|
||||
lappend cmd --refresh
|
||||
set fd_rf [open "| $cmd" r]
|
||||
fconfigure $fd_rf -blocking 0 -translation binary
|
||||
fileevent $fd_rf readable \
|
||||
[list switch_branch_stage2 $fd_rf $new_branch]
|
||||
}
|
||||
}
|
||||
|
||||
proc switch_branch_stage2 {fd_rf new_branch} {
|
||||
global ui_status_value HEAD
|
||||
|
||||
if {$fd_rf ne {}} {
|
||||
read $fd_rf
|
||||
if {![eof $fd_rf]} return
|
||||
close $fd_rf
|
||||
}
|
||||
|
||||
set ui_status_value "Updating working directory to '$new_branch'..."
|
||||
set cmd [list git read-tree]
|
||||
lappend cmd -m
|
||||
lappend cmd -u
|
||||
lappend cmd --exclude-per-directory=.gitignore
|
||||
lappend cmd $HEAD
|
||||
lappend cmd $new_branch
|
||||
set fd_rt [open "| $cmd" r]
|
||||
fconfigure $fd_rt -blocking 0 -translation binary
|
||||
fileevent $fd_rt readable \
|
||||
[list switch_branch_readtree_wait $fd_rt $new_branch]
|
||||
}
|
||||
|
||||
proc switch_branch_readtree_wait {fd_rt new_branch} {
|
||||
global selected_commit_type commit_type HEAD MERGE_HEAD PARENT
|
||||
global current_branch
|
||||
global ui_comm ui_status_value
|
||||
|
||||
# -- We never get interesting output on stdout; only stderr.
|
||||
#
|
||||
read $fd_rt
|
||||
fconfigure $fd_rt -blocking 1
|
||||
if {![eof $fd_rt]} {
|
||||
fconfigure $fd_rt -blocking 0
|
||||
return
|
||||
}
|
||||
|
||||
# -- The working directory wasn't in sync with the index and
|
||||
# we'd have to overwrite something to make the switch. A
|
||||
# merge is required.
|
||||
#
|
||||
if {[catch {close $fd_rt} err]} {
|
||||
regsub {^fatal: } $err {} err
|
||||
warn_popup "File level merge required.
|
||||
|
||||
$err
|
||||
|
||||
Staying on branch '$current_branch'."
|
||||
set ui_status_value "Aborted checkout of '$new_branch' (file level merging is required)."
|
||||
unlock_index
|
||||
return
|
||||
}
|
||||
|
||||
# -- Update the symbolic ref. Core git doesn't even check for failure
|
||||
# here, it Just Works(tm). If it doesn't we are in some really ugly
|
||||
# state that is difficult to recover from within git-gui.
|
||||
#
|
||||
if {[catch {git symbolic-ref HEAD "refs/heads/$new_branch"} err]} {
|
||||
error_popup "Failed to set current branch.
|
||||
|
||||
This working directory is only partially switched. We successfully updated your files, but failed to update an internal Git file.
|
||||
|
||||
This should not have occurred. [appname] will now close and give up.
|
||||
|
||||
$err"
|
||||
do_quit
|
||||
return
|
||||
}
|
||||
|
||||
# -- Update our repository state. If we were previously in amend mode
|
||||
# we need to toss the current buffer and do a full rescan to update
|
||||
# our file lists. If we weren't in amend mode our file lists are
|
||||
# accurate and we can avoid the rescan.
|
||||
#
|
||||
unlock_index
|
||||
set selected_commit_type new
|
||||
if {[string match amend* $commit_type]} {
|
||||
$ui_comm delete 0.0 end
|
||||
$ui_comm edit reset
|
||||
$ui_comm edit modified false
|
||||
rescan {set ui_status_value "Checked out branch '$current_branch'."}
|
||||
} else {
|
||||
repository_state commit_type HEAD MERGE_HEAD
|
||||
set PARENT $HEAD
|
||||
set ui_status_value "Checked out branch '$current_branch'."
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user