summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/git-diff.txt7
-rw-r--r--Makefile5
-rw-r--r--builtin-add.c2
-rw-r--r--builtin-diff.c1
-rwxr-xr-xgit-gui/git-gui.sh447
-rw-r--r--git-gui/lib/blame.tcl25
-rw-r--r--git-gui/lib/browser.tcl85
-rw-r--r--git-gui/lib/checkout_op.tcl101
-rw-r--r--git-gui/lib/choose_rev.tcl274
-rw-r--r--git-gui/lib/commit.tcl30
-rw-r--r--git-gui/lib/database.tcl27
-rw-r--r--git-gui/lib/diff.tcl1
-rw-r--r--git-gui/lib/encoding.tcl276
-rw-r--r--git-gui/lib/error.tcl7
-rw-r--r--git-gui/lib/index.tcl2
-rw-r--r--git-gui/lib/merge.tcl279
-rw-r--r--git-gui/lib/remote.tcl6
-rwxr-xr-xgit-rebase--interactive.sh4
-rwxr-xr-xgit-stash.sh39
-rwxr-xr-xgitk362
-rwxr-xr-xgitweb/gitweb.perl63
-rwxr-xr-xt/t3404-rebase-interactive.sh30
-rwxr-xr-xt/t9300-fast-import.sh2
-rwxr-xr-xt/t9500-gitweb-standalone-no-errors.sh28
24 files changed, 1518 insertions, 585 deletions
diff --git a/Documentation/git-diff.txt b/Documentation/git-diff.txt
index 639b969..b1f5e7f 100644
--- a/Documentation/git-diff.txt
+++ b/Documentation/git-diff.txt
@@ -102,17 +102,14 @@ Limiting the diff output::
+
------------
$ git diff --diff-filter=MRC <1>
-$ git diff --name-status -r <2>
+$ git diff --name-status <2>
$ git diff arch/i386 include/asm-i386 <3>
------------
+
<1> show only modification, rename and copy, but not addition
nor deletion.
<2> show only names and the nature of change, but not actual
-diff output. --name-status disables usual patch generation
-which in turn also disables recursive behavior, so without -r
-you would only see the directory name if there is a change in a
-file in a subdirectory.
+diff output.
<3> limit diff output to named subtrees.
Munging the diff output::
diff --git a/Makefile b/Makefile
index 73b487f..c58a4c2 100644
--- a/Makefile
+++ b/Makefile
@@ -176,6 +176,7 @@ CC = gcc
AR = ar
RM = rm -f
TAR = tar
+FIND = find
INSTALL = install
RPMBUILD = rpmbuild
TCL_PATH = tclsh
@@ -903,11 +904,11 @@ doc:
TAGS:
$(RM) TAGS
- find . -name '*.[hcS]' -print | xargs etags -a
+ $(FIND) . -name '*.[hcS]' -print | xargs etags -a
tags:
$(RM) tags
- find . -name '*.[hcS]' -print | xargs ctags -a
+ $(FIND) . -name '*.[hcS]' -print | xargs ctags -a
### Detect prefix changes
TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\
diff --git a/builtin-add.c b/builtin-add.c
index 7345479..de5c108 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -60,7 +60,7 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec,
path = git_path("info/exclude");
if (!access(path, R_OK))
add_excludes_from_file(dir, path);
- if (!access(excludes_file, R_OK))
+ if (excludes_file != NULL && !access(excludes_file, R_OK))
add_excludes_from_file(dir, excludes_file);
}
diff --git a/builtin-diff.c b/builtin-diff.c
index 7f367b6..b48121e 100644
--- a/builtin-diff.c
+++ b/builtin-diff.c
@@ -233,6 +233,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
die("diff_setup_done failed");
}
rev.diffopt.allow_external = 1;
+ rev.diffopt.recursive = 1;
/* Do we have --cached and not have a pending object, then
* default to HEAD by hand. Eek.
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 2077261..671b887 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -154,12 +154,10 @@ proc gitexec {args} {
}
proc reponame {} {
- global _reponame
- return $_reponame
+ return $::_reponame
}
proc is_MacOSX {} {
- global tcl_platform tk_library
if {[tk windowingsystem] eq {aqua}} {
return 1
}
@@ -167,17 +165,16 @@ proc is_MacOSX {} {
}
proc is_Windows {} {
- global tcl_platform
- if {$tcl_platform(platform) eq {windows}} {
+ if {$::tcl_platform(platform) eq {windows}} {
return 1
}
return 0
}
proc is_Cygwin {} {
- global tcl_platform _iscygwin
+ global _iscygwin
if {$_iscygwin eq {}} {
- if {$tcl_platform(platform) eq {windows}} {
+ if {$::tcl_platform(platform) eq {windows}} {
if {[catch {set p [exec cygpath --windir]} err]} {
set _iscygwin 0
} else {
@@ -367,16 +364,25 @@ proc _which {what} {
return {}
}
+proc _lappend_nice {cmd_var} {
+ global _nice
+ upvar $cmd_var cmd
+
+ if {![info exists _nice]} {
+ set _nice [_which nice]
+ }
+ if {$_nice ne {}} {
+ lappend cmd $_nice
+ }
+}
+
proc git {args} {
set opt [list exec]
while {1} {
switch -- [lindex $args 0] {
--nice {
- global _nice
- if {$_nice ne {}} {
- lappend opt $_nice
- }
+ _lappend_nice opt
}
default {
@@ -414,6 +420,7 @@ proc _open_stdout_stderr {cmd} {
error $err
}
}
+ fconfigure $fd -eofchar {}
return $fd
}
@@ -423,10 +430,7 @@ proc git_read {args} {
while {1} {
switch -- [lindex $args 0] {
--nice {
- global _nice
- if {$_nice ne {}} {
- lappend opt $_nice
- }
+ _lappend_nice opt
}
--stderr {
@@ -454,10 +458,7 @@ proc git_write {args} {
while {1} {
switch -- [lindex $args 0] {
--nice {
- global _nice
- if {$_nice ne {}} {
- lappend opt $_nice
- }
+ _lappend_nice opt
}
default {
@@ -524,7 +525,6 @@ if {$_git eq {}} {
error_popup "Cannot find git in PATH."
exit 1
}
-set _nice [_which nice]
######################################################################
##
@@ -544,8 +544,34 @@ if {![regsub {^git version } $_git_version {} _git_version]} {
error_popup "Cannot parse Git version string:\n\n$_git_version"
exit 1
}
+
+set _real_git_version $_git_version
+regsub -- {-dirty$} $_git_version {} _git_version
regsub {\.[0-9]+\.g[0-9a-f]+$} $_git_version {} _git_version
regsub {\.rc[0-9]+$} $_git_version {} _git_version
+regsub {\.GIT$} $_git_version {} _git_version
+
+if {![regexp {^[1-9]+(\.[0-9]+)+$} $_git_version]} {
+ catch {wm withdraw .}
+ if {[tk_messageBox \
+ -icon warning \
+ -type yesno \
+ -default no \
+ -title "[appname]: warning" \
+ -message "Git version cannot be determined.
+
+$_git claims it is version '$_real_git_version'.
+
+[appname] requires at least Git 1.5.0 or later.
+
+Assume '$_real_git_version' is version 1.5.0?
+"] eq {yes}} {
+ set _git_version 1.5.0
+ } else {
+ exit 1
+ }
+}
+unset _real_git_version
proc git-version {args} {
global _git_version
@@ -603,6 +629,46 @@ You are using [git-version]:
######################################################################
##
+## feature option selection
+
+if {[regexp {^git-(.+)$} [appname] _junk subcommand]} {
+ unset _junk
+} else {
+ set subcommand gui
+}
+if {$subcommand eq {gui.sh}} {
+ set subcommand gui
+}
+if {$subcommand eq {gui} && [llength $argv] > 0} {
+ set subcommand [lindex $argv 0]
+ set argv [lrange $argv 1 end]
+}
+
+enable_option multicommit
+enable_option branch
+enable_option transport
+disable_option bare
+
+switch -- $subcommand {
+browser -
+blame {
+ enable_option bare
+
+ disable_option multicommit
+ disable_option branch
+ disable_option transport
+}
+citool {
+ enable_option singlecommit
+
+ disable_option multicommit
+ disable_option branch
+ disable_option transport
+}
+}
+
+######################################################################
+##
## repository setup
if {[catch {
@@ -625,19 +691,24 @@ if {![file isdirectory $_gitdir]} {
error_popup "Git directory not found:\n\n$_gitdir"
exit 1
}
-if {[lindex [file split $_gitdir] end] ne {.git}} {
- catch {wm withdraw .}
- error_popup "Cannot use funny .git directory:\n\n$_gitdir"
- exit 1
+if {![is_enabled bare]} {
+ if {[lindex [file split $_gitdir] end] ne {.git}} {
+ catch {wm withdraw .}
+ error_popup "Cannot use funny .git directory:\n\n$_gitdir"
+ exit 1
+ }
+ if {[catch {cd [file dirname $_gitdir]} err]} {
+ catch {wm withdraw .}
+ error_popup "No working directory [file dirname $_gitdir]:\n\n$err"
+ exit 1
+ }
}
-if {[catch {cd [file dirname $_gitdir]} err]} {
- catch {wm withdraw .}
- error_popup "No working directory [file dirname $_gitdir]:\n\n$err"
- exit 1
+set _reponame [file split [file normalize $_gitdir]]
+if {[lindex $_reponame end] eq {.git}} {
+ set _reponame [lindex $_reponame end-1]
+} else {
+ set _reponame [lindex $_reponame end]
}
-set _reponame [lindex [file split \
- [file normalize [file dirname $_gitdir]]] \
- end]
######################################################################
##
@@ -758,8 +829,9 @@ proc rescan {after {honor_trustmtime 1}} {
array unset file_states
- if {![$ui_comm edit modified]
- || [string trim [$ui_comm get 0.0 end]] eq {}} {
+ if {!$::GITGUI_BCK_exists &&
+ (![$ui_comm edit modified]
+ || [string trim [$ui_comm get 0.0 end]] eq {})} {
if {[string match amend* $commit_type]} {
} elseif {[load_message GITGUI_MSG]} {
} elseif {[load_message MERGE_MSG]} {
@@ -800,6 +872,10 @@ proc rescan_stage2 {fd after} {
if {[file readable $info_exclude]} {
lappend ls_others "--exclude-from=$info_exclude"
}
+ set user_exclude [get_config core.excludesfile]
+ if {$user_exclude ne {} && [file readable $user_exclude]} {
+ lappend ls_others "--exclude-from=$user_exclude"
+ }
set buf_rdi {}
set buf_rdf {}
@@ -827,6 +903,7 @@ proc load_message {file} {
if {[catch {set fd [open $f r]}]} {
return 0
}
+ fconfigure $fd -eofchar {}
set content [string trim [read $fd]]
close $fd
regsub -all -line {[ \r\t]+$} $content {} content
@@ -1219,32 +1296,6 @@ static unsigned char file_merge_bits[] = {
0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f};
} -maskdata $filemask
-set file_dir_data {
-#define file_width 18
-#define file_height 18
-static unsigned char file_bits[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x03, 0x00,
- 0x0c, 0x03, 0x00, 0x04, 0xfe, 0x00, 0x06, 0x80, 0x00, 0xff, 0x9f, 0x00,
- 0x03, 0x98, 0x00, 0x02, 0x90, 0x00, 0x06, 0xb0, 0x00, 0x04, 0xa0, 0x00,
- 0x0c, 0xe0, 0x00, 0x08, 0xc0, 0x00, 0xf8, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-}
-image create bitmap file_dir -background white -foreground blue \
- -data $file_dir_data -maskdata $file_dir_data
-unset file_dir_data
-
-set file_uplevel_data {
-#define up_width 15
-#define up_height 15
-static unsigned char up_bits[] = {
- 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0xfc, 0x1f,
- 0xfe, 0x3f, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01,
- 0xc0, 0x01, 0xc0, 0x01, 0x00, 0x00};
-}
-image create bitmap file_uplevel -background white -foreground red \
- -data $file_uplevel_data -maskdata $file_uplevel_data
-unset file_uplevel_data
-
set ui_index .vpane.files.index.list
set ui_workdir .vpane.files.workdir.list
@@ -1345,6 +1396,7 @@ set is_quitting 0
proc do_quit {} {
global ui_comm is_quitting repo_config commit_type
+ global GITGUI_BCK_exists GITGUI_BCK_i
if {$is_quitting} return
set is_quitting 1
@@ -1353,18 +1405,30 @@ proc do_quit {} {
# -- Stash our current commit buffer.
#
set save [gitdir GITGUI_MSG]
- set msg [string trim [$ui_comm get 0.0 end]]
- regsub -all -line {[ \r\t]+$} $msg {} msg
- if {(![string match amend* $commit_type]
- || [$ui_comm edit modified])
- && $msg ne {}} {
- catch {
- set fd [open $save w]
- puts -nonewline $fd $msg
- close $fd
- }
+ if {$GITGUI_BCK_exists && ![$ui_comm edit modified]} {
+ file rename -force [gitdir GITGUI_BCK] $save
+ set GITGUI_BCK_exists 0
} else {
- catch {file delete $save}
+ set msg [string trim [$ui_comm get 0.0 end]]
+ regsub -all -line {[ \r\t]+$} $msg {} msg
+ if {(![string match amend* $commit_type]
+ || [$ui_comm edit modified])
+ && $msg ne {}} {
+ catch {
+ set fd [open $save w]
+ puts -nonewline $fd $msg
+ close $fd
+ }
+ } else {
+ catch {file delete $save}
+ }
+ }
+
+ # -- Remove our editor backup, its not needed.
+ #
+ after cancel $GITGUI_BCK_i
+ if {$GITGUI_BCK_exists} {
+ catch {file delete [gitdir GITGUI_BCK]}
}
# -- Stash our current window geometry into this repository.
@@ -1568,43 +1632,6 @@ apply_config
######################################################################
##
-## feature option selection
-
-if {[regexp {^git-(.+)$} [appname] _junk subcommand]} {
- unset _junk
-} else {
- set subcommand gui
-}
-if {$subcommand eq {gui.sh}} {
- set subcommand gui
-}
-if {$subcommand eq {gui} && [llength $argv] > 0} {
- set subcommand [lindex $argv 0]
- set argv [lrange $argv 1 end]
-}
-
-enable_option multicommit
-enable_option branch
-enable_option transport
-
-switch -- $subcommand {
-browser -
-blame {
- disable_option multicommit
- disable_option branch
- disable_option transport
-}
-citool {
- enable_option singlecommit
-
- disable_option multicommit
- disable_option branch
- disable_option transport
-}
-}
-
-######################################################################
-##
## ui construction
set ui_comm {}
@@ -1632,20 +1659,32 @@ if {[is_enabled transport]} {
menu .mbar.repository
.mbar.repository add command \
- -label {Browse Current Branch} \
+ -label {Browse Current Branch's Files} \
-command {browser::new $current_branch}
-trace add variable current_branch write ".mbar.repository entryconf [.mbar.repository index last] -label \"Browse \$current_branch\" ;#"
+set ui_browse_current [.mbar.repository index last]
+.mbar.repository add command \
+ -label {Browse Branch Files...} \
+ -command browser_open::dialog
.mbar.repository add separator
.mbar.repository add command \
- -label {Visualize Current Branch} \
+ -label {Visualize Current Branch's History} \
-command {do_gitk $current_branch}
-trace add variable current_branch write ".mbar.repository entryconf [.mbar.repository index last] -label \"Visualize \$current_branch\" ;#"
+set ui_visualize_current [.mbar.repository index last]
.mbar.repository add command \
- -label {Visualize All Branches} \
+ -label {Visualize All Branch History} \
-command {do_gitk --all}
.mbar.repository add separator
+proc current_branch_write {args} {
+ global current_branch
+ .mbar.repository entryconf $::ui_browse_current \
+ -label "Browse $current_branch's Files"
+ .mbar.repository entryconf $::ui_visualize_current \
+ -label "Visualize $current_branch's History"
+}
+trace add variable current_branch write current_branch_write
+
if {[is_enabled multicommit]} {
.mbar.repository add command -label {Database Statistics} \
-command do_stats
@@ -1766,12 +1805,12 @@ if {[is_enabled multicommit] || [is_enabled singlecommit]} {
lappend disable_on_lock \
[list .mbar.commit entryconf [.mbar.commit index last] -state]
- .mbar.commit add command -label {Add To Commit} \
+ .mbar.commit add command -label {Stage To Commit} \
-command do_add_selection
lappend disable_on_lock \
[list .mbar.commit entryconf [.mbar.commit index last] -state]
- .mbar.commit add command -label {Add Existing To Commit} \
+ .mbar.commit add command -label {Stage Changed Files To Commit} \
-command do_add_all \
-accelerator $M1T-I
lappend disable_on_lock \
@@ -1805,14 +1844,14 @@ if {[is_enabled multicommit] || [is_enabled singlecommit]} {
if {[is_enabled branch]} {
menu .mbar.merge
.mbar.merge add command -label {Local Merge...} \
- -command merge::dialog
+ -command merge::dialog \
+ -accelerator $M1T-M
lappend disable_on_lock \
[list .mbar.merge entryconf [.mbar.merge index last] -state]
.mbar.merge add command -label {Abort Merge...} \
-command merge::reset_hard
lappend disable_on_lock \
[list .mbar.merge entryconf [.mbar.merge index last] -state]
-
}
# -- Transport Menu
@@ -1844,33 +1883,6 @@ if {[is_MacOSX]} {
.mbar.edit add separator
.mbar.edit add command -label {Options...} \
-command do_options
-
- # -- Tools Menu
- #
- if {[is_Cygwin] && [file exists /usr/local/miga/lib/gui-miga]} {
- proc do_miga {} {
- if {![lock_index update]} return
- set cmd [list sh --login -c "/usr/local/miga/lib/gui-miga \"[pwd]\""]
- set miga_fd [open "|$cmd" r]
- fconfigure $miga_fd -blocking 0
- fileevent $miga_fd readable [list miga_done $miga_fd]
- ui_status {Running miga...}
- }
- proc miga_done {fd} {
- read $fd 512
- if {[eof $fd]} {
- close $fd
- unlock_index
- rescan ui_ready
- }
- }
- .mbar add cascade -label Tools -menu .mbar.tools
- menu .mbar.tools
- .mbar.tools add command -label "Migrate" \
- -command do_miga
- lappend disable_on_lock \
- [list .mbar.tools entryconf [.mbar.tools index last] -state]
- }
}
# -- Help Menu
@@ -1938,29 +1950,10 @@ proc usage {} {
# -- Not a normal commit type invocation? Do that instead!
#
switch -- $subcommand {
-browser {
- set subcommand_args {rev?}
- switch [llength $argv] {
- 0 { load_current_branch }
- 1 {
- set current_branch [lindex $argv 0]
- if {[regexp {^[0-9a-f]{1,39}$} $current_branch]} {
- if {[catch {
- set current_branch \
- [git rev-parse --verify $current_branch]
- } err]} {
- puts stderr $err
- exit 1
- }
- }
- }
- default usage
- }
- browser::new $current_branch
- return
-}
+browser -
blame {
- set subcommand_args {rev? path?}
+ set subcommand_args {rev? path}
+ if {$argv eq {}} usage
set head {}
set path {}
set is_path 0
@@ -1979,12 +1972,18 @@ blame {
} elseif {$head eq {}} {
if {$head ne {}} usage
set head $a
+ set is_path 1
} else {
usage
}
}
unset is_path
+ if {$head ne {} && $path eq {}} {
+ set path $_prefix$head
+ set head {}
+ }
+
if {$head eq {}} {
load_current_branch
} else {
@@ -1999,8 +1998,26 @@ blame {
set current_branch $head
}
- if {$path eq {}} usage
- blame::new $head $path
+ switch -- $subcommand {
+ browser {
+ if {$head eq {}} {
+ if {$path ne {} && [file isdirectory $path]} {
+ set head $current_branch
+ } else {
+ set head $path
+ set path {}
+ }
+ }
+ browser::new $head $path
+ }
+ blame {
+ if {$head eq {} && ![file exists $path]} {
+ puts stderr "fatal: cannot stat path $path: No such file or directory"
+ exit 1
+ }
+ blame::new $head $path
+ }
+ }
return
}
citool -
@@ -2115,7 +2132,7 @@ pack .vpane.lower.commarea.buttons.rescan -side top -fill x
lappend disable_on_lock \
{.vpane.lower.commarea.buttons.rescan conf -state}
-button .vpane.lower.commarea.buttons.incall -text {Add Existing} \
+button .vpane.lower.commarea.buttons.incall -text {Stage Changed} \
-command do_add_all
pack .vpane.lower.commarea.buttons.incall -side top -fill x
lappend disable_on_lock \
@@ -2389,17 +2406,25 @@ lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
$ctxm add separator
$ctxm add command -label {Options...} \
-command do_options
-bind_button3 $ui_diff "
- set cursorX %x
- set cursorY %y
- if {\$ui_index eq \$current_diff_side} {
- $ctxm entryconf $ui_diff_applyhunk -label {Unstage Hunk From Commit}
+proc popup_diff_menu {ctxm x y X Y} {
+ set ::cursorX $x
+ set ::cursorY $y
+ if {$::ui_index eq $::current_diff_side} {
+ $ctxm entryconf $::ui_diff_applyhunk \
+ -state normal \
+ -label {Unstage Hunk From Commit}
+ } elseif {{_O} eq [lindex $::file_states($::current_diff_path) 0]} {
+ $ctxm entryconf $::ui_diff_applyhunk \
+ -state disabled \
+ -label {Stage Hunk For Commit}
} else {
- $ctxm entryconf $ui_diff_applyhunk -label {Stage Hunk For Commit}
+ $ctxm entryconf $::ui_diff_applyhunk \
+ -state normal \
+ -label {Stage Hunk For Commit}
}
- tk_popup $ctxm %X %Y
-"
-unset ui_diff_applyhunk
+ tk_popup $ctxm $X $Y
+}
+bind_button3 $ui_diff [list popup_diff_menu $ctxm %x %y %X %Y]
# -- Status Bar
#
@@ -2460,6 +2485,8 @@ if {[is_enabled branch]} {
bind . <$M1B-Key-N> branch_create::dialog
bind . <$M1B-Key-o> branch_checkout::dialog
bind . <$M1B-Key-O> branch_checkout::dialog
+ bind . <$M1B-Key-m> merge::dialog
+ bind . <$M1B-Key-M> merge::dialog
}
if {[is_enabled transport]} {
bind . <$M1B-Key-p> do_push_anywhere
@@ -2551,24 +2578,64 @@ if {[is_enabled transport]} {
populate_push_menu
}
-# -- Only suggest a gc run if we are going to stay running.
-#
-if {[is_enabled multicommit]} {
- set object_limit 2000
- if {[is_Windows]} {set object_limit 200}
- regexp {^([0-9]+) objects,} [git count-objects] _junk objects_current
- if {$objects_current >= $object_limit} {
- if {[ask_popup \
- "This repository currently has $objects_current loose objects.
+if {[winfo exists $ui_comm]} {
+ set GITGUI_BCK_exists [load_message GITGUI_BCK]
+
+ # -- If both our backup and message files exist use the
+ # newer of the two files to initialize the buffer.
+ #
+ if {$GITGUI_BCK_exists} {
+ set m [gitdir GITGUI_MSG]
+ if {[file isfile $m]} {
+ if {[file mtime [gitdir GITGUI_BCK]] > [file mtime $m]} {
+ catch {file delete [gitdir GITGUI_MSG]}
+ } else {
+ $ui_comm delete 0.0 end
+ $ui_comm edit reset
+ $ui_comm edit modified false
+ catch {file delete [gitdir GITGUI_BCK]}
+ set GITGUI_BCK_exists 0
+ }
+ }
+ unset m
+ }
-To maintain optimal performance it is strongly recommended that you compress the database when more than $object_limit loose objects exist.
+ proc backup_commit_buffer {} {
+ global ui_comm GITGUI_BCK_exists
-Compress the database now?"] eq yes} {
- do_gc
+ set m [$ui_comm edit modified]
+ if {$m || $GITGUI_BCK_exists} {
+ set msg [string trim [$ui_comm get 0.0 end]]
+ regsub -all -line {[ \r\t]+$} $msg {} msg
+
+ if {$msg eq {}} {
+ if {$GITGUI_BCK_exists} {
+ catch {file delete [gitdir GITGUI_BCK]}
+ set GITGUI_BCK_exists 0
+ }
+ } elseif {$m} {
+ catch {
+ set fd [open [gitdir GITGUI_BCK] w]
+ puts -nonewline $fd $msg
+ close $fd
+ set GITGUI_BCK_exists 1
+ }
+ }
+
+ $ui_comm edit modified false
}
+
+ set ::GITGUI_BCK_i [after 2000 backup_commit_buffer]
}
- unset object_limit _junk objects_current
+
+ backup_commit_buffer
}
lock_index begin-read
+if {![winfo ismapped .]} {
+ wm deiconify .
+}
after 1 do_rescan
+if {[is_enabled multicommit]} {
+ after 1000 hint_gc
+}
diff --git a/git-gui/lib/blame.tcl b/git-gui/lib/blame.tcl
index 4bdb9a2..9607284 100644
--- a/git-gui/lib/blame.tcl
+++ b/git-gui/lib/blame.tcl
@@ -370,6 +370,7 @@ method _load {jump} {
$w_path conf -text [escape_path $path]
if {$commit eq {}} {
set fd [open $path r]
+ fconfigure $fd -eofchar {}
} else {
set fd [git_read cat-file blob "$commit:$path"]
}
@@ -770,15 +771,20 @@ method _showcommit {cur_w lno} {
set enc [string tolower [string range $line 9 end]]
}
}
- set msg [encoding convertfrom $enc [read $fd]]
- set msg [string trim $msg]
+ set msg [read $fd]
close $fd
- set author_name [encoding convertfrom $enc $author_name]
- set committer_name [encoding convertfrom $enc $committer_name]
-
- set header($cmit,author) $author_name
- set header($cmit,committer) $committer_name
+ set enc [tcl_encoding $enc]
+ if {$enc ne {}} {
+ set msg [encoding convertfrom $enc $msg]
+ set author_name [encoding convertfrom $enc $author_name]
+ set committer_name [encoding convertfrom $enc $committer_name]
+ set header($cmit,author) $author_name
+ set header($cmit,committer) $committer_name
+ set header($cmit,summary) \
+ [encoding convertfrom $enc $header($cmit,summary)]
+ }
+ set msg [string trim $msg]
}
set header($cmit,message) $msg
}
@@ -873,6 +879,11 @@ method _open_tooltip {cur_w} {
set org [lindex $amov_data $lno]
}
+ if {$dat eq {}} {
+ _hide_tooltip $this
+ return
+ }
+
set cmit [lindex $dat 0]
set tooltip_commit [list $cmit]
diff --git a/git-gui/lib/browser.tcl b/git-gui/lib/browser.tcl
index 911e5af..888db3c 100644
--- a/git-gui/lib/browser.tcl
+++ b/git-gui/lib/browser.tcl
@@ -3,6 +3,13 @@
class browser {
+image create photo ::browser::img_parent -data {R0lGODlhEAAQAIUAAPwCBBxSHBxOHMTSzNzu3KzCtBRGHCSKFIzCjLzSxBQ2FAxGHDzCLCyeHBQ+FHSmfAwuFBxKLDSCNMzizISyjJzOnDSyLAw+FAQSDAQeDBxWJAwmDAQOBKzWrDymNAQaDAQODAwaDDyKTFSyXFTGTEy6TAQCBAQKDAwiFBQyHAwSFAwmHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAZ1QIBwSCwaj0hiQCBICpcDQsFgGAaIguhhi0gohIsrQEDYMhiNrRfgeAQC5fMCAolIDhD2hFI5WC4YRBkaBxsOE2l/RxsHHA4dHmkfRyAbIQ4iIyQlB5NFGCAACiakpSZEJyinTgAcKSesACorgU4mJ6uxR35BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs=}
+image create photo ::browser::img_rblob -data {R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJSWjPz+/Ozq7GxqbJyanPT29HRydMzOzDQyNIyKjERCROTi3Pz69PTy7Pzy7PTu5Ozm3LyqlJyWlJSSjJSOhOzi1LyulPz27PTq3PTm1OzezLyqjIyKhJSKfOzaxPz29OzizLyidIyGdIyCdOTOpLymhOzavOTStMTCtMS+rMS6pMSynMSulLyedAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaQQIAQECgajcNkQMBkDgKEQFK4LFgLhkMBIVUKroWEYlEgMLxbBKLQUBwc52HgAQ4LBo049atWQyIPA3pEdFcQEhMUFYNVagQWFxgZGoxfYRsTHB0eH5UJCJAYICEinUoPIxIcHCQkIiIllQYEGCEhJicoKYwPmiQeKisrKLFKLCwtLi8wHyUlMYwM0tPUDH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs=}
+image create photo ::browser::img_xblob -data {R0lGODlhEAAQAIYAAPwCBFRWVFxaXNza3OTi3Nze3Ly2tJyanPz+/Ozq7GxubNzSxMzOzMTGxHRybDQyNLy+vHRydHx6fKSipISChIyKjGxqbERCRCwuLLy6vGRiZExKTCQiJAwKDLSytLy2rJSSlHx+fDw6PKyqrBQWFPTu5Ozm3LyulLS2tCQmJAQCBPTq3Ozi1MSynCwqLAQGBOTazOzizOzezLyqjBweHNzSvOzaxKyurHRuZNzOtLymhDw+PIyCdOzWvOTOpLyidNzKtOTStLyifMTCtMS+rLyedAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfZgACCAAEChYeGg4oCAwQFjgYBBwGKggEECJkICQoIkwADCwwNDY2mDA4Lng8QDhESsLARExQVDhYXGBkWExIaGw8cHR4SCQQfFQ8eFgUgIQEiwiMSBMYfGB4atwEXDyQd0wQlJicPKAHoFyIpJCoeDgMrLC0YKBsX6i4kL+4OMDEyZijr5oLGNxUqUCioEcPGDAwjPNyI6MEDChQjcOSwsUDHgw07RIgI4KCkAgs8cvTw8eOBogAxQtXIASTISiEuBwUYMoRIixYnZggpUgTDywdIkWJIitRPIAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7}
+image create photo ::browser::img_tree -data {R0lGODlhEAAQAIYAAPwCBAQCBExKTBwWHMzKzOzq7ERCRExGTCwqLARqnAQ+ZHR2dKyqrNTOzHx2fCQiJMTi9NTu9HzC3AxmnAQ+XPTm7Dy67DymzITC3IzG5AxypHRydKymrMzOzOzu7BweHByy9AyGtFyy1IzG3NTu/ARupFRSVByazBR6rAyGvFyuzJTK3MTm9BR+tAxWhHS61MTi7Pz+/IymvCxulBRelAx2rHS63Pz6/PTy9PTu9Nza3ISitBRupFSixNTS1CxqnDQyNMzGzOTi5MTCxMTGxGxubGxqbLy2vLSutGRiZLy6vLSytKyurDQuNFxaXKSipDw6PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAfDgACCAAECg4eIAAMEBQYHCImDBgkKCwwNBQIBBw4Bhw8QERITFJYEFQUFnoIPFhcYoRkaFBscHR4Ggh8gIRciEiMQJBkltCa6JyUoKSkXKhIrLCQYuQAPLS4TEyUhKb0qLzDVAjEFMjMuNBMoNcw21QY3ODkFOjs82RM1PfDzFRU3fOggcM7Fj2pAgggRokOHDx9DhhAZUqQaISBGhjwMEvEIkiIHEgUAkgSJkiNLmFSMJChAEydPGBSBwvJQgAc0/QQCACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs=}
+image create photo ::browser::img_symlink -data {R0lGODlhEAAQAIQAAPwCBCwqLLSytLy+vERGRFRWVDQ2NKSmpAQCBKyurMTGxISChJyanHR2dIyKjGxubHRydGRmZIyOjFxeXHx6fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAVbICACwWieY1CibCCsrBkMb0zchSEcNYskCtqBBzshFkOGQFk0IRqOxqPBODRHCMhCQKteRc9FI/KQWGOIyFYgkDC+gPR4snCcfRGKOIKIgSMQE31+f4OEYCZ+IQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7}
+image create photo ::browser::img_unknown -data {R0lGODlhEAAQAIUAAPwCBFxaXIyKjNTW1Nze3LS2tJyanER2RGS+VPz+/PTu5GxqbPz69BQ6BCxeLFSqRPT29HRydMzOzDQyNERmPKSypCRWHIyKhERCRDyGPKz2nESiLBxGHCyCHGxubPz6/PTy7Ozi1Ly2rKSipOzm3LyqlKSWhCRyFOzizLymhNTKtNzOvOzaxOTStPz27OzWvOTOpLSupLyedMS+rMS6pMSulLyqjLymfLyifAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAamQIAQECgajcOkYEBoDgoBQyAJOCCuiENCsWBIh9aGw9F4HCARiXciRDQoBUnlYRlcIgsMG5CxXAgMGhscBRAEBRd7AB0eBBoIgxUfICEiikSPgyMMIAokJZcBkBybJgomIaBJAZoMpyCmqkMBFCcVCrgKKAwpoSorKqchKCwtvasIFBIhLiYvLzDHsxQNMcMKLDAwMqEz3jQ1NTY3ONyrE+jp6hN+QQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7}
+
field w
field browser_commit
field browser_path
@@ -13,13 +20,13 @@ field browser_busy 1
field ls_buf {}; # Buffered record output from ls-tree
-constructor new {commit} {
+constructor new {commit {path {}}} {
global cursor_ptr M1B
make_toplevel top w
wm title $top "[appname] ([reponame]): File Browser"
set browser_commit $commit
- set browser_path $browser_commit:
+ set browser_path $browser_commit:$path
label $w.path \
-textvariable @browser_path \
@@ -73,7 +80,11 @@ constructor new {commit} {
bind $w_list <Visibility> [list focus $w_list]
set w $w_list
- _ls $this $browser_commit
+ if {$path ne {}} {
+ _ls $this $browser_commit:$path $path
+ } else {
+ _ls $this $browser_commit $path
+ }
return $this
}
@@ -173,7 +184,7 @@ method _ls {tree_id {name {}}} {
$w image create end \
-align center -padx 5 -pady 1 \
-name icon0 \
- -image file_uplevel
+ -image ::browser::img_parent
$w insert end {[Up To Parent]}
lappend browser_files parent
}
@@ -203,14 +214,21 @@ method _read {fd} {
switch -- $type {
blob {
- set image file_mod
+ scan [lindex $info 0] %o mode
+ if {$mode == 0120000} {
+ set image ::browser::img_symlink
+ } elseif {($mode & 0100) != 0} {
+ set image ::browser::img_xblob
+ } else {
+ set image ::browser::img_rblob
+ }
}
tree {
- set image file_dir
+ set image ::browser::img_tree
append path /
}
default {
- set image file_question
+ set image ::browser::img_unknown
}
}
@@ -239,3 +257,56 @@ method _read {fd} {
}
}
+
+class browser_open {
+
+field w ; # widget path
+field w_rev ; # mega-widget to pick the initial revision
+
+constructor dialog {} {
+ make_toplevel top w
+ wm title $top "[appname] ([reponame]): Browse Branch Files"
+ if {$top ne {.}} {
+ wm geometry $top "+[winfo rootx .]+[winfo rooty .]"
+ }
+
+ label $w.header \
+ -text {Browse Branch Files} \
+ -font font_uibold
+ pack $w.header -side top -fill x
+
+ frame $w.buttons
+ button $w.buttons.browse -text Browse \
+ -default active \
+ -command [cb _open]
+ pack $w.buttons.browse -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
+
+ set w_rev [::choose_rev::new $w.rev {Revision}]
+ $w_rev bind_listbox <Double-Button-1> [cb _open]
+ pack $w.rev -anchor nw -fill both -expand 1 -pady 5 -padx 5
+
+ bind $w <Visibility> [cb _visible]
+ bind $w <Key-Escape> [list destroy $w]
+ bind $w <Key-Return> [cb _open]\;break
+ tkwait window $w
+}
+
+method _open {} {
+ if {[catch {$w_rev commit_or_die} err]} {
+ return
+ }
+ set name [$w_rev get]
+ destroy $w
+ browser::new $name
+}
+
+method _visible {} {
+ grab $w
+ $w_rev focus_filter
+}
+
+}
diff --git a/git-gui/lib/checkout_op.tcl b/git-gui/lib/checkout_op.tcl
index 00a994b..170f737 100644
--- a/git-gui/lib/checkout_op.tcl
+++ b/git-gui/lib/checkout_op.tcl
@@ -12,6 +12,7 @@ field new_ref ; # ref we are updating/creating
field parent_w .; # window that started us
field merge_type none; # type of merge to apply to existing branch
+field merge_base {}; # merge base if we have another ref involved
field fetch_spec {}; # refetch tracking branch if used?
field checkout 1; # actually checkout the branch?
field create 0; # create the branch if it doesn't exist?
@@ -65,14 +66,19 @@ method run {} {
set r_head [lindex $fetch_spec 2]
regsub ^refs/heads/ $r_head {} r_name
+ set cmd [list git fetch $remote]
+ if {$l_trck ne {}} {
+ lappend cmd +$r_head:$l_trck
+ } else {
+ lappend cmd $r_head
+ }
+
_toplevel $this {Refreshing Tracking Branch}
set w_cons [::console::embed \
$w.console \
"Fetching $r_name from $remote"]
pack $w.console -fill both -expand 1
- $w_cons exec \
- [list git fetch $remote +$r_head:$l_trck] \
- [cb _finish_fetch]
+ $w_cons exec $cmd [cb _finish_fetch]
bind $w <$M1B-Key-w> break
bind $w <$M1B-Key-W> break
@@ -113,6 +119,9 @@ method _noop {} {}
method _finish_fetch {ok} {
if {$ok} {
set l_trck [lindex $fetch_spec 0]
+ if {$l_trck eq {}} {
+ set l_trck FETCH_HEAD
+ }
if {[catch {set new_hash [git rev-parse --verify "$l_trck^0"]} err]} {
set ok 0
$w_cons insert "fatal: Cannot resolve $l_trck"
@@ -180,29 +189,25 @@ method _update_ref {} {
# No merge would be required, don't compute anything.
#
} else {
- set mrb {}
- catch {set mrb [git merge-base $new $cur]}
- switch -- $merge_type {
- ff {
- if {$mrb eq $new} {
- # The current branch is actually newer.
- #
- set new $cur
- } elseif {$mrb eq $cur} {
- # The current branch is older.
- #
- set reflog_msg "merge $new_expr: Fast-forward"
- } else {
- _error $this "Branch '$newbranch' already exists.\n\nIt cannot fast-forward to $new_expr.\nA merge is required."
- return 0
+ catch {set merge_base [git merge-base $new $cur]}
+ if {$merge_base eq $cur} {
+ # The current branch is older.
+ #
+ set reflog_msg "merge $new_expr: Fast-forward"
+ } else {
+ switch -- $merge_type {
+ ff {
+ if {$merge_base eq $new} {
+ # The current branch is actually newer.
+ #
+ set new $cur
+ set new_hash $cur
+ } else {
+ _error $this "Branch '$newbranch' already exists.\n\nIt cannot fast-forward to $new_expr.\nA merge is required."
+ return 0
+ }
}
- }
- reset {
- if {$mrb eq $cur} {
- # The current branch is older.
- #
- set reflog_msg "merge $new_expr: Fast-forward"
- } else {
+ reset {
# The current branch will lose things.
#
if {[_confirm_reset $this $cur]} {
@@ -211,11 +216,11 @@ method _update_ref {} {
return 0
}
}
- }
- default {
- _error $this "Only 'ff' and 'reset' merge is currently supported."
- return 0
- }
+ default {
+ _error $this "Merge strategy '$merge_type' not supported."
+ return 0
+ }
+ }
}
}
@@ -243,7 +248,7 @@ method _checkout {} {
if {[lock_index checkout_op]} {
after idle [cb _start_checkout]
} else {
- _error $this "Index is already locked."
+ _error $this "Staging area (index) is already locked."
delete_this
}
}
@@ -270,7 +275,9 @@ The rescan will be automatically started now.
return
}
- if {[is_config_true gui.trustmtime]} {
+ if {$curHEAD eq $new_hash} {
+ _after_readtree $this
+ } elseif {[is_config_true gui.trustmtime]} {
_readtree $this
} else {
ui_status {Refreshing file status...}
@@ -378,22 +385,24 @@ method _after_readtree {} {
set rn [string length $rh]
if {[string equal -length $rn $rh $new_ref]} {
set new_branch [string range $new_ref $rn end]
- append log " to $new_branch"
-
- if {[catch {
- git symbolic-ref -m $log HEAD $new_ref
- } err]} {
- _fatal $this $err
+ if {$is_detached || $current_branch ne $new_branch} {
+ append log " to $new_branch"
+ if {[catch {
+ git symbolic-ref -m $log HEAD $new_ref
+ } err]} {
+ _fatal $this $err
+ }
+ set current_branch $new_branch
+ set is_detached 0
}
- set current_branch $new_branch
- set is_detached 0
} else {
- append log " to $new_expr"
-
- if {[catch {
- _detach_HEAD $log $new_hash
- } err]} {
- _fatal $this $err
+ if {$new_hash ne $HEAD} {
+ append log " to $new_expr"
+ if {[catch {
+ _detach_HEAD $log $new_hash
+ } err]} {
+ _fatal $this $err
+ }
}
set current_branch HEAD
set is_detached 1
diff --git a/git-gui/lib/choose_rev.tcl b/git-gui/lib/choose_rev.tcl
index afd8170..ec064b3 100644
--- a/git-gui/lib/choose_rev.tcl
+++ b/git-gui/lib/choose_rev.tcl
@@ -16,10 +16,28 @@ field cur_specs [list]; # list of specs for $revtype
field spec_head ; # list of all head specs
field spec_trck ; # list of all tracking branch specs
field spec_tag ; # list of all tag specs
+field tip_data ; # array of tip commit info by refname
+field log_last ; # array of reflog date by refname
-constructor new {path {title {}}} {
+field tooltip_wm {} ; # Current tooltip toplevel, if open
+field tooltip_t {} ; # Text widget in $tooltip_wm
+field tooltip_timer {} ; # Current timer event for our tooltip
+
+proc new {path {title {}}} {
+ return [_new $path 0 $title]
+}
+
+proc new_unmerged {path {title {}}} {
+ return [_new $path 1 $title]
+}
+
+constructor _new {path unmerged_only title} {
global current_branch is_detached
+ if {![info exists ::all_remotes]} {
+ load_all_remotes
+ }
+
set w $path
if {$title ne {}} {
@@ -86,13 +104,17 @@ constructor new {path {title {}}} {
listbox $w_list \
-font font_diff \
-width 50 \
- -height 5 \
+ -height 10 \
-selectmode browse \
-exportselection false \
-xscrollcommand [cb _sb_set $w.list.sbx h] \
-yscrollcommand [cb _sb_set $w.list.sby v]
pack $w_list -fill both -expand 1
grid $w.list -sticky nswe -padx {20 5} -columnspan 2
+ bind $w_list <Any-Motion> [cb _show_tooltip @%x,%y]
+ bind $w_list <Any-Enter> [cb _hide_tooltip]
+ bind $w_list <Any-Leave> [cb _hide_tooltip]
+ bind $w_list <Destroy> [cb _hide_tooltip]
grid columnconfigure $w 1 -weight 1
if {$is_detached} {
@@ -105,21 +127,89 @@ constructor new {path {title {}}} {
bind $w_filter <Key-Return> [list focus $w_list]\;break
bind $w_filter <Key-Down> [list focus $w_list]
+ set fmt list
+ append fmt { %(refname)}
+ append fmt { [list}
+ append fmt { %(objecttype)}
+ append fmt { %(objectname)}
+ append fmt { [concat %(taggername) %(authorname)]}
+ append fmt { [concat %(taggerdate) %(authordate)]}
+ append fmt { %(subject)}
+ append fmt {] [list}
+ append fmt { %(*objecttype)}
+ append fmt { %(*objectname)}
+ append fmt { %(*authorname)}
+ append fmt { %(*authordate)}
+ append fmt { %(*subject)}
+ append fmt {]}
+ set all_refn [list]
+ set fr_fd [git_read for-each-ref \
+ --tcl \
+ --sort=-taggerdate \
+ --format=$fmt \
+ refs/heads \
+ refs/remotes \
+ refs/tags \
+ ]
+ fconfigure $fr_fd -translation lf -encoding utf-8
+ while {[gets $fr_fd line] > 0} {
+ set line [eval $line]
+ if {[lindex $line 1 0] eq {tag}} {
+ if {[lindex $line 2 0] eq {commit}} {
+ set sha1 [lindex $line 2 1]
+ } else {
+ continue
+ }
+ } elseif {[lindex $line 1 0] eq {commit}} {
+ set sha1 [lindex $line 1 1]
+ } else {
+ continue
+ }
+ set refn [lindex $line 0]
+ set tip_data($refn) [lrange $line 1 end]
+ lappend cmt_refn($sha1) $refn
+ lappend all_refn $refn
+ }
+ close $fr_fd
+
+ if {$unmerged_only} {
+ set fr_fd [git_read rev-list --all ^$::HEAD]
+ while {[gets $fr_fd sha1] > 0} {
+ if {[catch {set rlst $cmt_refn($sha1)}]} continue
+ foreach refn $rlst {
+ set inc($refn) 1
+ }
+ }
+ close $fr_fd
+ } else {
+ foreach refn $all_refn {
+ set inc($refn) 1
+ }
+ }
+
set spec_head [list]
foreach name [load_all_heads] {
- lappend spec_head [list $name refs/heads/$name]
+ set refn refs/heads/$name
+ if {[info exists inc($refn)]} {
+ lappend spec_head [list $name $refn]
+ }
}
set spec_trck [list]
foreach spec [all_tracking_branches] {
- set name [lindex $spec 0]
- regsub ^refs/(heads|remotes)/ $name {} name
- lappend spec_trck [concat $name $spec]
+ set refn [lindex $spec 0]
+ if {[info exists inc($refn)]} {
+ regsub ^refs/(heads|remotes)/ $refn {} name
+ lappend spec_trck [concat $name $spec]
+ }
}
set spec_tag [list]
foreach name [load_all_tags] {
- lappend spec_tag [list $name refs/tags/$name]
+ set refn refs/tags/$name
+ if {[info exists inc($refn)]} {
+ lappend spec_tag [list $name $refn]
+ }
}
if {$is_detached} { set revtype HEAD
@@ -364,4 +454,174 @@ method _sb_set {sb orient first last} {
$sb set $first $last
}
+method _show_tooltip {pos} {
+ if {$tooltip_wm ne {}} {
+ _open_tooltip $this
+ } elseif {$tooltip_timer eq {}} {
+ set tooltip_timer [after 1000 [cb _open_tooltip]]
+ }
+}
+
+method _open_tooltip {} {
+ global remote_url
+
+ set tooltip_timer {}
+ set pos_x [winfo pointerx $w_list]
+ set pos_y [winfo pointery $w_list]
+ if {[winfo containing $pos_x $pos_y] ne $w_list} {
+ _hide_tooltip $this
+ return
+ }
+
+ set pos @[join [list \
+ [expr {$pos_x - [winfo rootx $w_list]}] \
+ [expr {$pos_y - [winfo rooty $w_list]}]] ,]
+ set lno [$w_list index $pos]
+ if {$lno eq {}} {
+ _hide_tooltip $this
+ return
+ }
+
+ set spec [lindex $cur_specs $lno]
+ set refn [lindex $spec 1]
+ if {$refn eq {}} {
+ _hide_tooltip $this
+ return
+ }
+
+ if {$tooltip_wm eq {}} {
+ set tooltip_wm [toplevel $w_list.tooltip -borderwidth 1]
+ wm overrideredirect $tooltip_wm 1
+ wm transient $tooltip_wm [winfo toplevel $w_list]
+ set tooltip_t $tooltip_wm.label
+ text $tooltip_t \
+ -takefocus 0 \
+ -highlightthickness 0 \
+ -relief flat \
+ -borderwidth 0 \
+ -wrap none \
+ -background lightyellow \
+ -foreground black
+ $tooltip_t tag conf section_header -font font_uibold
+ bind $tooltip_wm <Escape> [cb _hide_tooltip]
+ pack $tooltip_t
+ } else {
+ $tooltip_t conf -state normal
+ $tooltip_t delete 0.0 end
+ }
+
+ set data $tip_data($refn)
+ if {[lindex $data 0 0] eq {tag}} {
+ set tag [lindex $data 0]
+ if {[lindex $data 1 0] eq {commit}} {
+ set cmit [lindex $data 1]
+ } else {
+ set cmit {}
+ }
+ } elseif {[lindex $data 0 0] eq {commit}} {
+ set tag {}
+ set cmit [lindex $data 0]
+ }
+
+ $tooltip_t insert end [lindex $spec 0]
+ set last [_reflog_last $this [lindex $spec 1]]
+ if {$last ne {}} {
+ $tooltip_t insert end "\n"
+ $tooltip_t insert end "updated"
+ $tooltip_t insert end " $last"
+ }
+ $tooltip_t insert end "\n"
+
+ if {$tag ne {}} {
+ $tooltip_t insert end "\n"
+ $tooltip_t insert end "tag" section_header
+ $tooltip_t insert end " [lindex $tag 1]\n"
+ $tooltip_t insert end [lindex $tag 2]
+ $tooltip_t insert end " ([lindex $tag 3])\n"
+ $tooltip_t insert end [lindex $tag 4]
+ $tooltip_t insert end "\n"
+ }
+
+ if {$cmit ne {}} {
+ $tooltip_t insert end "\n"
+ $tooltip_t insert end "commit" section_header
+ $tooltip_t insert end " [lindex $cmit 1]\n"
+ $tooltip_t insert end [lindex $cmit 2]
+ $tooltip_t insert end " ([lindex $cmit 3])\n"
+ $tooltip_t insert end [lindex $cmit 4]
+ }
+
+ if {[llength $spec] > 2} {
+ $tooltip_t insert end "\n"
+ $tooltip_t insert end "remote" section_header
+ $tooltip_t insert end " [lindex $spec 2]\n"
+ $tooltip_t insert end "url"
+ $tooltip_t insert end " $remote_url([lindex $spec 2])\n"
+ $tooltip_t insert end "branch"
+ $tooltip_t insert end " [lindex $spec 3]"
+ }
+
+ $tooltip_t conf -state disabled
+ _position_tooltip $this
+}
+
+method _reflog_last {name} {
+ if {[info exists reflog_last($name)]} {
+ return reflog_last($name)
+ }
+
+ set last {}
+ if {[catch {set last [file mtime [gitdir $name]]}]
+ && ![catch {set g [open [gitdir logs $name] r]}]} {
+ fconfigure $g -translation binary
+ while {[gets $g line] >= 0} {
+ if {[regexp {> ([1-9][0-9]*) } $line line when]} {
+ set last $when
+ }
+ }
+ close $g
+ }
+
+ if {$last ne {}} {
+ set last [clock format $last -format {%a %b %e %H:%M:%S %Y}]
+ }
+ set reflog_last($name) $last
+ return $last
+}
+
+method _position_tooltip {} {
+ set max_h [lindex [split [$tooltip_t index end] .] 0]
+ set max_w 0
+ for {set i 1} {$i <= $max_h} {incr i} {
+ set c [lindex [split [$tooltip_t index "$i.0 lineend"] .] 1]
+ if {$c > $max_w} {set max_w $c}
+ }
+ $tooltip_t conf -width $max_w -height $max_h
+
+ set req_w [winfo reqwidth $tooltip_t]
+ set req_h [winfo reqheight $tooltip_t]
+ set pos_x [expr {[winfo pointerx .] + 5}]
+ set pos_y [expr {[winfo pointery .] + 10}]
+
+ set g "${req_w}x${req_h}"
+ if {$pos_x >= 0} {append g +}
+ append g $pos_x
+ if {$pos_y >= 0} {append g +}
+ append g $pos_y
+
+ wm geometry $tooltip_wm $g
+ raise $tooltip_wm
+}
+
+method _hide_tooltip {} {
+ if {$tooltip_wm ne {}} {
+ destroy $tooltip_wm
+ set tooltip_wm {}
+ }
+ if {$tooltip_timer ne {}} {
+ after cancel $tooltip_timer
+ set tooltip_timer {}
+ }
+}
+
}
diff --git a/git-gui/lib/commit.tcl b/git-gui/lib/commit.tcl
index 46a78c1..f857a2f 100644
--- a/git-gui/lib/commit.tcl
+++ b/git-gui/lib/commit.tcl
@@ -37,9 +37,14 @@ You are currently in the middle of a merge that has not been fully completed. Y
set enc [string tolower [string range $line 9 end]]
}
}
- set msg [encoding convertfrom $enc [read $fd]]
- set msg [string trim $msg]
+ set msg [read $fd]
close $fd
+
+ set enc [tcl_encoding $enc]
+ if {$enc ne {}} {
+ set msg [encoding convertfrom $enc $msg]
+ }
+ set msg [string trim $msg]
} err]} {
error_popup "Error loading commit data for amend:\n\n$err"
return
@@ -148,7 +153,7 @@ The rescan will be automatically started now.
U? {
error_popup "Unmerged files cannot be committed.
-File [short_path $path] has merge conflicts. You must resolve them and add the file before committing.
+File [short_path $path] has merge conflicts. You must resolve them and stage the file before committing.
"
unlock_index
return
@@ -164,7 +169,7 @@ File [short_path $path] cannot be committed by this program.
if {!$files_ready && ![string match *merge $curType]} {
info_popup {No changes to commit.
-You must add at least 1 file before you can commit.
+You must stage at least 1 file before you can commit.
}
unlock_index
return
@@ -209,7 +214,7 @@ A good commit message has the following format:
ui_status {Calling pre-commit hook...}
set pch_error {}
set fd_ph [open "| $pchook" r]
- fconfigure $fd_ph -blocking 0 -translation binary
+ fconfigure $fd_ph -blocking 0 -translation binary -eofchar {}
fileevent $fd_ph readable \
[list commit_prehook_wait $fd_ph $curHEAD $msg]
}
@@ -287,11 +292,18 @@ A rescan will be automatically started now.
#
set msg_p [gitdir COMMIT_EDITMSG]
set msg_wt [open $msg_p w]
+ fconfigure $msg_wt -translation lf
if {[catch {set enc $repo_config(i18n.commitencoding)}]} {
set enc utf-8
}
- fconfigure $msg_wt -encoding binary -translation binary
- puts -nonewline $msg_wt [encoding convertto $enc $msg]
+ set use_enc [tcl_encoding $enc]
+ if {$use_enc ne {}} {
+ fconfigure $msg_wt -encoding $use_enc
+ } else {
+ puts stderr "warning: Tcl does not support encoding '$enc'."
+ fconfigure $msg_wt -encoding utf-8
+ }
+ puts -nonewline $msg_wt $msg
close $msg_wt
# -- Create the commit.
@@ -367,6 +379,10 @@ A rescan will be automatically started now.
$ui_comm delete 0.0 end
$ui_comm edit reset
$ui_comm edit modified false
+ if {$::GITGUI_BCK_exists} {
+ catch {file delete [gitdir GITGUI_BCK]}
+ set ::GITGUI_BCK_exists 0
+ }
if {[is_enabled singlecommit]} do_quit
diff --git a/git-gui/lib/database.tcl b/git-gui/lib/database.tcl
index 87c815d..0657cc2 100644
--- a/git-gui/lib/database.tcl
+++ b/git-gui/lib/database.tcl
@@ -87,3 +87,30 @@ proc do_fsck_objects {} {
lappend cmd --strict
console::exec $w $cmd
}
+
+proc hint_gc {} {
+ set object_limit 8
+ if {[is_Windows]} {
+ set object_limit 1
+ }
+
+ set objects_current [llength [glob \
+ -directory [gitdir objects 42] \
+ -nocomplain \
+ -tails \
+ -- \
+ *]]
+
+ if {$objects_current >= $object_limit} {
+ set objects_current [expr {$objects_current * 256}]
+ set object_limit [expr {$object_limit * 256}]
+ if {[ask_popup \
+ "This repository currently has approximately $objects_current loose objects.
+
+To maintain optimal performance it is strongly recommended that you compress the database when more than $object_limit loose objects exist.
+
+Compress the database now?"] eq yes} {
+ do_gc
+ }
+ }
+}
diff --git a/git-gui/lib/diff.tcl b/git-gui/lib/diff.tcl
index 9cb9d06..e09e125 100644
--- a/git-gui/lib/diff.tcl
+++ b/git-gui/lib/diff.tcl
@@ -86,6 +86,7 @@ proc show_diff {path w {lno {}}} {
set max_sz [expr {128 * 1024}]
if {[catch {
set fd [open $path r]
+ fconfigure $fd -eofchar {}
set content [read $fd $max_sz]
close $fd
set sz [file size $path]
diff --git a/git-gui/lib/encoding.tcl b/git-gui/lib/encoding.tcl
new file mode 100644
index 0000000..7f06b0d
--- /dev/null
+++ b/git-gui/lib/encoding.tcl
@@ -0,0 +1,276 @@
+# git-gui encoding support
+# Copyright (C) 2005 Paul Mackerras <paulus@samba.org>
+# (Copied from gitk, commit fd8ccbec4f0161)
+
+# This list of encoding names and aliases is distilled from
+# http://www.iana.org/assignments/character-sets.
+# Not all of them are supported by Tcl.
+set encoding_aliases {
+ { ANSI_X3.4-1968 iso-ir-6 ANSI_X3.4-1986 ISO_646.irv:1991 ASCII
+ ISO646-US US-ASCII us IBM367 cp367 csASCII }
+ { ISO-10646-UTF-1 csISO10646UTF1 }
+ { ISO_646.basic:1983 ref csISO646basic1983 }
+ { INVARIANT csINVARIANT }
+ { ISO_646.irv:1983 iso-ir-2 irv csISO2IntlRefVersion }
+ { BS_4730 iso-ir-4 ISO646-GB gb uk csISO4UnitedKingdom }
+ { NATS-SEFI iso-ir-8-1 csNATSSEFI }
+ { NATS-SEFI-ADD iso-ir-8-2 csNATSSEFIADD }
+ { NATS-DANO iso-ir-9-1 csNATSDANO }
+ { NATS-DANO-ADD iso-ir-9-2 csNATSDANOADD }
+ { SEN_850200_B iso-ir-10 FI ISO646-FI ISO646-SE se csISO10Swedish }
+ { SEN_850200_C iso-ir-11 ISO646-SE2 se2 csISO11SwedishForNames }
+ { KS_C_5601-1987 iso-ir-149 KS_C_5601-1989 KSC_5601 korean csKSC56011987 }
+ { ISO-2022-KR csISO2022KR }
+ { EUC-KR csEUCKR }
+ { ISO-2022-JP csISO2022JP }
+ { ISO-2022-JP-2 csISO2022JP2 }
+ { JIS_C6220-1969-jp JIS_C6220-1969 iso-ir-13 katakana x0201-7
+ csISO13JISC6220jp }
+ { JIS_C6220-1969-ro iso-ir-14 jp ISO646-JP csISO14JISC6220ro }
+ { IT iso-ir-15 ISO646-IT csISO15Italian }
+ { PT iso-ir-16 ISO646-PT csISO16Portuguese }
+ { ES iso-ir-17 ISO646-ES csISO17Spanish }
+ { greek7-old iso-ir-18 csISO18Greek7Old }
+ { latin-greek iso-ir-19 csISO19LatinGreek }
+ { DIN_66003 iso-ir-21 de ISO646-DE csISO21German }
+ { NF_Z_62-010_(1973) iso-ir-25 ISO646-FR1 csISO25French }
+ { Latin-greek-1 iso-ir-27 csISO27LatinGreek1 }
+ { ISO_5427 iso-ir-37 csISO5427Cyrillic }
+ { JIS_C6226-1978 iso-ir-42 csISO42JISC62261978 }
+ { BS_viewdata iso-ir-47 csISO47BSViewdata }
+ { INIS iso-ir-49 csISO49INIS }
+ { INIS-8 iso-ir-50 csISO50INIS8 }
+ { INIS-cyrillic iso-ir-51 csISO51INISCyrillic }
+ { ISO_5427:1981 iso-ir-54 ISO5427Cyrillic1981 }
+ { ISO_5428:1980 iso-ir-55 csISO5428Greek }
+ { GB_1988-80 iso-ir-57 cn ISO646-CN csISO57GB1988 }
+ { GB_2312-80 iso-ir-58 chinese csISO58GB231280 }
+ { NS_4551-1 iso-ir-60 ISO646-NO no csISO60DanishNorwegian
+ csISO60Norwegian1 }
+ { NS_4551-2 ISO646-NO2 iso-ir-61 no2 csISO61Norwegian2 }
+ { NF_Z_62-010 iso-ir-69 ISO646-FR fr csISO69French }
+ { videotex-suppl iso-ir-70 csISO70VideotexSupp1 }
+ { PT2 iso-ir-84 ISO646-PT2 csISO84Portuguese2 }
+ { ES2 iso-ir-85 ISO646-ES2 csISO85Spanish2 }
+ { MSZ_7795.3 iso-ir-86 ISO646-HU hu csISO86Hungarian }
+ { JIS_C6226-1983 iso-ir-87 x0208 JIS_X0208-1983 csISO87JISX0208 }
+ { greek7 iso-ir-88 csISO88Greek7 }
+ { ASMO_449 ISO_9036 arabic7 iso-ir-89 csISO89ASMO449 }
+ { iso-ir-90 csISO90 }
+ { JIS_C6229-1984-a iso-ir-91 jp-ocr-a csISO91JISC62291984a }
+ { JIS_C6229-1984-b iso-ir-92 ISO646-JP-OCR-B jp-ocr-b
+ csISO92JISC62991984b }
+ { JIS_C6229-1984-b-add iso-ir-93 jp-ocr-b-add csISO93JIS62291984badd }
+ { JIS_C6229-1984-hand iso-ir-94 jp-ocr-hand csISO94JIS62291984hand }
+ { JIS_C6229-1984-hand-add iso-ir-95 jp-ocr-hand-add
+ csISO95JIS62291984handadd }
+ { JIS_C6229-1984-kana iso-ir-96 csISO96JISC62291984kana }
+ { ISO_2033-1983 iso-ir-98 e13b csISO2033 }
+ { ANSI_X3.110-1983 iso-ir-99 CSA_T500-1983 NAPLPS csISO99NAPLPS }
+ { ISO_8859-1:1987 iso-ir-100 ISO_8859-1 ISO-8859-1 latin1 l1 IBM819
+ CP819 csISOLatin1 }
+ { ISO_8859-2:1987 iso-ir-101 ISO_8859-2 ISO-8859-2 latin2 l2 csISOLatin2 }
+ { T.61-7bit iso-ir-102 csISO102T617bit }
+ { T.61-8bit T.61 iso-ir-103 csISO103T618bit }
+ { ISO_8859-3:1988 iso-ir-109 ISO_8859-3 ISO-8859-3 latin3 l3 csISOLatin3 }
+ { ISO_8859-4:1988 iso-ir-110 ISO_8859-4 ISO-8859-4 latin4 l4 csISOLatin4 }
+ { ECMA-cyrillic iso-ir-111 KOI8-E csISO111ECMACyrillic }
+ { CSA_Z243.4-1985-1 iso-ir-121 ISO646-CA csa7-1 ca csISO121Canadian1 }
+ { CSA_Z243.4-1985-2 iso-ir-122 ISO646-CA2 csa7-2 csISO122Canadian2 }
+ { CSA_Z243.4-1985-gr iso-ir-123 csISO123CSAZ24341985gr }
+ { ISO_8859-6:1987 iso-ir-127 ISO_8859-6 ISO-8859-6 ECMA-114 ASMO-708
+ arabic csISOLatinArabic }
+ { ISO_8859-6-E csISO88596E ISO-8859-6-E }
+ { ISO_8859-6-I csISO88596I ISO-8859-6-I }
+ { ISO_8859-7:1987 iso-ir-126 ISO_8859-7 ISO-8859-7 ELOT_928 ECMA-118
+ greek greek8 csISOLatinGreek }
+ { T.101-G2 iso-ir-128 csISO128T101G2 }
+ { ISO_8859-8:1988 iso-ir-138 ISO_8859-8 ISO-8859-8 hebrew
+ csISOLatinHebrew }
+ { ISO_8859-8-E csISO88598E ISO-8859-8-E }
+ { ISO_8859-8-I csISO88598I ISO-8859-8-I }
+ { CSN_369103 iso-ir-139 csISO139CSN369103 }
+ { JUS_I.B1.002 iso-ir-141 ISO646-YU js yu csISO141JUSIB1002 }
+ { ISO_6937-2-add iso-ir-142 csISOTextComm }
+ { IEC_P27-1 iso-ir-143 csISO143IECP271 }
+ { ISO_8859-5:1988 iso-ir-144 ISO_8859-5 ISO-8859-5 cyrillic
+ csISOLatinCyrillic }
+ { JUS_I.B1.003-serb iso-ir-146 serbian csISO146Serbian }
+ { JUS_I.B1.003-mac macedonian iso-ir-147 csISO147Macedonian }
+ { ISO_8859-9:1989 iso-ir-148 ISO_8859-9 ISO-8859-9 latin5 l5 csISOLatin5 }
+ { greek-ccitt iso-ir-150 csISO150 csISO150GreekCCITT }
+ { NC_NC00-10:81 cuba iso-ir-151 ISO646-CU csISO151Cuba }
+ { ISO_6937-2-25 iso-ir-152 csISO6937Add }
+ { GOST_19768-74 ST_SEV_358-88 iso-ir-153 csISO153GOST1976874 }
+ { ISO_8859-supp iso-ir-154 latin1-2-5 csISO8859Supp }
+ { ISO_10367-box iso-ir-155 csISO10367Box }
+ { ISO-8859-10 iso-ir-157 l6 ISO_8859-10:1992 csISOLatin6 latin6 }
+ { latin-lap lap iso-ir-158 csISO158Lap }
+ { JIS_X0212-1990 x0212 iso-ir-159 csISO159JISX02121990 }
+ { DS_2089 DS2089 ISO646-DK dk csISO646Danish }
+ { us-dk csUSDK }
+ { dk-us csDKUS }
+ { JIS_X0201 X0201 csHalfWidthKatakana }
+ { KSC5636 ISO646-KR csKSC5636 }
+ { ISO-10646-UCS-2 csUnicode }
+ { ISO-10646-UCS-4 csUCS4 }
+ { DEC-MCS dec csDECMCS }
+ { hp-roman8 roman8 r8 csHPRoman8 }
+ { macintosh mac csMacintosh }
+ { IBM037 cp037 ebcdic-cp-us ebcdic-cp-ca ebcdic-cp-wt ebcdic-cp-nl
+ csIBM037 }
+ { IBM038 EBCDIC-INT cp038 csIBM038 }
+ { IBM273 CP273 csIBM273 }
+ { IBM274 EBCDIC-BE CP274 csIBM274 }
+ { IBM275 EBCDIC-BR cp275 csIBM275 }
+ { IBM277 EBCDIC-CP-DK EBCDIC-CP-NO csIBM277 }
+ { IBM278 CP278 ebcdic-cp-fi ebcdic-cp-se csIBM278 }
+ { IBM280 CP280 ebcdic-cp-it csIBM280 }
+ { IBM281 EBCDIC-JP-E cp281 csIBM281 }
+ { IBM284 CP284 ebcdic-cp-es csIBM284 }
+ { IBM285 CP285 ebcdic-cp-gb csIBM285 }
+ { IBM290 cp290 EBCDIC-JP-kana csIBM290 }
+ { IBM297 cp297 ebcdic-cp-fr csIBM297 }
+ { IBM420 cp420 ebcdic-cp-ar1 csIBM420 }
+ { IBM423 cp423 ebcdic-cp-gr csIBM423 }
+ { IBM424 cp424 ebcdic-cp-he csIBM424 }
+ { IBM437 cp437 437 csPC8CodePage437 }
+ { IBM500 CP500 ebcdic-cp-be ebcdic-cp-ch csIBM500 }
+ { IBM775 cp775 csPC775Baltic }
+ { IBM850 cp850 850 csPC850Multilingual }
+ { IBM851 cp851 851 csIBM851 }
+ { IBM852 cp852 852 csPCp852 }
+ { IBM855 cp855 855 csIBM855 }
+ { IBM857 cp857 857 csIBM857 }
+ { IBM860 cp860 860 csIBM860 }
+ { IBM861 cp861 861 cp-is csIBM861 }
+ { IBM862 cp862 862 csPC862LatinHebrew }
+ { IBM863 cp863 863 csIBM863 }
+ { IBM864 cp864 csIBM864 }
+ { IBM865 cp865 865 csIBM865 }
+ { IBM866 cp866 866 csIBM866 }
+ { IBM868 CP868 cp-ar csIBM868 }
+ { IBM869 cp869 869 cp-gr csIBM869 }
+ { IBM870 CP870 ebcdic-cp-roece ebcdic-cp-yu csIBM870 }
+ { IBM871 CP871 ebcdic-cp-is csIBM871 }
+ { IBM880 cp880 EBCDIC-Cyrillic csIBM880 }
+ { IBM891 cp891 csIBM891 }
+ { IBM903 cp903 csIBM903 }
+ { IBM904 cp904 904 csIBBM904 }
+ { IBM905 CP905 ebcdic-cp-tr csIBM905 }
+ { IBM918 CP918 ebcdic-cp-ar2 csIBM918 }
+ { IBM1026 CP1026 csIBM1026 }
+ { EBCDIC-AT-DE csIBMEBCDICATDE }
+ { EBCDIC-AT-DE-A csEBCDICATDEA }
+ { EBCDIC-CA-FR csEBCDICCAFR }
+ { EBCDIC-DK-NO csEBCDICDKNO }
+ { EBCDIC-DK-NO-A csEBCDICDKNOA }
+ { EBCDIC-FI-SE csEBCDICFISE }
+ { EBCDIC-FI-SE-A csEBCDICFISEA }
+ { EBCDIC-FR csEBCDICFR }
+ { EBCDIC-IT csEBCDICIT }
+ { EBCDIC-PT csEBCDICPT }
+ { EBCDIC-ES csEBCDICES }
+ { EBCDIC-ES-A csEBCDICESA }
+ { EBCDIC-ES-S csEBCDICESS }
+ { EBCDIC-UK csEBCDICUK }
+ { EBCDIC-US csEBCDICUS }
+ { UNKNOWN-8BIT csUnknown8BiT }
+ { MNEMONIC csMnemonic }
+ { MNEM csMnem }
+ { VISCII csVISCII }
+ { VIQR csVIQR }
+ { KOI8-R csKOI8R }
+ { IBM00858 CCSID00858 CP00858 PC-Multilingual-850+euro }
+ { IBM00924 CCSID00924 CP00924 ebcdic-Latin9--euro }
+ { IBM01140 CCSID01140 CP01140 ebcdic-us-37+euro }
+ { IBM01141 CCSID01141 CP01141 ebcdic-de-273+euro }
+ { IBM01142 CCSID01142 CP01142 ebcdic-dk-277+euro ebcdic-no-277+euro }
+ { IBM01143 CCSID01143 CP01143 ebcdic-fi-278+euro ebcdic-se-278+euro }
+ { IBM01144 CCSID01144 CP01144 ebcdic-it-280+euro }
+ { IBM01145 CCSID01145 CP01145 ebcdic-es-284+euro }
+ { IBM01146 CCSID01146 CP01146 ebcdic-gb-285+euro }
+ { IBM01147 CCSID01147 CP01147 ebcdic-fr-297+euro }
+ { IBM01148 CCSID01148 CP01148 ebcdic-international-500+euro }
+ { IBM01149 CCSID01149 CP01149 ebcdic-is-871+euro }
+ { IBM1047 IBM-1047 }
+ { PTCP154 csPTCP154 PT154 CP154 Cyrillic-Asian }
+ { Amiga-1251 Ami1251 Amiga1251 Ami-1251 }
+ { UNICODE-1-1 csUnicode11 }
+ { CESU-8 csCESU-8 }
+ { BOCU-1 csBOCU-1 }
+ { UNICODE-1-1-UTF-7 csUnicode11UTF7 }
+ { ISO-8859-14 iso-ir-199 ISO_8859-14:1998 ISO_8859-14 latin8 iso-celtic
+ l8 }
+ { ISO-8859-15 ISO_8859-15 Latin-9 }
+ { ISO-8859-16 iso-ir-226 ISO_8859-16:2001 ISO_8859-16 latin10 l10 }
+ { GBK CP936 MS936 windows-936 }
+ { JIS_Encoding csJISEncoding }
+ { Shift_JIS MS_Kanji csShiftJIS }
+ { Extended_UNIX_Code_Packed_Format_for_Japanese csEUCPkdFmtJapanese
+ EUC-JP }
+ { Extended_UNIX_Code_Fixed_Width_for_Japanese csEUCFixWidJapanese }
+ { ISO-10646-UCS-Basic csUnicodeASCII }
+ { ISO-10646-Unicode-Latin1 csUnicodeLatin1 ISO-10646 }
+ { ISO-Unicode-IBM-1261 csUnicodeIBM1261 }
+ { ISO-Unicode-IBM-1268 csUnicodeIBM1268 }
+ { ISO-Unicode-IBM-1276 csUnicodeIBM1276 }
+ { ISO-Unicode-IBM-1264 csUnicodeIBM1264 }
+ { ISO-Unicode-IBM-1265 csUnicodeIBM1265 }
+ { ISO-8859-1-Windows-3.0-Latin-1 csWindows30Latin1 }
+ { ISO-8859-1-Windows-3.1-Latin-1 csWindows31Latin1 }
+ { ISO-8859-2-Windows-Latin-2 csWindows31Latin2 }
+ { ISO-8859-9-Windows-Latin-5 csWindows31Latin5 }
+ { Adobe-Standard-Encoding csAdobeStandardEncoding }
+ { Ventura-US csVenturaUS }
+ { Ventura-International csVenturaInternational }
+ { PC8-Danish-Norwegian csPC8DanishNorwegian }
+ { PC8-Turkish csPC8Turkish }
+ { IBM-Symbols csIBMSymbols }
+ { IBM-Thai csIBMThai }
+ { HP-Legal csHPLegal }
+ { HP-Pi-font csHPPiFont }
+ { HP-Math8 csHPMath8 }
+ { Adobe-Symbol-Encoding csHPPSMath }
+ { HP-DeskTop csHPDesktop }
+ { Ventura-Math csVenturaMath }
+ { Microsoft-Publishing csMicrosoftPublishing }
+ { Windows-31J csWindows31J }
+ { GB2312 csGB2312 }
+ { Big5 csBig5 }
+}
+
+proc tcl_encoding {enc} {
+ global encoding_aliases
+ set names [encoding names]
+ set lcnames [string tolower $names]
+ set enc [string tolower $enc]
+ set i [lsearch -exact $lcnames $enc]
+ if {$i < 0} {
+ # look for "isonnn" instead of "iso-nnn" or "iso_nnn"
+ if {[regsub {^iso[-_]} $enc iso encx]} {
+ set i [lsearch -exact $lcnames $encx]
+ }
+ }
+ if {$i < 0} {
+ foreach l $encoding_aliases {
+ set ll [string tolower $l]
+ if {[lsearch -exact $ll $enc] < 0} continue
+ # look through the aliases for one that tcl knows about
+ foreach e $ll {
+ set i [lsearch -exact $lcnames $e]
+ if {$i < 0} {
+ if {[regsub {^iso[-_]} $e iso ex]} {
+ set i [lsearch -exact $lcnames $ex]
+ }
+ }
+ if {$i >= 0} break
+ }
+ break
+ }
+ }
+ if {$i >= 0} {
+ return [lindex $names $i]
+ }
+ return {}
+}
diff --git a/git-gui/lib/error.tcl b/git-gui/lib/error.tcl
index d0253ae..16a2218 100644
--- a/git-gui/lib/error.tcl
+++ b/git-gui/lib/error.tcl
@@ -51,12 +51,15 @@ proc ask_popup {msg} {
if {[reponame] ne {}} {
append title " ([reponame])"
}
- return [tk_messageBox \
- -parent . \
+ set cmd [list tk_messageBox \
-icon question \
-type yesno \
-title $title \
-message $msg]
+ if {[winfo ismapped .]} {
+ lappend cmd -parent .
+ }
+ eval $cmd
}
proc hook_failed_popup {hook msg} {
diff --git a/git-gui/lib/index.tcl b/git-gui/lib/index.tcl
index 3ea72e1..f47f929 100644
--- a/git-gui/lib/index.tcl
+++ b/git-gui/lib/index.tcl
@@ -360,7 +360,7 @@ proc revert_helper {txt paths} {
"[appname] ([reponame])" \
"Revert changes in $s?
-Any unadded changes will be permanently lost by the revert." \
+Any unstaged changes will be permanently lost by the revert." \
question \
1 \
{Do Nothing} \
diff --git a/git-gui/lib/merge.tcl b/git-gui/lib/merge.tcl
index 288d7ac..5de0d82 100644
--- a/git-gui/lib/merge.tcl
+++ b/git-gui/lib/merge.tcl
@@ -1,9 +1,12 @@
# git-gui branch merge support
# Copyright (C) 2006, 2007 Shawn Pearce
-namespace eval merge {
+class merge {
+
+field w ; # top level window
+field w_rev ; # mega-widget to pick the revision to merge
-proc _can_merge {} {
+method _can_merge {} {
global HEAD commit_type file_states
if {[string match amend* $commit_type]} {
@@ -42,7 +45,7 @@ The rescan will be automatically started now.
File [short_path $path] has merge conflicts.
-You must resolve them, add the file, and commit to complete the current merge. Only then can you begin another merge.
+You must resolve them, stage the file, and commit to complete the current merge. Only then can you begin another merge.
"
unlock_index
return 0
@@ -63,147 +66,93 @@ You should complete the current commit before starting a merge. Doing so will h
return 1
}
-proc _refs {w list} {
- set r {}
- foreach i [$w.source.l curselection] {
- lappend r [lindex [lindex $list $i] 0]
+method _rev {} {
+ if {[catch {$w_rev commit_or_die}]} {
+ return {}
}
- return $r
+ return [$w_rev get]
}
-proc _visualize {w list} {
- set revs [_refs $w $list]
- if {$revs eq {}} return
- lappend revs --not HEAD
- do_gitk $revs
+method _visualize {} {
+ set rev [_rev $this]
+ if {$rev ne {}} {
+ do_gitk [list $rev --not HEAD]
+ }
}
-proc _start {w list} {
- global HEAD current_branch
+method _start {} {
+ global HEAD current_branch remote_url
- set cmd [list git merge]
- set names [_refs $w $list]
- set revcnt [llength $names]
- append cmd { } $names
-
- if {$revcnt == 0} {
+ set name [_rev $this]
+ if {$name eq {}} {
return
- } elseif {$revcnt == 1} {
- set unit branch
- } elseif {$revcnt <= 15} {
- set unit branches
-
- if {[tk_dialog \
- $w.confirm_octopus \
- [wm title $w] \
- "Use octopus merge strategy?
-
-You are merging $revcnt branches at once. This requires using the octopus merge driver, which may not succeed if there are file-level conflicts.
-" \
- question \
- 0 \
- {Cancel} \
- {Use octopus} \
- ] != 1} return
- } else {
- tk_messageBox \
- -icon error \
- -type ok \
- -title [wm title $w] \
- -parent $w \
- -message "Too many branches selected.
+ }
-You have requested to merge $revcnt branches in an octopus merge. This exceeds Git's internal limit of 15 branches per merge.
+ set spec [$w_rev get_tracking_branch]
+ set cmit [$w_rev get_commit]
-Please select fewer branches. To merge more than 15 branches, merge the branches in batches.
-"
- return
+ set fh [open [gitdir FETCH_HEAD] w]
+ fconfigure $fh -translation lf
+ if {$spec eq {}} {
+ set remote .
+ set branch $name
+ set stitle $branch
+ } else {
+ set remote $remote_url([lindex $spec 1])
+ if {[regexp {^[^:@]*@[^:]*:/} $remote]} {
+ regsub {^[^:@]*@} $remote {} remote
+ }
+ set branch [lindex $spec 2]
+ set stitle "$branch of $remote"
}
-
- set msg "Merging $current_branch, [join $names {, }]"
+ regsub ^refs/heads/ $branch {} branch
+ puts $fh "$cmit\t\tbranch '$branch' of $remote"
+ close $fh
+
+ set cmd [list git]
+ lappend cmd merge
+ lappend cmd --strategy=recursive
+ lappend cmd [git fmt-merge-msg <[gitdir FETCH_HEAD]]
+ lappend cmd HEAD
+ lappend cmd $cmit
+
+ set msg "Merging $current_branch and $stitle"
ui_status "$msg..."
- set cons [console::new "Merge" $msg]
- console::exec $cons $cmd \
- [namespace code [list _finish $revcnt $cons]]
+ set cons [console::new "Merge" "merge $stitle"]
+ console::exec $cons $cmd [cb _finish $cons]
wm protocol $w WM_DELETE_WINDOW {}
destroy $w
}
-proc _finish {revcnt w ok} {
- console::done $w $ok
+method _finish {cons ok} {
+ console::done $cons $ok
if {$ok} {
set msg {Merge completed successfully.}
} else {
- if {$revcnt != 1} {
- info_popup "Octopus merge failed.
-
-Your merge of $revcnt branches has failed.
-
-There are file-level conflicts between the branches which must be resolved manually.
-
-The working directory will now be reset.
-
-You can attempt this merge again by merging only one branch at a time." $w
-
- set fd [git_read read-tree --reset -u HEAD]
- fconfigure $fd -blocking 0 -translation binary
- fileevent $fd readable \
- [namespace code [list _reset_wait $fd]]
- ui_status {Aborting... please wait...}
- return
- }
-
set msg {Merge failed. Conflict resolution is required.}
}
unlock_index
rescan [list ui_status $msg]
+ delete_this
}
-proc dialog {} {
+constructor dialog {} {
global current_branch
global M1B
- if {![_can_merge]} return
-
- set fmt {list %(objectname) %(*objectname) %(refname) %(subject)}
- set fr_fd [git_read for-each-ref \
- --tcl \
- --format=$fmt \
- refs/heads \
- refs/remotes \
- refs/tags \
- ]
- fconfigure $fr_fd -translation binary
- while {[gets $fr_fd line] > 0} {
- set line [eval $line]
- set ref [lindex $line 2]
- regsub ^refs/(heads|remotes|tags)/ $ref {} ref
- set subj($ref) [lindex $line 3]
- lappend sha1([lindex $line 0]) $ref
- if {[lindex $line 1] ne {}} {
- lappend sha1([lindex $line 1]) $ref
- }
- }
- close $fr_fd
-
- set to_show {}
- set fr_fd [git_read rev-list --all --not HEAD]
- while {[gets $fr_fd line] > 0} {
- if {[catch {set ref $sha1($line)}]} continue
- foreach n $ref {
- lappend to_show [list $n $line]
- }
+ if {![_can_merge $this]} {
+ delete_this
+ return
}
- close $fr_fd
- set to_show [lsort -unique $to_show]
- set w .merge_setup
- toplevel $w
- wm geometry $w "+[winfo rootx .]+[winfo rooty .]"
+ make_toplevel top w
+ wm title $top "[appname] ([reponame]): Merge"
+ if {$top ne {.}} {
+ wm geometry $top "+[winfo rootx .]+[winfo rooty .]"
+ }
- set _visualize [namespace code [list _visualize $w $to_show]]
- set _start [namespace code [list _start $w $to_show]]
+ set _start [cb _start]
label $w.header \
-text "Merge Into $current_branch" \
@@ -211,55 +160,51 @@ proc dialog {} {
pack $w.header -side top -fill x
frame $w.buttons
- button $w.buttons.visualize -text Visualize -command $_visualize
+ button $w.buttons.visualize \
+ -text Visualize \
+ -command [cb _visualize]
pack $w.buttons.visualize -side left
- button $w.buttons.create -text Merge -command $_start
- pack $w.buttons.create -side right
+ button $w.buttons.merge \
+ -text Merge \
+ -command $_start
+ pack $w.buttons.merge -side right
button $w.buttons.cancel \
-text {Cancel} \
- -command "unlock_index;destroy $w"
+ -command [cb _cancel]
pack $w.buttons.cancel -side right -padx 5
pack $w.buttons -side bottom -fill x -pady 10 -padx 10
- labelframe $w.source -text {Source Branches}
- listbox $w.source.l \
- -height 10 \
- -width 70 \
- -font font_diff \
- -selectmode extended \
- -yscrollcommand [list $w.source.sby set]
- scrollbar $w.source.sby -command [list $w.source.l yview]
- pack $w.source.sby -side right -fill y
- pack $w.source.l -side left -fill both -expand 1
- pack $w.source -fill both -expand 1 -pady 5 -padx 5
-
- foreach ref $to_show {
- set n [lindex $ref 0]
- if {[string length $n] > 20} {
- set n "[string range $n 0 16]..."
- }
- $w.source.l insert end [format {%s %-20s %s} \
- [string range [lindex $ref 1] 0 5] \
- $n \
- $subj([lindex $ref 0])]
- }
-
- bind $w.source.l <Key-K> [list event generate %W <Shift-Key-Up>]
- bind $w.source.l <Key-J> [list event generate %W <Shift-Key-Down>]
- bind $w.source.l <Key-k> [list event generate %W <Key-Up>]
- bind $w.source.l <Key-j> [list event generate %W <Key-Down>]
- bind $w.source.l <Key-h> [list event generate %W <Key-Left>]
- bind $w.source.l <Key-l> [list event generate %W <Key-Right>]
- bind $w.source.l <Key-v> $_visualize
+ set w_rev [::choose_rev::new_unmerged $w.rev {Revision To Merge}]
+ pack $w.rev -anchor nw -fill both -expand 1 -pady 5 -padx 5
bind $w <$M1B-Key-Return> $_start
- bind $w <Visibility> "grab $w; focus $w.source.l"
- bind $w <Key-Escape> "unlock_index;destroy $w"
- wm protocol $w WM_DELETE_WINDOW "unlock_index;destroy $w"
- wm title $w "[appname] ([reponame]): Merge"
+ bind $w <Key-Return> $_start
+ bind $w <Key-Escape> [cb _cancel]
+ wm protocol $w WM_DELETE_WINDOW [cb _cancel]
+
+ bind $w.buttons.merge <Visibility> [cb _visible]
tkwait window $w
}
+method _visible {} {
+ grab $w
+ if {[is_config_true gui.matchtrackingbranch]} {
+ $w_rev pick_tracking_branch
+ }
+ $w_rev focus_filter
+}
+
+method _cancel {} {
+ wm protocol $w WM_DELETE_WINDOW {}
+ unlock_index
+ destroy $w
+ delete_this
+}
+
+}
+
+namespace eval merge {
+
proc reset_hard {} {
global HEAD commit_type file_states
@@ -274,20 +219,24 @@ You must finish amending this commit.
if {![lock_index abort]} return
if {[string match *merge* $commit_type]} {
- set op merge
+ set op_question "Abort merge?
+
+Aborting the current merge will cause *ALL* uncommitted changes to be lost.
+
+Continue with aborting the current merge?"
} else {
- set op commit
- }
+ set op_question "Reset changes?
- if {[ask_popup "Abort $op?
+Resetting the changes will cause *ALL* uncommitted changes to be lost.
-Aborting the current $op will cause *ALL* uncommitted changes to be lost.
+Continue with resetting the current changes?"
+ }
-Continue with aborting the current $op?"] eq {yes}} {
- set fd [git_read read-tree --reset -u HEAD]
+ if {[ask_popup $op_question] eq {yes}} {
+ set fd [git_read --stderr read-tree --reset -u -v HEAD]
fconfigure $fd -blocking 0 -translation binary
fileevent $fd readable [namespace code [list _reset_wait $fd]]
- ui_status {Aborting... please wait...}
+ $::main_status start {Aborting} {files reset}
} else {
unlock_index
}
@@ -296,9 +245,12 @@ Continue with aborting the current $op?"] eq {yes}} {
proc _reset_wait {fd} {
global ui_comm
- read $fd
+ $::main_status update_meter [read $fd]
+
+ fconfigure $fd -blocking 1
if {[eof $fd]} {
- close $fd
+ set fail [catch {close $fd} err]
+ $::main_status stop
unlock_index
$ui_comm delete 0.0 end
@@ -310,7 +262,12 @@ proc _reset_wait {fd} {
catch {file delete [gitdir MERGE_MSG]}
catch {file delete [gitdir GITGUI_MSG]}
+ if {$fail} {
+ warn_popup "Abort failed.\n\n$err"
+ }
rescan {ui_status {Abort completed. Ready.}}
+ } else {
+ fconfigure $fd -blocking 0
}
}
diff --git a/git-gui/lib/remote.tcl b/git-gui/lib/remote.tcl
index e235ca8..cf9b9d5 100644
--- a/git-gui/lib/remote.tcl
+++ b/git-gui/lib/remote.tcl
@@ -57,6 +57,7 @@ proc all_tracking_branches {} {
proc load_all_remotes {} {
global repo_config
global all_remotes tracking_branches some_heads_tracking
+ global remote_url
set some_heads_tracking 0
set all_remotes [list]
@@ -76,6 +77,10 @@ proc load_all_remotes {} {
catch {
set fd [open [file join $rm_dir $name] r]
while {[gets $fd line] >= 0} {
+ if {[regexp {^URL:[ ]*(.+)$} $line line url]} {
+ set remote_url($name) $url
+ continue
+ }
if {![regexp {^Pull:[ ]*([^:]+):(.+)$} \
$line line src dst]} continue
if {[string index $src 0] eq {+}} {
@@ -100,6 +105,7 @@ proc load_all_remotes {} {
foreach line [array names repo_config remote.*.url] {
if {![regexp ^remote\.(.*)\.url\$ $line line name]} continue
lappend all_remotes $name
+ set remote_url($name) $repo_config(remote.$name.url)
if {[catch {set fl $repo_config(remote.$name.fetch)}]} {
set fl {}
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 9a88335..061cd0a 100755
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -17,7 +17,7 @@ USAGE='(--continue | --abort | --skip | [--preserve-merges] [--verbose]
require_work_tree
DOTEST="$GIT_DIR/.dotest-merge"
-TODO="$DOTEST"/todo
+TODO="$DOTEST"/git-rebase-todo
DONE="$DOTEST"/done
MSG="$DOTEST"/message
SQUASH_MSG="$DOTEST"/message-squash
@@ -260,8 +260,8 @@ do_next () {
esac
failed=f
- pick_one -n $sha1 || failed=t
output git reset --soft HEAD^
+ pick_one -n $sha1 || failed=t
author_script=$(get_author_ident_from_commit $sha1)
echo "$author_script" > "$DOTEST"/author-script
case $failed in
diff --git a/git-stash.sh b/git-stash.sh
index f90dffd..30425ce 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -36,6 +36,9 @@ save_stash () {
test -f "$GIT_DIR/logs/$ref_stash" ||
clear_stash || die "Cannot initialize stash"
+ # Make sure the reflog for stash is kept.
+ : >>"$GIT_DIR/logs/$ref_stash"
+
# state of the base commit
if b_commit=$(git rev-parse --verify HEAD)
then
@@ -125,19 +128,24 @@ apply_stash () {
c_tree=$(git write-tree) ||
die 'Cannot apply a stash in the middle of a merge'
+ # stash records the work tree, and is a merge between the
+ # base commit (first parent) and the index tree (second parent).
s=$(git rev-parse --revs-only --no-flags --default $ref_stash "$@") &&
w_tree=$(git rev-parse --verify "$s:") &&
- b_tree=$(git rev-parse --verify "$s^:") ||
+ b_tree=$(git rev-parse --verify "$s^1:") &&
+ i_tree=$(git rev-parse --verify "$s^2:") ||
die "$*: no valid stashed state found"
- test -z "$unstash_index" || {
+ unstashed_index_tree=
+ if test -n "$unstash_index" && test "$b_tree" != "$i_tree"
+ then
git diff --binary $s^2^..$s^2 | git apply --cached
test $? -ne 0 &&
die 'Conflicts in index. Try without --index.'
unstashed_index_tree=$(git-write-tree) ||
die 'Could not save index tree'
git reset
- }
+ fi
eval "
GITHEAD_$w_tree='Stashed changes' &&
@@ -149,18 +157,25 @@ apply_stash () {
if git-merge-recursive $b_tree -- $c_tree $w_tree
then
# No conflict
- a="$TMP-added" &&
- git diff --cached --name-only --diff-filter=A $c_tree >"$a" &&
- git read-tree --reset $c_tree &&
- git update-index --add --stdin <"$a" ||
- die "Cannot unstage modified files"
- git-status
- rm -f "$a"
- test -z "$unstash_index" || git read-tree $unstashed_index_tree
+ if test -n "$unstashed_index_tree"
+ then
+ git read-tree "$unstashed_index_tree"
+ else
+ a="$TMP-added" &&
+ git diff --cached --name-only --diff-filter=A $c_tree >"$a" &&
+ git read-tree --reset $c_tree &&
+ git update-index --add --stdin <"$a" ||
+ die "Cannot unstage modified files"
+ rm -f "$a"
+ fi
+ git status || :
else
# Merge conflict; keep the exit status from merge-recursive
status=$?
- test -z "$unstash_index" || echo 'Index was not unstashed.' >&2
+ if test -n "$unstash_index"
+ then
+ echo >&2 'Index was not unstashed.'
+ fi
exit $status
fi
}
diff --git a/gitk b/gitk
index 39e452a..f74ce51 100755
--- a/gitk
+++ b/gitk
@@ -101,7 +101,7 @@ proc start_rev_list {view} {
set commfd($view) $fd
set leftover($view) {}
set lookingforhead $showlocalchanges
- fconfigure $fd -blocking 0 -translation lf
+ fconfigure $fd -blocking 0 -translation lf -eofchar {}
if {$tclencoding != {}} {
fconfigure $fd -encoding $tclencoding
}
@@ -139,6 +139,10 @@ proc getcommitlines {fd view} {
global vparentlist vdisporder vcmitlisted
set stuff [read $fd 500000]
+ # git log doesn't terminate the last commit with a null...
+ if {$stuff == {} && $leftover($view) ne {} && [eof $fd]} {
+ set stuff "\0"
+ }
if {$stuff == {}} {
if {![eof $fd]} {
return 1
@@ -262,11 +266,11 @@ proc chewcommits {view} {
set tlimit [expr {[clock clicks -milliseconds] + 50}]
set more [layoutmore $tlimit $allread]
if {$allread && !$more} {
- global displayorder nullid commitidx phase
+ global displayorder commitidx phase
global numcommits startmsecs
if {[info exists pending_select]} {
- set row [expr {[lindex $displayorder 0] eq $nullid}]
+ set row [first_real_row]
selectline $row 1
}
if {$commitidx($curview) > 0} {
@@ -437,6 +441,19 @@ proc readrefs {} {
}
}
+# skip over fake commits
+proc first_real_row {} {
+ global nullid nullid2 displayorder numcommits
+
+ for {set row 0} {$row < $numcommits} {incr row} {
+ set id [lindex $displayorder $row]
+ if {$id ne $nullid && $id ne $nullid2} {
+ break
+ }
+ }
+ return $row
+}
+
# update things for a head moved to a child of its previous location
proc movehead {id name} {
global headids idheads
@@ -796,6 +813,12 @@ proc makewindow {} {
wm geometry . "$geometry(main)"
}
+ if {[tk windowingsystem] eq {aqua}} {
+ set M1B M1
+ } else {
+ set M1B Control
+ }
+
bind .pwbottom <Configure> {resizecdetpanes %W %w}
pack .ctop -fill both -expand 1
bindall <1> {selcanvline %W %x %y}
@@ -814,12 +837,12 @@ proc makewindow {} {
bindkey <Key-Left> "goback"
bind . <Key-Prior> "selnextpage -1"
bind . <Key-Next> "selnextpage 1"
- bind . <Control-Home> "allcanvs yview moveto 0.0"
- bind . <Control-End> "allcanvs yview moveto 1.0"
- bind . <Control-Key-Up> "allcanvs yview scroll -1 units"
- bind . <Control-Key-Down> "allcanvs yview scroll 1 units"
- bind . <Control-Key-Prior> "allcanvs yview scroll -1 pages"
- bind . <Control-Key-Next> "allcanvs yview scroll 1 pages"
+ bind . <$M1B-Home> "allcanvs yview moveto 0.0"
+ bind . <$M1B-End> "allcanvs yview moveto 1.0"
+ bind . <$M1B-Key-Up> "allcanvs yview scroll -1 units"
+ bind . <$M1B-Key-Down> "allcanvs yview scroll 1 units"
+ bind . <$M1B-Key-Prior> "allcanvs yview scroll -1 pages"
+ bind . <$M1B-Key-Next> "allcanvs yview scroll 1 pages"
bindkey <Key-Delete> "$ctext yview scroll -1 pages"
bindkey <Key-BackSpace> "$ctext yview scroll -1 pages"
bindkey <Key-space> "$ctext yview scroll 1 pages"
@@ -839,15 +862,15 @@ proc makewindow {} {
bindkey ? findprev
bindkey f nextfile
bindkey <F5> updatecommits
- bind . <Control-q> doquit
- bind . <Control-f> dofind
- bind . <Control-g> {findnext 0}
- bind . <Control-r> dosearchback
- bind . <Control-s> dosearch
- bind . <Control-equal> {incrfont 1}
- bind . <Control-KP_Add> {incrfont 1}
- bind . <Control-minus> {incrfont -1}
- bind . <Control-KP_Subtract> {incrfont -1}
+ bind . <$M1B-q> doquit
+ bind . <$M1B-f> dofind
+ bind . <$M1B-g> {findnext 0}
+ bind . <$M1B-r> dosearchback
+ bind . <$M1B-s> dosearch
+ bind . <$M1B-equal> {incrfont 1}
+ bind . <$M1B-KP_Add> {incrfont 1}
+ bind . <$M1B-minus> {incrfont -1}
+ bind . <$M1B-KP_Subtract> {incrfont -1}
wm protocol . WM_DELETE_WINDOW doquit
bind . <Button-1> "click %W"
bind $fstring <Key-Return> dofind
@@ -1088,12 +1111,17 @@ proc keys {} {
raise $w
return
}
+ if {[tk windowingsystem] eq {aqua}} {
+ set M1T Cmd
+ } else {
+ set M1T Ctrl
+ }
toplevel $w
wm title $w "Gitk key bindings"
- message $w.m -text {
+ message $w.m -text "
Gitk key bindings:
-<Ctrl-Q> Quit
+<$M1T-Q> Quit
<Home> Move to first commit
<End> Move to last commit
<Up>, p, i Move up one commit
@@ -1102,12 +1130,12 @@ Gitk key bindings:
<Right>, x, l Go forward in history list
<PageUp> Move up one page in commit list
<PageDown> Move down one page in commit list
-<Ctrl-Home> Scroll to top of commit list
-<Ctrl-End> Scroll to bottom of commit list
-<Ctrl-Up> Scroll commit list up one line
-<Ctrl-Down> Scroll commit list down one line
-<Ctrl-PageUp> Scroll commit list up one page
-<Ctrl-PageDown> Scroll commit list down one page
+<$M1T-Home> Scroll to top of commit list
+<$M1T-End> Scroll to bottom of commit list
+<$M1T-Up> Scroll commit list up one line
+<$M1T-Down> Scroll commit list down one line
+<$M1T-PageUp> Scroll commit list up one page
+<$M1T-PageDown> Scroll commit list down one page
<Shift-Up> Move to previous highlighted line
<Shift-Down> Move to next highlighted line
<Delete>, b Scroll diff view up one page
@@ -1115,20 +1143,20 @@ Gitk key bindings:
<Space> Scroll diff view down one page
u Scroll diff view up 18 lines
d Scroll diff view down 18 lines
-<Ctrl-F> Find
-<Ctrl-G> Move to next find hit
+<$M1T-F> Find
+<$M1T-G> Move to next find hit
<Return> Move to next find hit
/ Move to next find hit, or redo find
? Move to previous find hit
f Scroll diff view to next file
-<Ctrl-S> Search for next hit in diff view
-<Ctrl-R> Search for previous hit in diff view
-<Ctrl-KP+> Increase font size
-<Ctrl-plus> Increase font size
-<Ctrl-KP-> Decrease font size
-<Ctrl-minus> Decrease font size
+<$M1T-S> Search for next hit in diff view
+<$M1T-R> Search for previous hit in diff view
+<$M1T-KP+> Increase font size
+<$M1T-plus> Increase font size
+<$M1T-KP-> Decrease font size
+<$M1T-minus> Decrease font size
<F5> Update
-} \
+" \
-justify left -bg white -border 2 -relief groove
pack $w.m -side top -fill both -padx 2 -pady 2
$w.m configure -font $uifont
@@ -1871,7 +1899,7 @@ proc showview {n} {
} elseif {$selid ne {}} {
set pending_select $selid
} else {
- set row [expr {[lindex $displayorder 0] eq $nullid}]
+ set row [first_real_row]
if {$row < $numcommits} {
selectline $row 0
} else {
@@ -2133,7 +2161,7 @@ proc readfhighlight {} {
proc find_change {name ix op} {
global nhighlights mainfont boldnamerows
- global findstring findpattern findtype markingmatches
+ global findstring findpattern findtype
# delete previous highlights, if any
foreach row $boldnamerows {
@@ -2148,7 +2176,6 @@ proc find_change {name ix op} {
$findstring]
set findpattern "*$e*"
}
- set markingmatches [expr {$findstring ne {}}]
drawvisible
}
@@ -2194,26 +2221,32 @@ proc askfindhighlight {row id} {
}
}
if {$markingmatches} {
- markrowmatches $row [lindex $info 0] [lindex $info 1]
+ markrowmatches $row $id
}
}
set nhighlights($row) $isbold
}
-proc markrowmatches {row headline author} {
- global canv canv2 linehtag linentag
+proc markrowmatches {row id} {
+ global canv canv2 linehtag linentag commitinfo findloc
+ set headline [lindex $commitinfo($id) 0]
+ set author [lindex $commitinfo($id) 1]
$canv delete match$row
$canv2 delete match$row
- set m [findmatches $headline]
- if {$m ne {}} {
- markmatches $canv $row $headline $linehtag($row) $m \
- [$canv itemcget $linehtag($row) -font]
+ if {$findloc eq "All fields" || $findloc eq "Headline"} {
+ set m [findmatches $headline]
+ if {$m ne {}} {
+ markmatches $canv $row $headline $linehtag($row) $m \
+ [$canv itemcget $linehtag($row) -font] $row
+ }
}
- set m [findmatches $author]
- if {$m ne {}} {
- markmatches $canv2 $row $author $linentag($row) $m \
- [$canv2 itemcget $linentag($row) -font]
+ if {$findloc eq "All fields" || $findloc eq "Author"} {
+ set m [findmatches $author]
+ if {$m ne {}} {
+ markmatches $canv2 $row $author $linentag($row) $m \
+ [$canv2 itemcget $linentag($row) -font] $row
+ }
}
}
@@ -2643,7 +2676,7 @@ proc layoutmore {tmax allread} {
proc showstuff {canshow last} {
global numcommits commitrow pending_select selectedline curview
- global lookingforhead mainheadid displayorder nullid selectfirst
+ global lookingforhead mainheadid displayorder selectfirst
global lastscrollset
if {$numcommits == 0} {
@@ -2676,7 +2709,7 @@ proc showstuff {canshow last} {
if {[info exists selectedline] || [info exists pending_select]} {
set selectfirst 0
} else {
- set l [expr {[lindex $displayorder 0] eq $nullid}]
+ set l [first_real_row]
selectline $l 1
set selectfirst 0
}
@@ -2700,48 +2733,93 @@ proc doshowlocalchanges {} {
}
proc dohidelocalchanges {} {
- global lookingforhead localrow lserial
+ global lookingforhead localfrow localirow lserial
set lookingforhead 0
- if {$localrow >= 0} {
- removerow $localrow
- set localrow -1
+ if {$localfrow >= 0} {
+ removerow $localfrow
+ set localfrow -1
+ if {$localirow > 0} {
+ incr localirow -1
+ }
+ }
+ if {$localirow >= 0} {
+ removerow $localirow
+ set localirow -1
}
incr lserial
}
-# spawn off a process to do git diff-index HEAD
+# spawn off a process to do git diff-index --cached HEAD
proc dodiffindex {} {
- global localrow lserial
+ global localirow localfrow lserial
incr lserial
- set localrow -1
- set fd [open "|git diff-index HEAD" r]
+ set localfrow -1
+ set localirow -1
+ set fd [open "|git diff-index --cached HEAD" r]
fconfigure $fd -blocking 0
filerun $fd [list readdiffindex $fd $lserial]
}
proc readdiffindex {fd serial} {
- global localrow commitrow mainheadid nullid curview
+ global localirow commitrow mainheadid nullid2 curview
global commitinfo commitdata lserial
+ set isdiff 1
if {[gets $fd line] < 0} {
- if {[eof $fd]} {
- close $fd
- return 0
+ if {![eof $fd]} {
+ return 1
}
- return 1
+ set isdiff 0
}
# we only need to see one line and we don't really care what it says...
close $fd
- if {$serial == $lserial && $localrow == -1} {
+ # now see if there are any local changes not checked in to the index
+ if {$serial == $lserial} {
+ set fd [open "|git diff-files" r]
+ fconfigure $fd -blocking 0
+ filerun $fd [list readdifffiles $fd $serial]
+ }
+
+ if {$isdiff && $serial == $lserial && $localirow == -1} {
+ # add the line for the changes in the index to the graph
+ set localirow $commitrow($curview,$mainheadid)
+ set hl "Local changes checked in to index but not committed"
+ set commitinfo($nullid2) [list $hl {} {} {} {} " $hl\n"]
+ set commitdata($nullid2) "\n $hl\n"
+ insertrow $localirow $nullid2
+ }
+ return 0
+}
+
+proc readdifffiles {fd serial} {
+ global localirow localfrow commitrow mainheadid nullid curview
+ global commitinfo commitdata lserial
+
+ set isdiff 1
+ if {[gets $fd line] < 0} {
+ if {![eof $fd]} {
+ return 1
+ }
+ set isdiff 0
+ }
+ # we only need to see one line and we don't really care what it says...
+ close $fd
+
+ if {$isdiff && $serial == $lserial && $localfrow == -1} {
# add the line for the local diff to the graph
- set localrow $commitrow($curview,$mainheadid)
- set hl "Local uncommitted changes"
+ if {$localirow >= 0} {
+ set localfrow $localirow
+ incr localirow
+ } else {
+ set localfrow $commitrow($curview,$mainheadid)
+ }
+ set hl "Local uncommitted changes, not checked in to index"
set commitinfo($nullid) [list $hl {} {} {} {} " $hl\n"]
set commitdata($nullid) "\n $hl\n"
- insertrow $localrow $nullid
+ insertrow $localfrow $nullid
}
return 0
}
@@ -3337,13 +3415,15 @@ proc drawcmittext {id row col} {
global linespc canv canv2 canv3 canvy0 fgcolor curview
global commitlisted commitinfo rowidlist parentlist
global rowtextx idpos idtags idheads idotherrefs
- global linehtag linentag linedtag markingmatches
- global mainfont canvxmax boldrows boldnamerows fgcolor nullid
+ global linehtag linentag linedtag
+ global mainfont canvxmax boldrows boldnamerows fgcolor nullid nullid2
# listed is 0 for boundary, 1 for normal, 2 for left, 3 for right
set listed [lindex $commitlisted $row]
if {$id eq $nullid} {
set ofill red
+ } elseif {$id eq $nullid2} {
+ set ofill green
} else {
set ofill [expr {$listed != 0? "blue": "white"}]
}
@@ -3412,9 +3492,6 @@ proc drawcmittext {id row col} {
set linedtag($row) [$canv3 create text 3 $y -anchor w -fill $fgcolor \
-text $date -font $mainfont -tags text]
set xr [expr {$xt + [font measure $mainfont $headline]}]
- if {$markingmatches} {
- markrowmatches $row $headline $name
- }
if {$xr > $canvxmax} {
set canvxmax $xr
setcanvscroll
@@ -3423,7 +3500,7 @@ proc drawcmittext {id row col} {
proc drawcmitrow {row} {
global displayorder rowidlist
- global iddrawn
+ global iddrawn markingmatches
global commitinfo parentlist numcommits
global filehighlight fhighlights findstring nhighlights
global hlview vhighlights
@@ -3444,18 +3521,22 @@ proc drawcmitrow {row} {
if {$highlight_related ne "None" && ![info exists rhighlights($row)]} {
askrelhighlight $row $id
}
- if {[info exists iddrawn($id)]} return
- set col [lsearch -exact [lindex $rowidlist $row] $id]
- if {$col < 0} {
- puts "oops, row $row id $id not in list"
- return
+ if {![info exists iddrawn($id)]} {
+ set col [lsearch -exact [lindex $rowidlist $row] $id]
+ if {$col < 0} {
+ puts "oops, row $row id $id not in list"
+ return
+ }
+ if {![info exists commitinfo($id)]} {
+ getcommit $id
+ }
+ assigncolor $id
+ drawcmittext $id $row $col
+ set iddrawn($id) 1
}
- if {![info exists commitinfo($id)]} {
- getcommit $id
+ if {$markingmatches} {
+ markrowmatches $row $id
}
- assigncolor $id
- drawcmittext $id $row $col
- set iddrawn($id) 1
}
proc drawcommits {row {endrow {}}} {
@@ -3973,7 +4054,6 @@ proc dofind {{rev 0}} {
if {!$rev} {
run findmore
} else {
- set findcurline $findstartline
if {$findcurline == 0} {
set findcurline $numcommits
}
@@ -4008,7 +4088,7 @@ proc findprev {} {
proc findmore {} {
global commitdata commitinfo numcommits findstring findpattern findloc
- global findstartline findcurline markingmatches displayorder
+ global findstartline findcurline displayorder
set fldtypes {Headline Author Date Committer CDate Comments}
set l [expr {$findcurline + 1}]
@@ -4026,6 +4106,8 @@ proc findmore {} {
set last 0
for {} {$l < $lim} {incr l} {
set id [lindex $displayorder $l]
+ # shouldn't happen unless git log doesn't give all the commits...
+ if {![info exists commitdata($id)]} continue
if {![doesmatch $commitdata($id)]} continue
if {![info exists commitinfo($id)]} {
getcommit $id
@@ -4034,7 +4116,6 @@ proc findmore {} {
foreach f $info ty $fldtypes {
if {($findloc eq "All fields" || $findloc eq $ty) &&
[doesmatch $f]} {
- set markingmatches 1
findselectline $l
notbusy finding
return 0
@@ -4053,7 +4134,7 @@ proc findmore {} {
proc findmorerev {} {
global commitdata commitinfo numcommits findstring findpattern findloc
- global findstartline findcurline markingmatches displayorder
+ global findstartline findcurline displayorder
set fldtypes {Headline Author Date Committer CDate Comments}
set l $findcurline
@@ -4080,7 +4161,6 @@ proc findmorerev {} {
foreach f $info ty $fldtypes {
if {($findloc eq "All fields" || $findloc eq $ty) &&
[doesmatch $f]} {
- set markingmatches 1
findselectline $l
notbusy finding
return 0
@@ -4098,7 +4178,10 @@ proc findmorerev {} {
}
proc findselectline {l} {
- global findloc commentend ctext
+ global findloc commentend ctext findcurline markingmatches
+
+ set markingmatches 1
+ set findcurline $l
selectline $l 1
if {$findloc == "All fields" || $findloc == "Comments"} {
# highlight the matches in the comments
@@ -4110,10 +4193,13 @@ proc findselectline {l} {
$ctext tag add found "1.0 + $start c" "1.0 + $end c"
}
}
+ drawvisible
}
# mark the bits of a headline or author that match a find string
-proc markmatches {canv l str tag matches font} {
+proc markmatches {canv l str tag matches font row} {
+ global selectedline
+
set bbox [$canv bbox $tag]
set x0 [lindex $bbox 0]
set y0 [lindex $bbox 1]
@@ -4128,6 +4214,9 @@ proc markmatches {canv l str tag matches font} {
[expr {$x0+$xlen+2}] $y1 \
-outline {} -tags [list match$l matches] -fill yellow]
$canv lower $t
+ if {[info exists selectedline] && $row == $selectedline} {
+ $canv raise $t secsel
+ }
}
}
@@ -4582,16 +4671,19 @@ proc goforw {} {
}
proc gettree {id} {
- global treefilelist treeidlist diffids diffmergeid treepending nullid
+ global treefilelist treeidlist diffids diffmergeid treepending
+ global nullid nullid2
set diffids $id
catch {unset diffmergeid}
if {![info exists treefilelist($id)]} {
if {![info exists treepending]} {
- if {$id ne $nullid} {
- set cmd [concat | git ls-tree -r $id]
+ if {$id eq $nullid} {
+ set cmd [list | git ls-files]
+ } elseif {$id eq $nullid2} {
+ set cmd [list | git ls-files --stage -t]
} else {
- set cmd [concat | git ls-files]
+ set cmd [list | git ls-tree -r $id]
}
if {[catch {set gtf [open $cmd r]}]} {
return
@@ -4608,12 +4700,14 @@ proc gettree {id} {
}
proc gettreeline {gtf id} {
- global treefilelist treeidlist treepending cmitmode diffids nullid
+ global treefilelist treeidlist treepending cmitmode diffids nullid nullid2
set nl 0
while {[incr nl] <= 1000 && [gets $gtf line] >= 0} {
- if {$diffids ne $nullid} {
- if {[lindex $line 1] ne "blob"} continue
+ if {$diffids eq $nullid} {
+ set fname $line
+ } else {
+ if {$diffids ne $nullid2 && [lindex $line 1] ne "blob"} continue
set i [string first "\t" $line]
if {$i < 0} continue
set sha1 [lindex $line 2]
@@ -4622,8 +4716,6 @@ proc gettreeline {gtf id} {
set fname [lindex $fname 0]
}
lappend treeidlist($id) $sha1
- } else {
- set fname $line
}
lappend treefilelist($id) $fname
}
@@ -4645,7 +4737,7 @@ proc gettreeline {gtf id} {
}
proc showfile {f} {
- global treefilelist treeidlist diffids nullid
+ global treefilelist treeidlist diffids nullid nullid2
global ctext commentend
set i [lsearch -exact $treefilelist($diffids) $f]
@@ -4653,15 +4745,15 @@ proc showfile {f} {
puts "oops, $f not in list for id $diffids"
return
}
- if {$diffids ne $nullid} {
- set blob [lindex $treeidlist($diffids) $i]
- if {[catch {set bf [open [concat | git cat-file blob $blob] r]} err]} {
- puts "oops, error reading blob $blob: $err"
+ if {$diffids eq $nullid} {
+ if {[catch {set bf [open $f r]} err]} {
+ puts "oops, can't read $f: $err"
return
}
} else {
- if {[catch {set bf [open $f r]} err]} {
- puts "oops, can't read $f: $err"
+ set blob [lindex $treeidlist($diffids) $i]
+ if {[catch {set bf [open [concat | git cat-file blob $blob] r]} err]} {
+ puts "oops, error reading blob $blob: $err"
return
}
}
@@ -4789,11 +4881,13 @@ proc getmergediffline {mdf id np} {
}
proc startdiff {ids} {
- global treediffs diffids treepending diffmergeid nullid
+ global treediffs diffids treepending diffmergeid nullid nullid2
set diffids $ids
catch {unset diffmergeid}
- if {![info exists treediffs($ids)] || [lsearch -exact $ids $nullid] >= 0} {
+ if {![info exists treediffs($ids)] ||
+ [lsearch -exact $ids $nullid] >= 0 ||
+ [lsearch -exact $ids $nullid2] >= 0} {
if {![info exists treepending]} {
gettreediffs $ids
}
@@ -4809,22 +4903,41 @@ proc addtocflist {ids} {
}
proc diffcmd {ids flags} {
- global nullid
+ global nullid nullid2
set i [lsearch -exact $ids $nullid]
+ set j [lsearch -exact $ids $nullid2]
if {$i >= 0} {
- set cmd [concat | git diff-index $flags]
+ if {[llength $ids] > 1 && $j < 0} {
+ # comparing working directory with some specific revision
+ set cmd [concat | git diff-index $flags]
+ if {$i == 0} {
+ lappend cmd -R [lindex $ids 1]
+ } else {
+ lappend cmd [lindex $ids 0]
+ }
+ } else {
+ # comparing working directory with index
+ set cmd [concat | git diff-files $flags]
+ if {$j == 1} {
+ lappend cmd -R
+ }
+ }
+ } elseif {$j >= 0} {
+ set cmd [concat | git diff-index --cached $flags]
if {[llength $ids] > 1} {
+ # comparing index with specific revision
if {$i == 0} {
lappend cmd -R [lindex $ids 1]
} else {
lappend cmd [lindex $ids 0]
}
} else {
+ # comparing index with HEAD
lappend cmd HEAD
}
} else {
- set cmd [concat | git diff-tree --no-commit-id -r $flags $ids]
+ set cmd [concat | git diff-tree -r $flags $ids]
}
return $cmd
}
@@ -4834,7 +4947,7 @@ proc gettreediffs {ids} {
set treepending $ids
set treediff {}
- if {[catch {set gdtf [open [diffcmd $ids {}] r]}]} return
+ if {[catch {set gdtf [open [diffcmd $ids {--no-commit-id}] r]}]} return
fconfigure $gdtf -blocking 0
filerun $gdtf [list gettreediffline $gdtf $ids]
}
@@ -4877,7 +4990,7 @@ proc getblobdiffs {ids} {
global diffinhdr treediffs
set env(GIT_DIFF_OPTS) $diffopts
- if {[catch {set bdf [open [diffcmd $ids {-p -C}] r]} err]} {
+ if {[catch {set bdf [open [diffcmd $ids {-p -C --no-commit-id}] r]} err]} {
puts "error getting diffs: $err"
return
}
@@ -5468,7 +5581,7 @@ proc mstime {} {
proc rowmenu {x y id} {
global rowctxmenu commitrow selectedline rowmenuid curview
- global nullid fakerowmenu mainhead
+ global nullid nullid2 fakerowmenu mainhead
set rowmenuid $id
if {![info exists selectedline]
@@ -5477,7 +5590,7 @@ proc rowmenu {x y id} {
} else {
set state normal
}
- if {$id ne $nullid} {
+ if {$id ne $nullid && $id ne $nullid2} {
set menu $rowctxmenu
$menu entryconfigure 7 -label "Reset $mainhead branch to here"
} else {
@@ -5596,18 +5709,12 @@ proc mkpatchrev {} {
}
proc mkpatchgo {} {
- global patchtop nullid
+ global patchtop nullid nullid2
set oldid [$patchtop.fromsha1 get]
set newid [$patchtop.tosha1 get]
set fname [$patchtop.fname get]
- if {$newid eq $nullid} {
- set cmd [list git diff-index -p $oldid]
- } elseif {$oldid eq $nullid} {
- set cmd [list git diff-index -p -R $newid]
- } else {
- set cmd [list git diff-tree -p $oldid $newid]
- }
+ set cmd [diffcmd [list $oldid $newid] -p]
lappend cmd >$fname &
if {[catch {eval exec $cmd} err]} {
error_popup "Error creating patch: $err"
@@ -7522,6 +7629,8 @@ if {$i >= [llength $argv] && $revtreeargs ne {}} {
}
set nullid "0000000000000000000000000000000000000000"
+set nullid2 "0000000000000000000000000000000000000001"
+
set runq {}
set history {}
@@ -7550,10 +7659,13 @@ set stopped 0
set stuffsaved 0
set patchnum 0
set lookingforhead 0
-set localrow -1
+set localirow -1
+set localfrow -1
set lserial 0
setcoords
makewindow
+# wait for the window to become visible
+tkwait visibility .
wm title . "[file tail $argv0]: [file tail [pwd]]"
readrefs
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index b381692..498b936 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -436,12 +436,11 @@ my %allowed_options = (
our @extra_options = $cgi->param('opt');
if (defined @extra_options) {
- foreach(@extra_options)
- {
- if (not grep(/^$_$/, keys %allowed_options)) {
+ foreach my $opt (@extra_options) {
+ if (not exists $allowed_options{$opt}) {
die_error(undef, "Invalid option parameter");
}
- if (not grep(/^$action$/, @{$allowed_options{$_}})) {
+ if (not grep(/^$action$/, @{$allowed_options{$opt}})) {
die_error(undef, "Invalid option parameter for this action");
}
}
@@ -598,7 +597,6 @@ sub href(%) {
action => "a",
file_name => "f",
file_parent => "fp",
- extra_options => "opt",
hash => "h",
hash_parent => "hp",
hash_base => "hb",
@@ -608,6 +606,7 @@ sub href(%) {
searchtext => "s",
searchtype => "st",
snapshot_format => "sf",
+ extra_options => "opt",
);
my %mapping = @mapping;
@@ -630,7 +629,13 @@ sub href(%) {
for (my $i = 0; $i < @mapping; $i += 2) {
my ($name, $symbol) = ($mapping[$i], $mapping[$i+1]);
if (defined $params{$name}) {
- push @result, $symbol . "=" . esc_param($params{$name});
+ if (ref($params{$name}) eq "ARRAY") {
+ foreach my $par (@{$params{$name}}) {
+ push @result, $symbol . "=" . esc_param($par);
+ }
+ } else {
+ push @result, $symbol . "=" . esc_param($params{$name});
+ }
}
}
$href .= "?" . join(';', @result) if scalar @result;
@@ -890,11 +895,25 @@ sub age_string {
return $age_str;
}
+use constant {
+ S_IFINVALID => 0030000,
+ S_IFGITLINK => 0160000,
+};
+
+# submodule/subproject, a commit object reference
+sub S_ISGITLINK($) {
+ my $mode = shift;
+
+ return (($mode & S_IFMT) == S_IFGITLINK)
+}
+
# convert file mode in octal to symbolic file mode string
sub mode_str {
my $mode = oct shift;
- if (S_ISDIR($mode & S_IFMT)) {
+ if (S_ISGITLINK($mode)) {
+ return 'm---------';
+ } elsif (S_ISDIR($mode & S_IFMT)) {
return 'drwxr-xr-x';
} elsif (S_ISLNK($mode)) {
return 'lrwxrwxrwx';
@@ -920,7 +939,9 @@ sub file_type {
$mode = oct $mode;
}
- if (S_ISDIR($mode & S_IFMT)) {
+ if (S_ISGITLINK($mode)) {
+ return "submodule";
+ } elsif (S_ISDIR($mode & S_IFMT)) {
return "directory";
} elsif (S_ISLNK($mode)) {
return "symlink";
@@ -941,7 +962,9 @@ sub file_type_long {
$mode = oct $mode;
}
- if (S_ISDIR($mode & S_IFMT)) {
+ if (S_ISGITLINK($mode)) {
+ return "submodule";
+ } elsif (S_ISDIR($mode & S_IFMT)) {
return "directory";
} elsif (S_ISLNK($mode)) {
return "symlink";
@@ -2267,9 +2290,17 @@ EOF
printf('<link rel="alternate" title="%s log RSS feed" '.
'href="%s" type="application/rss+xml" />'."\n",
esc_param($project), href(action=>"rss"));
+ printf('<link rel="alternate" title="%s log RSS feed (no merges)" '.
+ 'href="%s" type="application/rss+xml" />'."\n",
+ esc_param($project), href(action=>"rss",
+ extra_options=>"--no-merges"));
printf('<link rel="alternate" title="%s log Atom feed" '.
'href="%s" type="application/atom+xml" />'."\n",
esc_param($project), href(action=>"atom"));
+ printf('<link rel="alternate" title="%s log Atom feed (no merges)" '.
+ 'href="%s" type="application/atom+xml" />'."\n",
+ esc_param($project), href(action=>"atom",
+ extra_options=>"--no-merges"));
} else {
printf('<link rel="alternate" title="%s projects list" '.
'href="%s" type="text/plain; charset=utf-8"/>'."\n",
@@ -2707,6 +2738,20 @@ sub git_print_tree_entry {
"history");
}
print "</td>\n";
+ } else {
+ # unknown object: we can only present history for it
+ # (this includes 'commit' object, i.e. submodule support)
+ print "<td class=\"list\">" .
+ esc_path($t->{'name'}) .
+ "</td>\n";
+ print "<td class=\"link\">";
+ if (defined $hash_base) {
+ print $cgi->a({-href => href(action=>"history",
+ hash_base=>$hash_base,
+ file_name=>"$basedir$t->{'name'}")},
+ "history");
+ }
+ print "</td>\n";
}
}
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 8206436..817f614 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -221,4 +221,34 @@ test_expect_success 'multi-squash only fires up editor once' '
test 1 = $(git show | grep ONCE | wc -l)
'
+test_expect_success 'squash works as expected' '
+ for n in one two three four
+ do
+ echo $n >> file$n &&
+ git add file$n &&
+ git commit -m $n
+ done &&
+ one=$(git rev-parse HEAD~3) &&
+ FAKE_LINES="1 squash 3 2" git rebase -i HEAD~3 &&
+ test $one = $(git rev-parse HEAD~2)
+'
+
+test_expect_success 'interrupted squash works as expected' '
+ for n in one two three four
+ do
+ echo $n >> conflict &&
+ git add conflict &&
+ git commit -m $n
+ done &&
+ one=$(git rev-parse HEAD~3) &&
+ ! FAKE_LINES="1 squash 3 2" git rebase -i HEAD~3 &&
+ (echo one; echo two; echo four) > conflict &&
+ git add conflict &&
+ ! git rebase --continue &&
+ echo resolved > conflict &&
+ git add conflict &&
+ git rebase --continue &&
+ test $one = $(git rev-parse HEAD~2)
+'
+
test_done
diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index 4b920be..6f95305 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -577,7 +577,7 @@ EXPECT_END
test_expect_success \
'L: verify internal tree sorting' \
'git-fast-import <input &&
- git diff --raw L^ L >output &&
+ git diff-tree --abbrev --raw L^ L >output &&
git diff expect output'
###
diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh
index d948724..fa32598 100755
--- a/t/t9500-gitweb-standalone-no-errors.sh
+++ b/t/t9500-gitweb-standalone-no-errors.sh
@@ -521,4 +521,32 @@ test_expect_success \
'gitweb_run "p=.git;a=log"'
test_debug 'cat gitweb.log'
+# ----------------------------------------------------------------------
+# extra options
+
+test_expect_success \
+ 'opt: log --no-merges' \
+ 'gitweb_run "p=.git;a=log;opt=--no-merges"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+ 'opt: atom --no-merges' \
+ 'gitweb_run "p=.git;a=log;opt=--no-merges"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+ 'opt: "file" history --no-merges' \
+ 'gitweb_run "p=.git;a=history;f=file;opt=--no-merges"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+ 'opt: log --no-such-option (invalid option)' \
+ 'gitweb_run "p=.git;a=log;opt=--no-such-option"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+ 'opt: tree --no-merges (invalid option for action)' \
+ 'gitweb_run "p=.git;a=tree;opt=--no-merges"'
+test_debug 'cat gitweb.log'
+
test_done