Sync with 2.49.1
commit
e1775c0646
|
|
@ -0,0 +1,73 @@
|
|||
Git v2.43.7 Release Notes
|
||||
=========================
|
||||
|
||||
This release includes fixes for CVE-2025-27613, CVE-2025-27614,
|
||||
CVE-2025-46334, CVE-2025-46835, CVE-2025-48384, CVE-2025-48385, and
|
||||
CVE-2025-48386.
|
||||
|
||||
Fixes since v2.43.6
|
||||
-------------------
|
||||
|
||||
* CVE-2025-27613, Gitk:
|
||||
|
||||
When a user clones an untrusted repository and runs Gitk without
|
||||
additional command arguments, any writable file can be created and
|
||||
truncated. The option "Support per-file encoding" must have been
|
||||
enabled. The operation "Show origin of this line" is affected as
|
||||
well, regardless of the option being enabled or not.
|
||||
|
||||
* CVE-2025-27614, Gitk:
|
||||
|
||||
A Git repository can be crafted in such a way that a user who has
|
||||
cloned the repository can be tricked into running any script
|
||||
supplied by the attacker by invoking `gitk filename`, where
|
||||
`filename` has a particular structure.
|
||||
|
||||
* CVE-2025-46334, Git GUI (Windows only):
|
||||
|
||||
A malicious repository can ship versions of sh.exe or typical
|
||||
textconv filter programs such as astextplain. On Windows, path
|
||||
lookup can find such executables in the worktree. These programs
|
||||
are invoked when the user selects "Git Bash" or "Browse Files" from
|
||||
the menu.
|
||||
|
||||
* CVE-2025-46835, Git GUI:
|
||||
|
||||
When a user clones an untrusted repository and is tricked into
|
||||
editing a file located in a maliciously named directory in the
|
||||
repository, then Git GUI can create and overwrite any writable
|
||||
file.
|
||||
|
||||
* CVE-2025-48384, Git:
|
||||
|
||||
When reading a config value, Git strips any trailing carriage
|
||||
return and line feed (CRLF). When writing a config entry, values
|
||||
with a trailing CR are not quoted, causing the CR to be lost when
|
||||
the config is later read. When initializing a submodule, if the
|
||||
submodule path contains a trailing CR, the altered path is read
|
||||
resulting in the submodule being checked out to an incorrect
|
||||
location. If a symlink exists that points the altered path to the
|
||||
submodule hooks directory, and the submodule contains an executable
|
||||
post-checkout hook, the script may be unintentionally executed
|
||||
after checkout.
|
||||
|
||||
* CVE-2025-48385, Git:
|
||||
|
||||
When cloning a repository Git knows to optionally fetch a bundle
|
||||
advertised by the remote server, which allows the server-side to
|
||||
offload parts of the clone to a CDN. The Git client does not
|
||||
perform sufficient validation of the advertised bundles, which
|
||||
allows the remote side to perform protocol injection.
|
||||
|
||||
This protocol injection can cause the client to write the fetched
|
||||
bundle to a location controlled by the adversary. The fetched
|
||||
content is fully controlled by the server, which can in the worst
|
||||
case lead to arbitrary code execution.
|
||||
|
||||
* CVE-2025-48386, Git:
|
||||
|
||||
The wincred credential helper uses a static buffer (`target`) as a
|
||||
unique key for storing and comparing against internal storage. This
|
||||
credential helper does not properly bounds check the available
|
||||
space remaining in the buffer before appending to it with
|
||||
`wcsncat()`, leading to potential buffer overflows.
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
Git v2.44.4 Release Notes
|
||||
=========================
|
||||
|
||||
This release merges up the fixes that appears in v2.43.7 to address
|
||||
the following CVEs: CVE-2025-27613, CVE-2025-27614, CVE-2025-46334,
|
||||
CVE-2025-46835, CVE-2025-48384, CVE-2025-48385, and CVE-2025-48386.
|
||||
See the release notes for v2.43.7 for details.
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
Git v2.45.4 Release Notes
|
||||
=========================
|
||||
|
||||
This release merges up the fixes that appears in v2.43.7, and v2.44.4
|
||||
to address the following CVEs: CVE-2025-27613, CVE-2025-27614,
|
||||
CVE-2025-46334, CVE-2025-46835, CVE-2025-48384, CVE-2025-48385, and
|
||||
CVE-2025-48386. See the release notes for v2.43.7 for details.
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
Git v2.46.4 Release Notes
|
||||
=========================
|
||||
|
||||
This release merges up the fixes that appears in v2.43.7, v2.44.4, and
|
||||
v2.45.4 to address the following CVEs: CVE-2025-27613, CVE-2025-27614,
|
||||
CVE-2025-46334, CVE-2025-46835, CVE-2025-48384, CVE-2025-48385, and
|
||||
CVE-2025-48386. See the release notes for v2.43.7 for details.
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
Git v2.47.3 Release Notes
|
||||
=========================
|
||||
|
||||
This release merges up the fixes that appears in v2.43.7, v2.44.4,
|
||||
v2.45.4, and v2.46.4 to address the following CVEs: CVE-2025-27613,
|
||||
CVE-2025-27614, CVE-2025-46334, CVE-2025-46835, CVE-2025-48384,
|
||||
CVE-2025-48385, and CVE-2025-48386. See the release notes for v2.43.7
|
||||
for details.
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
Git v2.48.2 Release Notes
|
||||
=========================
|
||||
|
||||
This release merges up the fixes that appears in v2.43.7, v2.44.4,
|
||||
v2.45.4, v2.46.4, and v2.47.3 to address the following CVEs:
|
||||
CVE-2025-27613, CVE-2025-27614, CVE-2025-46334, CVE-2025-46835,
|
||||
CVE-2025-48384, CVE-2025-48385, and CVE-2025-48386. See the release
|
||||
notes for v2.43.7 for details.
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
Git v2.49.1 Release Notes
|
||||
=========================
|
||||
|
||||
This release merges up the fixes that appear in v2.43.7, v2.44.4,
|
||||
v2.45.4, v2.46.4, v2.47.3, and v2.48.2 to address the following CVEs:
|
||||
CVE-2025-27613, CVE-2025-27614, CVE-2025-46334, CVE-2025-46835,
|
||||
CVE-2025-48384, CVE-2025-48385, and CVE-2025-48386. See the release
|
||||
notes for v2.43.7 for details.
|
||||
|
||||
It also contains some updates to various CI bits to work around
|
||||
and/or to adjust to the deprecation of use of Ubuntu 20.04 GitHub
|
||||
Actions CI, updates to to Fedora base image.
|
||||
22
bundle-uri.c
22
bundle-uri.c
|
|
@ -297,6 +297,28 @@ static int download_https_uri_to_file(const char *file, const char *uri)
|
|||
struct strbuf line = STRBUF_INIT;
|
||||
int found_get = 0;
|
||||
|
||||
/*
|
||||
* The protocol we speak with git-remote-https(1) uses a space to
|
||||
* separate between URI and file, so the URI itself must not contain a
|
||||
* space. If it did, an adversary could change the location where the
|
||||
* downloaded file is being written to.
|
||||
*
|
||||
* Similarly, we use newlines to separate commands from one another.
|
||||
* Consequently, neither the URI nor the file must contain a newline or
|
||||
* otherwise an adversary could inject arbitrary commands.
|
||||
*
|
||||
* TODO: Restricting newlines in the target paths may break valid
|
||||
* usecases, even if those are a bit more on the esoteric side.
|
||||
* If this ever becomes a problem we should probably think about
|
||||
* alternatives. One alternative could be to use NUL-delimited
|
||||
* requests in git-remote-http(1). Another alternative could be
|
||||
* to use URL quoting.
|
||||
*/
|
||||
if (strpbrk(uri, " \n"))
|
||||
return error("bundle-uri: URI is malformed: '%s'", file);
|
||||
if (strchr(file, '\n'))
|
||||
return error("bundle-uri: filename is malformed: '%s'", file);
|
||||
|
||||
strvec_pushl(&cp.args, "git-remote-https", uri, NULL);
|
||||
cp.err = -1;
|
||||
cp.in = -1;
|
||||
|
|
|
|||
2
config.c
2
config.c
|
|
@ -2940,7 +2940,7 @@ static ssize_t write_pair(int fd, const char *key, const char *value,
|
|||
if (value[0] == ' ')
|
||||
quote = "\"";
|
||||
for (i = 0; value[i]; i++)
|
||||
if (value[i] == ';' || value[i] == '#')
|
||||
if (value[i] == ';' || value[i] == '#' || value[i] == '\r')
|
||||
quote = "\"";
|
||||
if (i && value[i - 1] == ' ')
|
||||
quote = "\"";
|
||||
|
|
|
|||
|
|
@ -39,6 +39,14 @@ static void *xmalloc(size_t size)
|
|||
static WCHAR *wusername, *password, *protocol, *host, *path, target[1024],
|
||||
*password_expiry_utc, *oauth_refresh_token;
|
||||
|
||||
static void target_append(const WCHAR *src)
|
||||
{
|
||||
size_t avail = ARRAY_SIZE(target) - wcslen(target) - 1; /* -1 for NUL */
|
||||
if (avail < wcslen(src))
|
||||
die("target buffer overflow");
|
||||
wcsncat(target, src, avail);
|
||||
}
|
||||
|
||||
static void write_item(const char *what, LPCWSTR wbuf, int wlen)
|
||||
{
|
||||
char *buf;
|
||||
|
|
@ -330,17 +338,17 @@ int main(int argc, char *argv[])
|
|||
|
||||
/* prepare 'target', the unique key for the credential */
|
||||
wcscpy(target, L"git:");
|
||||
wcsncat(target, protocol, ARRAY_SIZE(target));
|
||||
wcsncat(target, L"://", ARRAY_SIZE(target));
|
||||
target_append(protocol);
|
||||
target_append(L"://");
|
||||
if (wusername) {
|
||||
wcsncat(target, wusername, ARRAY_SIZE(target));
|
||||
wcsncat(target, L"@", ARRAY_SIZE(target));
|
||||
target_append(wusername);
|
||||
target_append(L"@");
|
||||
}
|
||||
if (host)
|
||||
wcsncat(target, host, ARRAY_SIZE(target));
|
||||
target_append(host);
|
||||
if (path) {
|
||||
wcsncat(target, L"/", ARRAY_SIZE(target));
|
||||
wcsncat(target, path, ARRAY_SIZE(target));
|
||||
target_append(L"/");
|
||||
target_append(path);
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "get"))
|
||||
|
|
|
|||
|
|
@ -77,99 +77,178 @@ proc is_Cygwin {} {
|
|||
|
||||
######################################################################
|
||||
##
|
||||
## PATH lookup
|
||||
## PATH lookup. Sanitize $PATH, assure exec/open use only that
|
||||
|
||||
set _search_path {}
|
||||
proc _which {what args} {
|
||||
global env _search_exe _search_path
|
||||
|
||||
if {$_search_path eq {}} {
|
||||
if {[is_Windows]} {
|
||||
set gitguidir [file dirname [info script]]
|
||||
regsub -all ";" $gitguidir "\\;" gitguidir
|
||||
set env(PATH) "$gitguidir;$env(PATH)"
|
||||
set _search_path [split $env(PATH) {;}]
|
||||
# Skip empty `PATH` elements
|
||||
set _search_path [lsearch -all -inline -not -exact \
|
||||
$_search_path ""]
|
||||
set _search_exe .exe
|
||||
} else {
|
||||
set _search_path [split $env(PATH) :]
|
||||
set _search_exe {}
|
||||
}
|
||||
}
|
||||
|
||||
if {[is_Windows] && [lsearch -exact $args -script] >= 0} {
|
||||
set suffix {}
|
||||
} else {
|
||||
set suffix $_search_exe
|
||||
}
|
||||
|
||||
foreach p $_search_path {
|
||||
set p [file join $p $what$suffix]
|
||||
if {[file exists $p]} {
|
||||
return [file normalize $p]
|
||||
}
|
||||
}
|
||||
return {}
|
||||
if {[is_Windows]} {
|
||||
set _path_sep {;}
|
||||
set _search_exe .exe
|
||||
} else {
|
||||
set _path_sep {:}
|
||||
set _search_exe {}
|
||||
}
|
||||
|
||||
proc sanitize_command_line {command_line from_index} {
|
||||
set i $from_index
|
||||
while {$i < [llength $command_line]} {
|
||||
set cmd [lindex $command_line $i]
|
||||
if {[llength [file split $cmd]] < 2} {
|
||||
set fullpath [_which $cmd]
|
||||
if {$fullpath eq ""} {
|
||||
throw {NOT-FOUND} "$cmd not found in PATH"
|
||||
}
|
||||
lset command_line $i $fullpath
|
||||
if {[is_Windows]} {
|
||||
set gitguidir [file dirname [info script]]
|
||||
regsub -all ";" $gitguidir "\\;" gitguidir
|
||||
set env(PATH) "$gitguidir;$env(PATH)"
|
||||
}
|
||||
|
||||
set _search_path {}
|
||||
set _path_seen [dict create]
|
||||
foreach p [split $env(PATH) $_path_sep] {
|
||||
# Keep only absolute paths, getting rid of ., empty, etc.
|
||||
if {[file pathtype $p] ne {absolute}} {
|
||||
continue
|
||||
}
|
||||
# Keep only the first occurence of any duplicates.
|
||||
set norm_p [file normalize $p]
|
||||
if {[dict exists $_path_seen $norm_p]} {
|
||||
continue
|
||||
}
|
||||
dict set _path_seen $norm_p 1
|
||||
lappend _search_path $norm_p
|
||||
}
|
||||
unset _path_seen
|
||||
|
||||
set env(PATH) [join $_search_path $_path_sep]
|
||||
|
||||
if {[is_Windows]} {
|
||||
proc _which {what args} {
|
||||
global _search_exe _search_path
|
||||
|
||||
if {[lsearch -exact $args -script] >= 0} {
|
||||
set suffix {}
|
||||
} elseif {[string match *$_search_exe [string tolower $what]]} {
|
||||
# The search string already has the file extension
|
||||
set suffix {}
|
||||
} else {
|
||||
set suffix $_search_exe
|
||||
}
|
||||
|
||||
# handle piped commands, e.g. `exec A | B`
|
||||
for {incr i} {$i < [llength $command_line]} {incr i} {
|
||||
if {[lindex $command_line $i] eq "|"} {
|
||||
foreach p $_search_path {
|
||||
set p [file join $p $what$suffix]
|
||||
if {[file exists $p]} {
|
||||
return [file normalize $p]
|
||||
}
|
||||
}
|
||||
return {}
|
||||
}
|
||||
|
||||
proc sanitize_command_line {command_line from_index} {
|
||||
set i $from_index
|
||||
while {$i < [llength $command_line]} {
|
||||
set cmd [lindex $command_line $i]
|
||||
if {[llength [file split $cmd]] < 2} {
|
||||
set fullpath [_which $cmd]
|
||||
if {$fullpath eq ""} {
|
||||
throw {NOT-FOUND} "$cmd not found in PATH"
|
||||
}
|
||||
lset command_line $i $fullpath
|
||||
}
|
||||
|
||||
# handle piped commands, e.g. `exec A | B`
|
||||
for {incr i} {$i < [llength $command_line]} {incr i} {
|
||||
if {[lindex $command_line $i] eq "|"} {
|
||||
incr i
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return $command_line
|
||||
}
|
||||
|
||||
# Override `exec` to avoid unsafe PATH lookup
|
||||
|
||||
rename exec real_exec
|
||||
|
||||
proc exec {args} {
|
||||
# skip options
|
||||
for {set i 0} {$i < [llength $args]} {incr i} {
|
||||
set arg [lindex $args $i]
|
||||
if {$arg eq "--"} {
|
||||
incr i
|
||||
break
|
||||
}
|
||||
if {[string range $arg 0 0] ne "-"} {
|
||||
break
|
||||
}
|
||||
}
|
||||
set args [sanitize_command_line $args $i]
|
||||
uplevel 1 real_exec $args
|
||||
}
|
||||
|
||||
# Override `open` to avoid unsafe PATH lookup
|
||||
|
||||
rename open real_open
|
||||
|
||||
proc open {args} {
|
||||
set arg0 [lindex $args 0]
|
||||
if {[string range $arg0 0 0] eq "|"} {
|
||||
set command_line [string trim [string range $arg0 1 end]]
|
||||
lset args 0 "| [sanitize_command_line $command_line 0]"
|
||||
}
|
||||
uplevel 1 real_open $args
|
||||
}
|
||||
|
||||
} else {
|
||||
# On non-Windows platforms, auto_execok, exec, and open are safe, and will
|
||||
# use the sanitized search path. But, we need _which for these.
|
||||
|
||||
proc _which {what args} {
|
||||
return [lindex [auto_execok $what] 0]
|
||||
}
|
||||
return $command_line
|
||||
}
|
||||
|
||||
# Override `exec` to avoid unsafe PATH lookup
|
||||
# Wrap exec/open to sanitize arguments
|
||||
|
||||
rename exec real_exec
|
||||
|
||||
proc exec {args} {
|
||||
# skip options
|
||||
for {set i 0} {$i < [llength $args]} {incr i} {
|
||||
set arg [lindex $args $i]
|
||||
if {$arg eq "--"} {
|
||||
incr i
|
||||
break
|
||||
}
|
||||
if {[string range $arg 0 0] ne "-"} {
|
||||
break
|
||||
}
|
||||
}
|
||||
set args [sanitize_command_line $args $i]
|
||||
uplevel 1 real_exec $args
|
||||
# unsafe arguments begin with redirections or the pipe or background operators
|
||||
proc is_arg_unsafe {arg} {
|
||||
regexp {^([<|>&]|2>)} $arg
|
||||
}
|
||||
|
||||
# Override `open` to avoid unsafe PATH lookup
|
||||
|
||||
rename open real_open
|
||||
|
||||
proc open {args} {
|
||||
set arg0 [lindex $args 0]
|
||||
if {[string range $arg0 0 0] eq "|"} {
|
||||
set command_line [string trim [string range $arg0 1 end]]
|
||||
lset args 0 "| [sanitize_command_line $command_line 0]"
|
||||
proc make_arg_safe {arg} {
|
||||
if {[is_arg_unsafe $arg]} {
|
||||
set arg [file join . $arg]
|
||||
}
|
||||
uplevel 1 real_open $args
|
||||
return $arg
|
||||
}
|
||||
|
||||
proc make_arglist_safe {arglist} {
|
||||
set res {}
|
||||
foreach arg $arglist {
|
||||
lappend res [make_arg_safe $arg]
|
||||
}
|
||||
return $res
|
||||
}
|
||||
|
||||
# executes one command
|
||||
# no redirections or pipelines are possible
|
||||
# cmd is a list that specifies the command and its arguments
|
||||
# calls `exec` and returns its value
|
||||
proc safe_exec {cmd} {
|
||||
eval exec [make_arglist_safe $cmd]
|
||||
}
|
||||
|
||||
# executes one command in the background
|
||||
# no redirections or pipelines are possible
|
||||
# cmd is a list that specifies the command and its arguments
|
||||
# calls `exec` and returns its value
|
||||
proc safe_exec_bg {cmd} {
|
||||
eval exec [make_arglist_safe $cmd] &
|
||||
}
|
||||
|
||||
proc safe_open_file {filename flags} {
|
||||
# a file name starting with "|" would attempt to run a process
|
||||
# but such a file name must be treated as a relative path
|
||||
# hide the "|" behind "./"
|
||||
if {[string index $filename 0] eq "|"} {
|
||||
set filename [file join . $filename]
|
||||
}
|
||||
open $filename $flags
|
||||
}
|
||||
|
||||
# End exec/open wrappers
|
||||
|
||||
######################################################################
|
||||
##
|
||||
## locate our library
|
||||
|
|
@ -270,11 +349,11 @@ unset oguimsg
|
|||
|
||||
if {[tk windowingsystem] eq "aqua"} {
|
||||
catch {
|
||||
exec osascript -e [format {
|
||||
safe_exec [list osascript -e [format {
|
||||
tell application "System Events"
|
||||
set frontmost of processes whose unix id is %d to true
|
||||
end tell
|
||||
} [pid]]
|
||||
} [pid]]]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -304,15 +383,37 @@ if {$_trace >= 0} {
|
|||
# branches).
|
||||
set _last_merged_branch {}
|
||||
|
||||
proc shellpath {} {
|
||||
global _shellpath env
|
||||
if {[string match @@* $_shellpath]} {
|
||||
if {[info exists env(SHELL)]} {
|
||||
return $env(SHELL)
|
||||
} else {
|
||||
return /bin/sh
|
||||
}
|
||||
# for testing, allow unconfigured _shellpath
|
||||
if {[string match @@* $_shellpath]} {
|
||||
if {[info exists env(SHELL)]} {
|
||||
set _shellpath $env(SHELL)
|
||||
} else {
|
||||
set _shellpath /bin/sh
|
||||
}
|
||||
}
|
||||
|
||||
if {[is_Windows]} {
|
||||
set _shellpath [safe_exec [list cygpath -m $_shellpath]]
|
||||
}
|
||||
|
||||
if {![file executable $_shellpath] || \
|
||||
!([file pathtype $_shellpath] eq {absolute})} {
|
||||
set errmsg "The defined shell ('$_shellpath') is not usable, \
|
||||
it must be an absolute path to an executable."
|
||||
puts stderr $errmsg
|
||||
|
||||
catch {wm withdraw .}
|
||||
tk_messageBox \
|
||||
-icon error \
|
||||
-type ok \
|
||||
-title "git-gui: configuration error" \
|
||||
-message $errmsg
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
proc shellpath {} {
|
||||
global _shellpath
|
||||
return $_shellpath
|
||||
}
|
||||
|
||||
|
|
@ -494,7 +595,7 @@ proc _git_cmd {name} {
|
|||
# Tcl on Windows doesn't know it.
|
||||
#
|
||||
set p [gitexec git-$name]
|
||||
set f [open $p r]
|
||||
set f [safe_open_file $p r]
|
||||
set s [gets $f]
|
||||
close $f
|
||||
|
||||
|
|
@ -524,32 +625,14 @@ proc _git_cmd {name} {
|
|||
return $v
|
||||
}
|
||||
|
||||
# Test a file for a hashbang to identify executable scripts on Windows.
|
||||
proc is_shellscript {filename} {
|
||||
if {![file exists $filename]} {return 0}
|
||||
set f [open $filename r]
|
||||
fconfigure $f -encoding binary
|
||||
set magic [read $f 2]
|
||||
close $f
|
||||
return [expr {$magic eq "#!"}]
|
||||
}
|
||||
|
||||
# Run a command connected via pipes on stdout.
|
||||
# Run a shell command connected via pipes on stdout.
|
||||
# This is for use with textconv filters and uses sh -c "..." to allow it to
|
||||
# contain a command with arguments. On windows we must check for shell
|
||||
# scripts specifically otherwise just call the filter command.
|
||||
# contain a command with arguments. We presume this
|
||||
# to be a shellscript that the configured shell (/bin/sh by default) knows
|
||||
# how to run.
|
||||
proc open_cmd_pipe {cmd path} {
|
||||
global env
|
||||
if {![file executable [shellpath]]} {
|
||||
set exe [auto_execok [lindex $cmd 0]]
|
||||
if {[is_shellscript [lindex $exe 0]]} {
|
||||
set run [linsert [auto_execok sh] end -c "$cmd \"\$0\"" $path]
|
||||
} else {
|
||||
set run [concat $exe [lrange $cmd 1 end] $path]
|
||||
}
|
||||
} else {
|
||||
set run [list [shellpath] -c "$cmd \"\$0\"" $path]
|
||||
}
|
||||
set run [list [shellpath] -c "$cmd \"\$0\"" $path]
|
||||
set run [make_arglist_safe $run]
|
||||
return [open |$run r]
|
||||
}
|
||||
|
||||
|
|
@ -559,7 +642,7 @@ proc _lappend_nice {cmd_var} {
|
|||
|
||||
if {![info exists _nice]} {
|
||||
set _nice [_which nice]
|
||||
if {[catch {exec $_nice git version}]} {
|
||||
if {[catch {safe_exec [list $_nice git version]}]} {
|
||||
set _nice {}
|
||||
} elseif {[is_Windows] && [file dirname $_nice] ne [file dirname $::_git]} {
|
||||
set _nice {}
|
||||
|
|
@ -571,7 +654,11 @@ proc _lappend_nice {cmd_var} {
|
|||
}
|
||||
|
||||
proc git {args} {
|
||||
set fd [eval [list git_read] $args]
|
||||
git_redir $args {}
|
||||
}
|
||||
|
||||
proc git_redir {cmd redir} {
|
||||
set fd [git_read $cmd $redir]
|
||||
fconfigure $fd -translation binary -encoding utf-8
|
||||
set result [string trimright [read $fd] "\n"]
|
||||
close $fd
|
||||
|
|
@ -581,88 +668,47 @@ proc git {args} {
|
|||
return $result
|
||||
}
|
||||
|
||||
proc _open_stdout_stderr {cmd} {
|
||||
_trace_exec $cmd
|
||||
proc safe_open_command {cmd {redir {}}} {
|
||||
set cmd [make_arglist_safe $cmd]
|
||||
_trace_exec [concat $cmd $redir]
|
||||
if {[catch {
|
||||
set fd [open [concat [list | ] $cmd] r]
|
||||
} err]} {
|
||||
if { [lindex $cmd end] eq {2>@1}
|
||||
&& $err eq {can not find channel named "1"}
|
||||
} {
|
||||
# Older versions of Tcl 8.4 don't have this 2>@1 IO
|
||||
# redirect operator. Fallback to |& cat for those.
|
||||
# The command was not actually started, so its safe
|
||||
# to try to start it a second time.
|
||||
#
|
||||
set fd [open [concat \
|
||||
[list | ] \
|
||||
[lrange $cmd 0 end-1] \
|
||||
[list |& cat] \
|
||||
] r]
|
||||
} else {
|
||||
error $err
|
||||
}
|
||||
set fd [open [concat [list | ] $cmd $redir] r]
|
||||
} err]} {
|
||||
error $err
|
||||
}
|
||||
fconfigure $fd -eofchar {}
|
||||
return $fd
|
||||
}
|
||||
|
||||
proc git_read {args} {
|
||||
set opt [list]
|
||||
proc git_read {cmd {redir {}}} {
|
||||
set cmdp [_git_cmd [lindex $cmd 0]]
|
||||
set cmd [lrange $cmd 1 end]
|
||||
|
||||
while {1} {
|
||||
switch -- [lindex $args 0] {
|
||||
--nice {
|
||||
_lappend_nice opt
|
||||
}
|
||||
|
||||
--stderr {
|
||||
lappend args 2>@1
|
||||
}
|
||||
|
||||
default {
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
set args [lrange $args 1 end]
|
||||
}
|
||||
|
||||
set cmdp [_git_cmd [lindex $args 0]]
|
||||
set args [lrange $args 1 end]
|
||||
|
||||
return [_open_stdout_stderr [concat $opt $cmdp $args]]
|
||||
return [safe_open_command [concat $cmdp $cmd] $redir]
|
||||
}
|
||||
|
||||
proc git_write {args} {
|
||||
proc git_read_nice {cmd} {
|
||||
set opt [list]
|
||||
|
||||
while {1} {
|
||||
switch -- [lindex $args 0] {
|
||||
--nice {
|
||||
_lappend_nice opt
|
||||
}
|
||||
_lappend_nice opt
|
||||
|
||||
default {
|
||||
break
|
||||
}
|
||||
set cmdp [_git_cmd [lindex $cmd 0]]
|
||||
set cmd [lrange $cmd 1 end]
|
||||
|
||||
}
|
||||
return [safe_open_command [concat $opt $cmdp $cmd]]
|
||||
}
|
||||
|
||||
set args [lrange $args 1 end]
|
||||
}
|
||||
proc git_write {cmd} {
|
||||
set cmd [make_arglist_safe $cmd]
|
||||
set cmdp [_git_cmd [lindex $cmd 0]]
|
||||
set cmd [lrange $cmd 1 end]
|
||||
|
||||
set cmdp [_git_cmd [lindex $args 0]]
|
||||
set args [lrange $args 1 end]
|
||||
|
||||
_trace_exec [concat $opt $cmdp $args]
|
||||
return [open [concat [list | ] $opt $cmdp $args] w]
|
||||
_trace_exec [concat $cmdp $cmd]
|
||||
return [open [concat [list | ] $cmdp $cmd] w]
|
||||
}
|
||||
|
||||
proc githook_read {hook_name args} {
|
||||
set cmd [concat git hook run --ignore-missing $hook_name -- $args 2>@1]
|
||||
return [_open_stdout_stderr $cmd]
|
||||
git_read [concat [list hook run --ignore-missing $hook_name --] $args] [list 2>@1]
|
||||
}
|
||||
|
||||
proc kill_file_process {fd} {
|
||||
|
|
@ -670,9 +716,9 @@ proc kill_file_process {fd} {
|
|||
|
||||
catch {
|
||||
if {[is_Windows]} {
|
||||
exec taskkill /pid $process
|
||||
safe_exec [list taskkill /pid $process]
|
||||
} else {
|
||||
exec kill $process
|
||||
safe_exec [list kill $process]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -698,7 +744,7 @@ proc sq {value} {
|
|||
proc load_current_branch {} {
|
||||
global current_branch is_detached
|
||||
|
||||
set fd [open [gitdir HEAD] r]
|
||||
set fd [safe_open_file [gitdir HEAD] r]
|
||||
fconfigure $fd -translation binary -encoding utf-8
|
||||
if {[gets $fd ref] < 1} {
|
||||
set ref {}
|
||||
|
|
@ -1068,7 +1114,7 @@ You are using [git-version]:
|
|||
## configure our library
|
||||
|
||||
set idx [file join $oguilib tclIndex]
|
||||
if {[catch {set fd [open $idx r]} err]} {
|
||||
if {[catch {set fd [safe_open_file $idx r]} err]} {
|
||||
catch {wm withdraw .}
|
||||
tk_messageBox \
|
||||
-icon error \
|
||||
|
|
@ -1106,53 +1152,30 @@ unset -nocomplain idx fd
|
|||
##
|
||||
## config file parsing
|
||||
|
||||
git-version proc _parse_config {arr_name args} {
|
||||
>= 1.5.3 {
|
||||
upvar $arr_name arr
|
||||
array unset arr
|
||||
set buf {}
|
||||
catch {
|
||||
set fd_rc [eval \
|
||||
[list git_read config] \
|
||||
$args \
|
||||
[list --null --list]]
|
||||
fconfigure $fd_rc -translation binary -encoding utf-8
|
||||
set buf [read $fd_rc]
|
||||
close $fd_rc
|
||||
}
|
||||
foreach line [split $buf "\0"] {
|
||||
if {[regexp {^([^\n]+)\n(.*)$} $line line name value]} {
|
||||
if {[is_many_config $name]} {
|
||||
lappend arr($name) $value
|
||||
} else {
|
||||
set arr($name) $value
|
||||
}
|
||||
} elseif {[regexp {^([^\n]+)$} $line line name]} {
|
||||
# no value given, but interpreting them as
|
||||
# boolean will be handled as true
|
||||
set arr($name) {}
|
||||
}
|
||||
}
|
||||
proc _parse_config {arr_name args} {
|
||||
upvar $arr_name arr
|
||||
array unset arr
|
||||
set buf {}
|
||||
catch {
|
||||
set fd_rc [git_read \
|
||||
[concat config \
|
||||
$args \
|
||||
--null --list]]
|
||||
fconfigure $fd_rc -translation binary -encoding utf-8
|
||||
set buf [read $fd_rc]
|
||||
close $fd_rc
|
||||
}
|
||||
default {
|
||||
upvar $arr_name arr
|
||||
array unset arr
|
||||
catch {
|
||||
set fd_rc [eval [list git_read config --list] $args]
|
||||
while {[gets $fd_rc line] >= 0} {
|
||||
if {[regexp {^([^=]+)=(.*)$} $line line name value]} {
|
||||
if {[is_many_config $name]} {
|
||||
lappend arr($name) $value
|
||||
} else {
|
||||
set arr($name) $value
|
||||
}
|
||||
} elseif {[regexp {^([^=]+)$} $line line name]} {
|
||||
# no value given, but interpreting them as
|
||||
# boolean will be handled as true
|
||||
set arr($name) {}
|
||||
}
|
||||
foreach line [split $buf "\0"] {
|
||||
if {[regexp {^([^\n]+)\n(.*)$} $line line name value]} {
|
||||
if {[is_many_config $name]} {
|
||||
lappend arr($name) $value
|
||||
} else {
|
||||
set arr($name) $value
|
||||
}
|
||||
close $fd_rc
|
||||
} elseif {[regexp {^([^\n]+)$} $line line name]} {
|
||||
# no value given, but interpreting them as
|
||||
# boolean will be handled as true
|
||||
set arr($name) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1427,7 +1450,7 @@ proc repository_state {ctvar hdvar mhvar} {
|
|||
set merge_head [gitdir MERGE_HEAD]
|
||||
if {[file exists $merge_head]} {
|
||||
set ct merge
|
||||
set fd_mh [open $merge_head r]
|
||||
set fd_mh [safe_open_file $merge_head r]
|
||||
while {[gets $fd_mh line] >= 0} {
|
||||
lappend mh $line
|
||||
}
|
||||
|
|
@ -1446,7 +1469,7 @@ proc PARENT {} {
|
|||
return $p
|
||||
}
|
||||
if {$empty_tree eq {}} {
|
||||
set empty_tree [git mktree << {}]
|
||||
set empty_tree [git_redir [list mktree] [list << {}]]
|
||||
}
|
||||
return $empty_tree
|
||||
}
|
||||
|
|
@ -1505,12 +1528,12 @@ proc rescan {after {honor_trustmtime 1}} {
|
|||
} else {
|
||||
set rescan_active 1
|
||||
ui_status [mc "Refreshing file status..."]
|
||||
set fd_rf [git_read update-index \
|
||||
set fd_rf [git_read [list update-index \
|
||||
-q \
|
||||
--unmerged \
|
||||
--ignore-missing \
|
||||
--refresh \
|
||||
]
|
||||
]]
|
||||
fconfigure $fd_rf -blocking 0 -translation binary
|
||||
fileevent $fd_rf readable \
|
||||
[list rescan_stage2 $fd_rf $after]
|
||||
|
|
@ -1550,11 +1573,11 @@ proc rescan_stage2 {fd after} {
|
|||
set rescan_active 2
|
||||
ui_status [mc "Scanning for modified files ..."]
|
||||
if {[git-version >= "1.7.2"]} {
|
||||
set fd_di [git_read diff-index --cached --ignore-submodules=dirty -z [PARENT]]
|
||||
set fd_di [git_read [list diff-index --cached --ignore-submodules=dirty -z [PARENT]]]
|
||||
} else {
|
||||
set fd_di [git_read diff-index --cached -z [PARENT]]
|
||||
set fd_di [git_read [list diff-index --cached -z [PARENT]]]
|
||||
}
|
||||
set fd_df [git_read diff-files -z]
|
||||
set fd_df [git_read [list diff-files -z]]
|
||||
|
||||
fconfigure $fd_di -blocking 0 -translation binary -encoding binary
|
||||
fconfigure $fd_df -blocking 0 -translation binary -encoding binary
|
||||
|
|
@ -1563,7 +1586,7 @@ proc rescan_stage2 {fd after} {
|
|||
fileevent $fd_df readable [list read_diff_files $fd_df $after]
|
||||
|
||||
if {[is_config_true gui.displayuntracked]} {
|
||||
set fd_lo [eval git_read ls-files --others -z $ls_others]
|
||||
set fd_lo [git_read [concat ls-files --others -z $ls_others]]
|
||||
fconfigure $fd_lo -blocking 0 -translation binary -encoding binary
|
||||
fileevent $fd_lo readable [list read_ls_others $fd_lo $after]
|
||||
incr rescan_active
|
||||
|
|
@ -1575,7 +1598,7 @@ proc load_message {file {encoding {}}} {
|
|||
|
||||
set f [gitdir $file]
|
||||
if {[file isfile $f]} {
|
||||
if {[catch {set fd [open $f r]}]} {
|
||||
if {[catch {set fd [safe_open_file $f r]}]} {
|
||||
return 0
|
||||
}
|
||||
fconfigure $fd -eofchar {}
|
||||
|
|
@ -1599,23 +1622,23 @@ proc run_prepare_commit_msg_hook {} {
|
|||
# it will be .git/MERGE_MSG (merge), .git/SQUASH_MSG (squash), or an
|
||||
# empty file but existent file.
|
||||
|
||||
set fd_pcm [open [gitdir PREPARE_COMMIT_MSG] a]
|
||||
set fd_pcm [safe_open_file [gitdir PREPARE_COMMIT_MSG] a]
|
||||
|
||||
if {[file isfile [gitdir MERGE_MSG]]} {
|
||||
set pcm_source "merge"
|
||||
set fd_mm [open [gitdir MERGE_MSG] r]
|
||||
set fd_mm [safe_open_file [gitdir MERGE_MSG] r]
|
||||
fconfigure $fd_mm -encoding utf-8
|
||||
puts -nonewline $fd_pcm [read $fd_mm]
|
||||
close $fd_mm
|
||||
} elseif {[file isfile [gitdir SQUASH_MSG]]} {
|
||||
set pcm_source "squash"
|
||||
set fd_sm [open [gitdir SQUASH_MSG] r]
|
||||
set fd_sm [safe_open_file [gitdir SQUASH_MSG] r]
|
||||
fconfigure $fd_sm -encoding utf-8
|
||||
puts -nonewline $fd_pcm [read $fd_sm]
|
||||
close $fd_sm
|
||||
} elseif {[file isfile [get_config commit.template]]} {
|
||||
set pcm_source "template"
|
||||
set fd_sm [open [get_config commit.template] r]
|
||||
set fd_sm [safe_open_file [get_config commit.template] r]
|
||||
fconfigure $fd_sm -encoding utf-8
|
||||
puts -nonewline $fd_pcm [read $fd_sm]
|
||||
close $fd_sm
|
||||
|
|
@ -2205,7 +2228,7 @@ proc do_gitk {revs {is_submodule false}} {
|
|||
unset env(GIT_DIR)
|
||||
unset env(GIT_WORK_TREE)
|
||||
}
|
||||
eval exec $cmd $revs "--" "--" &
|
||||
safe_exec_bg [concat $cmd $revs "--" "--"]
|
||||
|
||||
set env(GIT_DIR) $_gitdir
|
||||
set env(GIT_WORK_TREE) $_gitworktree
|
||||
|
|
@ -2242,7 +2265,7 @@ proc do_git_gui {} {
|
|||
set pwd [pwd]
|
||||
cd $current_diff_path
|
||||
|
||||
eval exec $exe gui &
|
||||
safe_exec_bg [concat $exe gui]
|
||||
|
||||
set env(GIT_DIR) $_gitdir
|
||||
set env(GIT_WORK_TREE) $_gitworktree
|
||||
|
|
@ -2273,16 +2296,18 @@ proc get_explorer {} {
|
|||
|
||||
proc do_explore {} {
|
||||
global _gitworktree
|
||||
set explorer [get_explorer]
|
||||
eval exec $explorer [list [file nativename $_gitworktree]] &
|
||||
set cmd [get_explorer]
|
||||
lappend cmd [file nativename $_gitworktree]
|
||||
safe_exec_bg $cmd
|
||||
}
|
||||
|
||||
# Open file relative to the working tree by the default associated app.
|
||||
proc do_file_open {file} {
|
||||
global _gitworktree
|
||||
set explorer [get_explorer]
|
||||
set cmd [get_explorer]
|
||||
set full_file_path [file join $_gitworktree $file]
|
||||
exec $explorer [file nativename $full_file_path] &
|
||||
lappend cmd [file nativename $full_file_path]
|
||||
safe_exec_bg $cmd
|
||||
}
|
||||
|
||||
set is_quitting 0
|
||||
|
|
@ -2316,7 +2341,7 @@ proc do_quit {{rc {1}}} {
|
|||
if {![string match amend* $commit_type]
|
||||
&& $msg ne {}} {
|
||||
catch {
|
||||
set fd [open $save w]
|
||||
set fd [safe_open_file $save w]
|
||||
fconfigure $fd -encoding utf-8
|
||||
puts -nonewline $fd $msg
|
||||
close $fd
|
||||
|
|
@ -2760,17 +2785,16 @@ if {![is_bare]} {
|
|||
|
||||
if {[is_Windows]} {
|
||||
# Use /git-bash.exe if available
|
||||
set normalized [file normalize $::argv0]
|
||||
regsub "/mingw../libexec/git-core/git-gui$" \
|
||||
$normalized "/git-bash.exe" cmdLine
|
||||
if {$cmdLine != $normalized && [file exists $cmdLine]} {
|
||||
set cmdLine [list "Git Bash" $cmdLine &]
|
||||
set _git_bash [safe_exec [list cygpath -m /git-bash.exe]]
|
||||
if {[file executable $_git_bash]} {
|
||||
set _bash_cmdline [list "Git Bash" $_git_bash]
|
||||
} else {
|
||||
set cmdLine [list "Git Bash" bash --login -l &]
|
||||
set _bash_cmdline [list "Git Bash" bash --login -l]
|
||||
}
|
||||
.mbar.repository add command \
|
||||
-label [mc "Git Bash"] \
|
||||
-command {eval exec [auto_execok start] $cmdLine}
|
||||
-command {safe_exec_bg [concat [list [_which cmd] /c start] $_bash_cmdline]}
|
||||
unset _git_bash
|
||||
}
|
||||
|
||||
if {[is_Windows] || ![is_bare]} {
|
||||
|
|
@ -4079,7 +4103,7 @@ if {[winfo exists $ui_comm]} {
|
|||
}
|
||||
} elseif {$m} {
|
||||
catch {
|
||||
set fd [open [gitdir GITGUI_BCK] w]
|
||||
set fd [safe_open_file [gitdir GITGUI_BCK] w]
|
||||
fconfigure $fd -encoding utf-8
|
||||
puts -nonewline $fd $msg
|
||||
close $fd
|
||||
|
|
|
|||
|
|
@ -481,14 +481,14 @@ method _load {jump} {
|
|||
if {$do_textconv ne 0} {
|
||||
set fd [open_cmd_pipe $textconv $path]
|
||||
} else {
|
||||
set fd [open $path r]
|
||||
set fd [safe_open_file $path r]
|
||||
}
|
||||
fconfigure $fd -eofchar {}
|
||||
} else {
|
||||
if {$do_textconv ne 0} {
|
||||
set fd [git_read cat-file --textconv "$commit:$path"]
|
||||
set fd [git_read [list cat-file --textconv "$commit:$path"]]
|
||||
} else {
|
||||
set fd [git_read cat-file blob "$commit:$path"]
|
||||
set fd [git_read [list cat-file blob "$commit:$path"]]
|
||||
}
|
||||
}
|
||||
fconfigure $fd \
|
||||
|
|
@ -617,7 +617,7 @@ method _exec_blame {cur_w cur_d options cur_s} {
|
|||
}
|
||||
|
||||
lappend options -- $path
|
||||
set fd [eval git_read --nice blame $options]
|
||||
set fd [git_read_nice [concat blame $options]]
|
||||
fconfigure $fd -blocking 0 -translation lf -encoding utf-8
|
||||
fileevent $fd readable [cb _read_blame $fd $cur_w $cur_d]
|
||||
set current_fd $fd
|
||||
|
|
@ -986,7 +986,7 @@ method _showcommit {cur_w lno} {
|
|||
if {[catch {set msg $header($cmit,message)}]} {
|
||||
set msg {}
|
||||
catch {
|
||||
set fd [git_read cat-file commit $cmit]
|
||||
set fd [git_read [list cat-file commit $cmit]]
|
||||
fconfigure $fd -encoding binary -translation lf
|
||||
# By default commits are assumed to be in utf-8
|
||||
set enc utf-8
|
||||
|
|
@ -1134,7 +1134,7 @@ method _blameparent {} {
|
|||
} else {
|
||||
set diffcmd [list diff-tree --unified=0 $cparent $cmit -- $new_path]
|
||||
}
|
||||
if {[catch {set fd [eval git_read $diffcmd]} err]} {
|
||||
if {[catch {set fd [git_read $diffcmd]} err]} {
|
||||
$status_operation stop [mc "Unable to display parent"]
|
||||
error_popup [strcat [mc "Error loading diff:"] "\n\n$err"]
|
||||
return
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ proc load_all_heads {} {
|
|||
set rh refs/heads
|
||||
set rh_len [expr {[string length $rh] + 1}]
|
||||
set all_heads [list]
|
||||
set fd [git_read for-each-ref --format=%(refname) $rh]
|
||||
set fd [git_read [list for-each-ref --format=%(refname) $rh]]
|
||||
fconfigure $fd -translation binary -encoding utf-8
|
||||
while {[gets $fd line] > 0} {
|
||||
if {!$some_heads_tracking || ![is_tracking_branch $line]} {
|
||||
|
|
@ -21,10 +21,10 @@ proc load_all_heads {} {
|
|||
|
||||
proc load_all_tags {} {
|
||||
set all_tags [list]
|
||||
set fd [git_read for-each-ref \
|
||||
set fd [git_read [list for-each-ref \
|
||||
--sort=-taggerdate \
|
||||
--format=%(refname) \
|
||||
refs/tags]
|
||||
refs/tags]]
|
||||
fconfigure $fd -translation binary -encoding utf-8
|
||||
while {[gets $fd line] > 0} {
|
||||
if {![regsub ^refs/tags/ $line {} name]} continue
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ method _ls {tree_id {name {}}} {
|
|||
lappend browser_stack [list $tree_id $name]
|
||||
$w conf -state disabled
|
||||
|
||||
set fd [git_read ls-tree -z $tree_id]
|
||||
set fd [git_read [list ls-tree -z $tree_id]]
|
||||
fconfigure $fd -blocking 0 -translation binary -encoding utf-8
|
||||
fileevent $fd readable [cb _read $fd]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -304,12 +304,12 @@ The rescan will be automatically started now.
|
|||
_readtree $this
|
||||
} else {
|
||||
ui_status [mc "Refreshing file status..."]
|
||||
set fd [git_read update-index \
|
||||
set fd [git_read [list update-index \
|
||||
-q \
|
||||
--unmerged \
|
||||
--ignore-missing \
|
||||
--refresh \
|
||||
]
|
||||
]]
|
||||
fconfigure $fd -blocking 0 -translation binary
|
||||
fileevent $fd readable [cb _refresh_wait $fd]
|
||||
}
|
||||
|
|
@ -345,14 +345,15 @@ method _readtree {} {
|
|||
[mc "Updating working directory to '%s'..." [_name $this]] \
|
||||
[mc "files checked out"]]
|
||||
|
||||
set fd [git_read --stderr read-tree \
|
||||
set fd [git_read [list read-tree \
|
||||
-m \
|
||||
-u \
|
||||
-v \
|
||||
--exclude-per-directory=.gitignore \
|
||||
$HEAD \
|
||||
$new_hash \
|
||||
]
|
||||
] \
|
||||
[list 2>@1]]
|
||||
fconfigure $fd -blocking 0 -translation binary
|
||||
fileevent $fd readable [cb _readtree_wait $fd $status_bar_operation]
|
||||
}
|
||||
|
|
@ -510,18 +511,8 @@ method _update_repo_state {} {
|
|||
delete_this
|
||||
}
|
||||
|
||||
git-version proc _detach_HEAD {log new} {
|
||||
>= 1.5.3 {
|
||||
git update-ref --no-deref -m $log HEAD $new
|
||||
}
|
||||
default {
|
||||
set p [gitdir HEAD]
|
||||
file delete $p
|
||||
set fd [open $p w]
|
||||
fconfigure $fd -translation lf -encoding utf-8
|
||||
puts $fd $new
|
||||
close $fd
|
||||
}
|
||||
proc _detach_HEAD {log new} {
|
||||
git update-ref --no-deref -m $log HEAD $new
|
||||
}
|
||||
|
||||
method _confirm_reset {cur} {
|
||||
|
|
@ -582,7 +573,7 @@ method _confirm_reset {cur} {
|
|||
pack $w.buttons.cancel -side right -padx 5
|
||||
pack $w.buttons -side bottom -fill x -pady 10 -padx 10
|
||||
|
||||
set fd [git_read rev-list --pretty=oneline $cur ^$new_hash]
|
||||
set fd [git_read [list rev-list --pretty=oneline $cur ^$new_hash]]
|
||||
while {[gets $fd line] > 0} {
|
||||
set abbr [string range $line 0 7]
|
||||
set subj [string range $line 41 end]
|
||||
|
|
|
|||
|
|
@ -641,8 +641,8 @@ method _do_clone2 {} {
|
|||
set pwd [pwd]
|
||||
if {[catch {
|
||||
file mkdir [gitdir objects info]
|
||||
set f_in [open [file join $objdir info alternates] r]
|
||||
set f_cp [open [gitdir objects info alternates] w]
|
||||
set f_in [safe_open_file [file join $objdir info alternates] r]
|
||||
set f_cp [safe_open_file [gitdir objects info alternates] w]
|
||||
fconfigure $f_in -translation binary -encoding binary
|
||||
fconfigure $f_cp -translation binary -encoding binary
|
||||
cd $objdir
|
||||
|
|
@ -727,7 +727,7 @@ method _do_clone2 {} {
|
|||
[cb _do_clone_tags]
|
||||
}
|
||||
shared {
|
||||
set fd [open [gitdir objects info alternates] w]
|
||||
set fd [safe_open_file [gitdir objects info alternates] w]
|
||||
fconfigure $fd -translation binary
|
||||
puts $fd $objdir
|
||||
close $fd
|
||||
|
|
@ -760,8 +760,8 @@ method _copy_files {objdir tocopy} {
|
|||
}
|
||||
foreach p $tocopy {
|
||||
if {[catch {
|
||||
set f_in [open [file join $objdir $p] r]
|
||||
set f_cp [open [file join .git objects $p] w]
|
||||
set f_in [safe_open_file [file join $objdir $p] r]
|
||||
set f_cp [safe_open_file [file join .git objects $p] w]
|
||||
fconfigure $f_in -translation binary -encoding binary
|
||||
fconfigure $f_cp -translation binary -encoding binary
|
||||
|
||||
|
|
@ -818,12 +818,12 @@ method _clone_refs {} {
|
|||
error_popup [mc "Not a Git repository: %s" [file tail $origin_url]]
|
||||
return 0
|
||||
}
|
||||
set fd_in [git_read for-each-ref \
|
||||
set fd_in [git_read [list for-each-ref \
|
||||
--tcl \
|
||||
{--format=list %(refname) %(objectname) %(*objectname)}]
|
||||
{--format=list %(refname) %(objectname) %(*objectname)}]]
|
||||
cd $pwd
|
||||
|
||||
set fd [open [gitdir packed-refs] w]
|
||||
set fd [safe_open_file [gitdir packed-refs] w]
|
||||
fconfigure $fd -translation binary
|
||||
puts $fd "# pack-refs with: peeled"
|
||||
while {[gets $fd_in line] >= 0} {
|
||||
|
|
@ -877,7 +877,7 @@ method _do_clone_full_end {ok} {
|
|||
|
||||
set HEAD {}
|
||||
if {[file exists [gitdir FETCH_HEAD]]} {
|
||||
set fd [open [gitdir FETCH_HEAD] r]
|
||||
set fd [safe_open_file [gitdir FETCH_HEAD] r]
|
||||
while {[gets $fd line] >= 0} {
|
||||
if {[regexp "^(.{40})\t\t" $line line HEAD]} {
|
||||
break
|
||||
|
|
@ -953,13 +953,14 @@ method _do_clone_checkout {HEAD} {
|
|||
[mc "files"]]
|
||||
|
||||
set readtree_err {}
|
||||
set fd [git_read --stderr read-tree \
|
||||
set fd [git_read [list read-tree \
|
||||
-m \
|
||||
-u \
|
||||
-v \
|
||||
HEAD \
|
||||
HEAD \
|
||||
]
|
||||
] \
|
||||
[list 2>@1]]
|
||||
fconfigure $fd -blocking 0 -translation binary
|
||||
fileevent $fd readable [cb _readtree_wait $fd]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -146,14 +146,14 @@ constructor _new {path unmerged_only title} {
|
|||
append fmt { %(*subject)}
|
||||
append fmt {]}
|
||||
set all_refn [list]
|
||||
set fr_fd [git_read for-each-ref \
|
||||
set fr_fd [git_read [list 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]
|
||||
|
|
@ -176,7 +176,7 @@ constructor _new {path unmerged_only title} {
|
|||
close $fr_fd
|
||||
|
||||
if {$unmerged_only} {
|
||||
set fr_fd [git_read rev-list --all ^$::HEAD]
|
||||
set fr_fd [git_read [list rev-list --all ^$::HEAD]]
|
||||
while {[gets $fr_fd sha1] > 0} {
|
||||
if {[catch {set rlst $cmt_refn($sha1)}]} continue
|
||||
foreach refn $rlst {
|
||||
|
|
@ -579,7 +579,7 @@ method _reflog_last {name} {
|
|||
|
||||
set last {}
|
||||
if {[catch {set last [file mtime [gitdir $name]]}]
|
||||
&& ![catch {set g [open [gitdir logs $name] r]}]} {
|
||||
&& ![catch {set g [safe_open_file [gitdir logs $name] r]}]} {
|
||||
fconfigure $g -translation binary
|
||||
while {[gets $g line] >= 0} {
|
||||
if {[regexp {> ([1-9][0-9]*) } $line line when]} {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ You are currently in the middle of a merge that has not been fully completed. Y
|
|||
if {[catch {
|
||||
set name ""
|
||||
set email ""
|
||||
set fd [git_read cat-file commit $curHEAD]
|
||||
set fd [git_read [list cat-file commit $curHEAD]]
|
||||
fconfigure $fd -encoding binary -translation lf
|
||||
# By default commits are assumed to be in utf-8
|
||||
set enc utf-8
|
||||
|
|
@ -236,7 +236,7 @@ A good commit message has the following format:
|
|||
# -- Build the message file.
|
||||
#
|
||||
set msg_p [gitdir GITGUI_EDITMSG]
|
||||
set msg_wt [open $msg_p w]
|
||||
set msg_wt [safe_open_file $msg_p w]
|
||||
fconfigure $msg_wt -translation lf
|
||||
setup_commit_encoding $msg_wt
|
||||
puts $msg_wt $msg
|
||||
|
|
@ -336,7 +336,7 @@ proc commit_commitmsg_wait {fd_ph curHEAD msg_p} {
|
|||
|
||||
proc commit_writetree {curHEAD msg_p} {
|
||||
ui_status [mc "Committing changes..."]
|
||||
set fd_wt [git_read write-tree]
|
||||
set fd_wt [git_read [list write-tree]]
|
||||
fileevent $fd_wt readable \
|
||||
[list commit_committree $fd_wt $curHEAD $msg_p]
|
||||
}
|
||||
|
|
@ -361,7 +361,7 @@ proc commit_committree {fd_wt curHEAD msg_p} {
|
|||
# -- Verify this wasn't an empty change.
|
||||
#
|
||||
if {$commit_type eq {normal}} {
|
||||
set fd_ot [git_read cat-file commit $PARENT]
|
||||
set fd_ot [git_read [list cat-file commit $PARENT]]
|
||||
fconfigure $fd_ot -encoding binary -translation lf
|
||||
set old_tree [gets $fd_ot]
|
||||
close $fd_ot
|
||||
|
|
@ -399,8 +399,8 @@ A rescan will be automatically started now.
|
|||
foreach p [concat $PARENT $MERGE_HEAD] {
|
||||
lappend cmd -p $p
|
||||
}
|
||||
lappend cmd <$msg_p
|
||||
if {[catch {set cmt_id [eval git $cmd]} err]} {
|
||||
set msgtxt [list <$msg_p]
|
||||
if {[catch {set cmt_id [git_redir $cmd $msgtxt]} err]} {
|
||||
catch {file delete $msg_p}
|
||||
error_popup [strcat [mc "commit-tree failed:"] "\n\n$err"]
|
||||
ui_status [mc "Commit failed."]
|
||||
|
|
@ -420,7 +420,7 @@ A rescan will be automatically started now.
|
|||
if {$commit_type ne {normal}} {
|
||||
append reflogm " ($commit_type)"
|
||||
}
|
||||
set msg_fd [open $msg_p r]
|
||||
set msg_fd [safe_open_file $msg_p r]
|
||||
setup_commit_encoding $msg_fd 1
|
||||
gets $msg_fd subject
|
||||
close $msg_fd
|
||||
|
|
|
|||
|
|
@ -92,10 +92,9 @@ method _init {} {
|
|||
|
||||
method exec {cmd {after {}}} {
|
||||
if {[lindex $cmd 0] eq {git}} {
|
||||
set fd_f [eval git_read --stderr [lrange $cmd 1 end]]
|
||||
set fd_f [git_read [lrange $cmd 1 end] [list 2>@1]]
|
||||
} else {
|
||||
lappend cmd 2>@1
|
||||
set fd_f [_open_stdout_stderr $cmd]
|
||||
set fd_f [safe_open_command $cmd [list 2>@1]]
|
||||
}
|
||||
fconfigure $fd_f -blocking 0 -translation binary -encoding [encoding system]
|
||||
fileevent $fd_f readable [cb _read $fd_f $after]
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
proc do_stats {} {
|
||||
global use_ttk NS
|
||||
set fd [git_read count-objects -v]
|
||||
set fd [git_read [list count-objects -v]]
|
||||
while {[gets $fd line] > 0} {
|
||||
if {[regexp {^([^:]+): (\d+)$} $line _ name value]} {
|
||||
set stats($name) $value
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ proc show_other_diff {path w m cont_info} {
|
|||
set sz [string length $content]
|
||||
}
|
||||
file {
|
||||
set fd [open $path r]
|
||||
set fd [safe_open_file $path r]
|
||||
fconfigure $fd \
|
||||
-eofchar {} \
|
||||
-encoding [get_path_encoding $path]
|
||||
|
|
@ -215,7 +215,7 @@ proc show_other_diff {path w m cont_info} {
|
|||
$ui_diff insert end \
|
||||
"* [mc "Git Repository (subproject)"]\n" \
|
||||
d_info
|
||||
} elseif {![catch {set type [exec file $path]}]} {
|
||||
} elseif {![catch {set type [safe_exec [list file $path]]}]} {
|
||||
set n [string length $path]
|
||||
if {[string equal -length $n $path $type]} {
|
||||
set type [string range $type $n end]
|
||||
|
|
@ -327,7 +327,7 @@ proc start_show_diff {cont_info {add_opts {}}} {
|
|||
}
|
||||
}
|
||||
|
||||
if {[catch {set fd [eval git_read --nice $cmd]} err]} {
|
||||
if {[catch {set fd [git_read_nice $cmd]} err]} {
|
||||
set diff_active 0
|
||||
unlock_index
|
||||
ui_status [mc "Unable to display %s" [escape_path $path]]
|
||||
|
|
@ -603,7 +603,7 @@ proc apply_or_revert_hunk {x y revert} {
|
|||
|
||||
if {[catch {
|
||||
set enc [get_path_encoding $current_diff_path]
|
||||
set p [eval git_write $apply_cmd]
|
||||
set p [git_write $apply_cmd]
|
||||
fconfigure $p -translation binary -encoding $enc
|
||||
puts -nonewline $p $wholepatch
|
||||
close $p} err]} {
|
||||
|
|
@ -839,7 +839,7 @@ proc apply_or_revert_range_or_line {x y revert} {
|
|||
|
||||
if {[catch {
|
||||
set enc [get_path_encoding $current_diff_path]
|
||||
set p [eval git_write $apply_cmd]
|
||||
set p [git_write $apply_cmd]
|
||||
fconfigure $p -translation binary -encoding $enc
|
||||
puts -nonewline $p $current_diff_header
|
||||
puts -nonewline $p $wholepatch
|
||||
|
|
@ -876,7 +876,7 @@ proc undo_last_revert {} {
|
|||
|
||||
if {[catch {
|
||||
set enc $last_revert_enc
|
||||
set p [eval git_write $apply_cmd]
|
||||
set p [git_write $apply_cmd]
|
||||
fconfigure $p -translation binary -encoding $enc
|
||||
puts -nonewline $p $last_revert
|
||||
close $p} err]} {
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ proc update_indexinfo {msg path_list after} {
|
|||
if {$batch > 25} {set batch 25}
|
||||
|
||||
set status_bar_operation [$::main_status start $msg [mc "files"]]
|
||||
set fd [git_write update-index -z --index-info]
|
||||
set fd [git_write [list update-index -z --index-info]]
|
||||
fconfigure $fd \
|
||||
-blocking 0 \
|
||||
-buffering full \
|
||||
|
|
@ -144,7 +144,7 @@ proc update_index {msg path_list after} {
|
|||
if {$batch > 25} {set batch 25}
|
||||
|
||||
set status_bar_operation [$::main_status start $msg [mc "files"]]
|
||||
set fd [git_write update-index --add --remove -z --stdin]
|
||||
set fd [git_write [list update-index --add --remove -z --stdin]]
|
||||
fconfigure $fd \
|
||||
-blocking 0 \
|
||||
-buffering full \
|
||||
|
|
@ -218,13 +218,13 @@ proc checkout_index {msg path_list after capture_error} {
|
|||
if {$batch > 25} {set batch 25}
|
||||
|
||||
set status_bar_operation [$::main_status start $msg [mc "files"]]
|
||||
set fd [git_write checkout-index \
|
||||
set fd [git_write [list checkout-index \
|
||||
--index \
|
||||
--quiet \
|
||||
--force \
|
||||
-z \
|
||||
--stdin \
|
||||
]
|
||||
]]
|
||||
fconfigure $fd \
|
||||
-blocking 0 \
|
||||
-buffering full \
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ method _start {} {
|
|||
set spec [$w_rev get_tracking_branch]
|
||||
set cmit [$w_rev get_commit]
|
||||
|
||||
set fh [open [gitdir FETCH_HEAD] w]
|
||||
set fh [safe_open_file [gitdir FETCH_HEAD] w]
|
||||
fconfigure $fh -translation lf
|
||||
if {$spec eq {}} {
|
||||
set remote .
|
||||
|
|
@ -118,7 +118,7 @@ method _start {} {
|
|||
set cmd [list git]
|
||||
lappend cmd merge
|
||||
lappend cmd --strategy=recursive
|
||||
lappend cmd [git fmt-merge-msg <[gitdir FETCH_HEAD]]
|
||||
lappend cmd [git_redir [list fmt-merge-msg] [list <[gitdir FETCH_HEAD]]]
|
||||
lappend cmd HEAD
|
||||
lappend cmd $name
|
||||
}
|
||||
|
|
@ -239,7 +239,7 @@ Continue with resetting the current changes?"]
|
|||
}
|
||||
|
||||
if {[ask_popup $op_question] eq {yes}} {
|
||||
set fd [git_read --stderr read-tree --reset -u -v HEAD]
|
||||
set fd [git_read [list read-tree --reset -u -v HEAD] [list 2>@1]]
|
||||
fconfigure $fd -blocking 0 -translation binary
|
||||
set status_bar_operation [$::main_status \
|
||||
start \
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ proc merge_load_stages {path cont} {
|
|||
set merge_stages(3) {}
|
||||
set merge_stages_buf {}
|
||||
|
||||
set merge_stages_fd [eval git_read ls-files -u -z -- {$path}]
|
||||
set merge_stages_fd [git_read [list ls-files -u -z -- $path]]
|
||||
|
||||
fconfigure $merge_stages_fd -blocking 0 -translation binary -encoding binary
|
||||
fileevent $merge_stages_fd readable [list read_merge_stages $merge_stages_fd $cont]
|
||||
|
|
@ -310,7 +310,7 @@ proc merge_tool_get_stages {target stages} {
|
|||
foreach fname $stages {
|
||||
if {$merge_stages($i) eq {}} {
|
||||
file delete $fname
|
||||
catch { close [open $fname w] }
|
||||
catch { close [safe_open_file $fname w] }
|
||||
} else {
|
||||
# A hack to support autocrlf properly
|
||||
git checkout-index -f --stage=$i -- $target
|
||||
|
|
@ -360,9 +360,9 @@ proc merge_tool_start {cmdline target backup stages} {
|
|||
|
||||
# Force redirection to avoid interpreting output on stderr
|
||||
# as an error, and launch the tool
|
||||
lappend cmdline {2>@1}
|
||||
set redir [list {2>@1}]
|
||||
|
||||
if {[catch { set mtool_fd [_open_stdout_stderr $cmdline] } err]} {
|
||||
if {[catch { set mtool_fd [safe_open_command $cmdline $redir] } err]} {
|
||||
delete_temp_files $mtool_tmpfiles
|
||||
error_popup [mc "Could not start the merge tool:\n\n%s" $err]
|
||||
return
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ proc all_tracking_branches {} {
|
|||
}
|
||||
|
||||
if {$pat ne {}} {
|
||||
set fd [eval git_read for-each-ref --format=%(refname) $cmd]
|
||||
set fd [git_read [concat for-each-ref --format=%(refname) $cmd]]
|
||||
while {[gets $fd n] > 0} {
|
||||
foreach spec $pat {
|
||||
set dst [string range [lindex $spec 0] 0 end-2]
|
||||
|
|
@ -75,7 +75,7 @@ proc load_all_remotes {} {
|
|||
|
||||
foreach name $all_remotes {
|
||||
catch {
|
||||
set fd [open [file join $rm_dir $name] r]
|
||||
set fd [safe_open_file [file join $rm_dir $name] r]
|
||||
while {[gets $fd line] >= 0} {
|
||||
if {[regexp {^URL:[ ]*(.+)$} $line line url]} {
|
||||
set remote_url($name) $url
|
||||
|
|
@ -145,7 +145,7 @@ proc add_fetch_entry {r} {
|
|||
}
|
||||
} else {
|
||||
catch {
|
||||
set fd [open [gitdir remotes $r] r]
|
||||
set fd [safe_open_file [gitdir remotes $r] r]
|
||||
while {[gets $fd n] >= 0} {
|
||||
if {[regexp {^Pull:[ \t]*([^:]+):} $n]} {
|
||||
set enable 1
|
||||
|
|
@ -182,7 +182,7 @@ proc add_push_entry {r} {
|
|||
}
|
||||
} else {
|
||||
catch {
|
||||
set fd [open [gitdir remotes $r] r]
|
||||
set fd [safe_open_file [gitdir remotes $r] r]
|
||||
while {[gets $fd n] >= 0} {
|
||||
if {[regexp {^Push:[ \t]*([^:]+):} $n]} {
|
||||
set enable 1
|
||||
|
|
|
|||
|
|
@ -308,7 +308,7 @@ method _load {cache uri} {
|
|||
set full_list [list]
|
||||
set head_cache($cache) [list]
|
||||
set full_cache($cache) [list]
|
||||
set active_ls [git_read ls-remote $uri]
|
||||
set active_ls [git_read [list ls-remote $uri]]
|
||||
fconfigure $active_ls \
|
||||
-blocking 0 \
|
||||
-translation lf \
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ proc do_windows_shortcut {} {
|
|||
set fn ${fn}.lnk
|
||||
}
|
||||
# Use git-gui.exe if available (ie: git-for-windows)
|
||||
set cmdLine [auto_execok git-gui.exe]
|
||||
set cmdLine [list [_which git-gui]]
|
||||
if {$cmdLine eq {}} {
|
||||
set cmdLine [list [info nameofexecutable] \
|
||||
[file normalize $::argv0]]
|
||||
|
|
@ -30,8 +30,8 @@ proc do_cygwin_shortcut {} {
|
|||
global argv0 _gitworktree oguilib
|
||||
|
||||
if {[catch {
|
||||
set desktop [exec cygpath \
|
||||
--desktop]
|
||||
set desktop [safe_exec [list cygpath \
|
||||
--desktop]]
|
||||
}]} {
|
||||
set desktop .
|
||||
}
|
||||
|
|
@ -50,14 +50,14 @@ proc do_cygwin_shortcut {} {
|
|||
"CHERE_INVOKING=1 \
|
||||
source /etc/profile; \
|
||||
git gui"}
|
||||
exec /bin/mkshortcut.exe \
|
||||
safe_exec [list /bin/mkshortcut.exe \
|
||||
--arguments $shargs \
|
||||
--desc "git-gui on $repodir" \
|
||||
--icon $oguilib/git-gui.ico \
|
||||
--name $fn \
|
||||
--show min \
|
||||
--workingdir $repodir \
|
||||
/bin/sh.exe
|
||||
/bin/sh.exe]
|
||||
} err]} {
|
||||
error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"]
|
||||
}
|
||||
|
|
@ -83,7 +83,7 @@ proc do_macosx_app {} {
|
|||
|
||||
file mkdir $MacOS
|
||||
|
||||
set fd [open [file join $Contents Info.plist] w]
|
||||
set fd [safe_open_file [file join $Contents Info.plist] w]
|
||||
puts $fd {<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
|
|
@ -108,7 +108,7 @@ proc do_macosx_app {} {
|
|||
</plist>}
|
||||
close $fd
|
||||
|
||||
set fd [open $exe w]
|
||||
set fd [safe_open_file $exe w]
|
||||
puts $fd "#!/bin/sh"
|
||||
foreach name [lsort [array names env]] {
|
||||
set value $env($name)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ proc find_ssh_key {} {
|
|||
~/.ssh/id_rsa.pub ~/.ssh/identity.pub
|
||||
} {
|
||||
if {[file exists $name]} {
|
||||
set fh [open $name r]
|
||||
set fh [safe_open_file $name r]
|
||||
set cont [read $fh]
|
||||
close $fh
|
||||
return [list $name $cont]
|
||||
|
|
@ -83,9 +83,10 @@ proc make_ssh_key {w} {
|
|||
set sshkey_title [mc "Generating..."]
|
||||
$w.header.gen configure -state disabled
|
||||
|
||||
set cmdline [list sh -c {echo | ssh-keygen -q -t rsa -f ~/.ssh/id_rsa 2>&1}]
|
||||
set cmdline [list [shellpath] -c \
|
||||
{echo | ssh-keygen -q -t rsa -f ~/.ssh/id_rsa 2>&1}]
|
||||
|
||||
if {[catch { set sshkey_fd [_open_stdout_stderr $cmdline] } err]} {
|
||||
if {[catch { set sshkey_fd [safe_open_command $cmdline] } err]} {
|
||||
error_popup [mc "Could not start ssh-keygen:\n\n%s" $err]
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,14 +110,14 @@ proc tools_exec {fullname} {
|
|||
|
||||
set cmdline $repo_config(guitool.$fullname.cmd)
|
||||
if {[is_config_true "guitool.$fullname.noconsole"]} {
|
||||
tools_run_silent [list sh -c $cmdline] \
|
||||
tools_run_silent [list [shellpath] -c $cmdline] \
|
||||
[list tools_complete $fullname {}]
|
||||
} else {
|
||||
regsub {/} $fullname { / } title
|
||||
set w [console::new \
|
||||
[mc "Tool: %s" $title] \
|
||||
[mc "Running: %s" $cmdline]]
|
||||
console::exec $w [list sh -c $cmdline] \
|
||||
console::exec $w [list [shellpath] -c $cmdline] \
|
||||
[list tools_complete $fullname $w]
|
||||
}
|
||||
|
||||
|
|
@ -130,8 +130,7 @@ proc tools_exec {fullname} {
|
|||
}
|
||||
|
||||
proc tools_run_silent {cmd after} {
|
||||
lappend cmd 2>@1
|
||||
set fd [_open_stdout_stderr $cmd]
|
||||
set fd [safe_open_command $cmd [list 2>@1]]
|
||||
|
||||
fconfigure $fd -blocking 0 -translation binary
|
||||
fileevent $fd readable [list tools_consume_input $fd $after]
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
# Copyright (C) 2007 Shawn Pearce
|
||||
|
||||
proc win32_read_lnk {lnk_path} {
|
||||
return [exec cscript.exe \
|
||||
return [safe_exec [list cscript.exe \
|
||||
/E:jscript \
|
||||
/nologo \
|
||||
[file join $::oguilib win32_shortcut.js] \
|
||||
$lnk_path]
|
||||
$lnk_path]]
|
||||
}
|
||||
|
||||
proc win32_create_lnk {lnk_path lnk_exec lnk_dir} {
|
||||
|
|
@ -15,12 +15,13 @@ proc win32_create_lnk {lnk_path lnk_exec lnk_dir} {
|
|||
set lnk_args [lrange $lnk_exec 1 end]
|
||||
set lnk_exec [lindex $lnk_exec 0]
|
||||
|
||||
eval [list exec wscript.exe \
|
||||
set cmd [list wscript.exe \
|
||||
/E:jscript \
|
||||
/nologo \
|
||||
[file nativename [file join $oguilib win32_shortcut.js]] \
|
||||
$lnk_path \
|
||||
[file nativename [file join $oguilib git-gui.ico]] \
|
||||
$lnk_dir \
|
||||
$lnk_exec] $lnk_args
|
||||
$lnk_exec]
|
||||
safe_exec [concat $cmd $lnk_args]
|
||||
}
|
||||
|
|
|
|||
277
gitk-git/gitk
277
gitk-git/gitk
|
|
@ -113,6 +113,91 @@ if {[is_Windows]} {
|
|||
|
||||
# End of safe PATH lookup stuff
|
||||
|
||||
# Wrap exec/open to sanitize arguments
|
||||
|
||||
# unsafe arguments begin with redirections or the pipe or background operators
|
||||
proc is_arg_unsafe {arg} {
|
||||
regexp {^([<|>&]|2>)} $arg
|
||||
}
|
||||
|
||||
proc make_arg_safe {arg} {
|
||||
if {[is_arg_unsafe $arg]} {
|
||||
set arg [file join . $arg]
|
||||
}
|
||||
return $arg
|
||||
}
|
||||
|
||||
proc make_arglist_safe {arglist} {
|
||||
set res {}
|
||||
foreach arg $arglist {
|
||||
lappend res [make_arg_safe $arg]
|
||||
}
|
||||
return $res
|
||||
}
|
||||
|
||||
# executes one command
|
||||
# no redirections or pipelines are possible
|
||||
# cmd is a list that specifies the command and its arguments
|
||||
# calls `exec` and returns its value
|
||||
proc safe_exec {cmd} {
|
||||
eval exec [make_arglist_safe $cmd]
|
||||
}
|
||||
|
||||
# executes one command with redirections
|
||||
# no pipelines are possible
|
||||
# cmd is a list that specifies the command and its arguments
|
||||
# redir is a list that specifies redirections (output, background, constant(!) commands)
|
||||
# calls `exec` and returns its value
|
||||
proc safe_exec_redirect {cmd redir} {
|
||||
eval exec [make_arglist_safe $cmd] $redir
|
||||
}
|
||||
|
||||
proc safe_open_file {filename flags} {
|
||||
# a file name starting with "|" would attempt to run a process
|
||||
# but such a file name must be treated as a relative path
|
||||
# hide the "|" behind "./"
|
||||
if {[string index $filename 0] eq "|"} {
|
||||
set filename [file join . $filename]
|
||||
}
|
||||
open $filename $flags
|
||||
}
|
||||
|
||||
# opens a command pipeline for reading
|
||||
# cmd is a list that specifies the command and its arguments
|
||||
# calls `open` and returns the file id
|
||||
proc safe_open_command {cmd} {
|
||||
open |[make_arglist_safe $cmd] r
|
||||
}
|
||||
|
||||
# opens a command pipeline for reading and writing
|
||||
# cmd is a list that specifies the command and its arguments
|
||||
# calls `open` and returns the file id
|
||||
proc safe_open_command_rw {cmd} {
|
||||
open |[make_arglist_safe $cmd] r+
|
||||
}
|
||||
|
||||
# opens a command pipeline for reading with redirections
|
||||
# cmd is a list that specifies the command and its arguments
|
||||
# redir is a list that specifies redirections
|
||||
# calls `open` and returns the file id
|
||||
proc safe_open_command_redirect {cmd redir} {
|
||||
set cmd [make_arglist_safe $cmd]
|
||||
open |[concat $cmd $redir] r
|
||||
}
|
||||
|
||||
# opens a pipeline with several commands for reading
|
||||
# cmds is a list of lists, each of which specifies a command and its arguments
|
||||
# calls `open` and returns the file id
|
||||
proc safe_open_pipeline {cmds} {
|
||||
set cmd {}
|
||||
foreach subcmd $cmds {
|
||||
set cmd [concat $cmd | [make_arglist_safe $subcmd]]
|
||||
}
|
||||
open $cmd r
|
||||
}
|
||||
|
||||
# End exec/open wrappers
|
||||
|
||||
proc hasworktree {} {
|
||||
return [expr {[exec git rev-parse --is-bare-repository] == "false" &&
|
||||
[exec git rev-parse --is-inside-git-dir] == "false"}]
|
||||
|
|
@ -238,7 +323,7 @@ proc unmerged_files {files} {
|
|||
set mlist {}
|
||||
set nr_unmerged 0
|
||||
if {[catch {
|
||||
set fd [open "| git ls-files -u" r]
|
||||
set fd [safe_open_command {git ls-files -u}]
|
||||
} err]} {
|
||||
show_error {} . "[mc "Couldn't get list of unmerged files:"] $err"
|
||||
exit 1
|
||||
|
|
@ -400,7 +485,7 @@ proc parseviewrevs {view revs} {
|
|||
} elseif {[lsearch -exact $revs --all] >= 0} {
|
||||
lappend revs HEAD
|
||||
}
|
||||
if {[catch {set ids [eval exec git rev-parse $revs]} err]} {
|
||||
if {[catch {set ids [safe_exec [concat git rev-parse $revs]]} err]} {
|
||||
# we get stdout followed by stderr in $err
|
||||
# for an unknown rev, git rev-parse echoes it and then errors out
|
||||
set errlines [split $err "\n"]
|
||||
|
|
@ -457,16 +542,6 @@ proc parseviewrevs {view revs} {
|
|||
return $ret
|
||||
}
|
||||
|
||||
# Escapes a list of filter paths to be passed to git log via stdin. Note that
|
||||
# paths must not be quoted.
|
||||
proc escape_filter_paths {paths} {
|
||||
set escaped [list]
|
||||
foreach path $paths {
|
||||
lappend escaped [string map {\\ \\\\ "\ " "\\\ "} $path]
|
||||
}
|
||||
return $escaped
|
||||
}
|
||||
|
||||
# Start off a git log process and arrange to read its output
|
||||
proc start_rev_list {view} {
|
||||
global startmsecs commitidx viewcomplete curview
|
||||
|
|
@ -488,7 +563,7 @@ proc start_rev_list {view} {
|
|||
set args $viewargs($view)
|
||||
if {$viewargscmd($view) ne {}} {
|
||||
if {[catch {
|
||||
set str [exec sh -c $viewargscmd($view)]
|
||||
set str [safe_exec [list sh -c $viewargscmd($view)]]
|
||||
} err]} {
|
||||
error_popup "[mc "Error executing --argscmd command:"] $err"
|
||||
return 0
|
||||
|
|
@ -526,10 +601,9 @@ proc start_rev_list {view} {
|
|||
}
|
||||
|
||||
if {[catch {
|
||||
set fd [open [concat | git log --no-color -z --pretty=raw $show_notes \
|
||||
--parents --boundary $args --stdin \
|
||||
"<<[join [concat $revs "--" \
|
||||
[escape_filter_paths $files]] "\\n"]"] r]
|
||||
set fd [safe_open_command_redirect [concat git log --no-color -z --pretty=raw $show_notes \
|
||||
--parents --boundary $args --stdin] \
|
||||
[list "<<[join [concat $revs "--" $files] "\n"]"]]
|
||||
} err]} {
|
||||
error_popup "[mc "Error executing git log:"] $err"
|
||||
return 0
|
||||
|
|
@ -563,9 +637,9 @@ proc stop_instance {inst} {
|
|||
set pid [pid $fd]
|
||||
|
||||
if {$::tcl_platform(platform) eq {windows}} {
|
||||
exec taskkill /pid $pid
|
||||
safe_exec [list taskkill /pid $pid]
|
||||
} else {
|
||||
exec kill $pid
|
||||
safe_exec [list kill $pid]
|
||||
}
|
||||
}
|
||||
catch {close $fd}
|
||||
|
|
@ -680,11 +754,9 @@ proc updatecommits {} {
|
|||
set args $vorigargs($view)
|
||||
}
|
||||
if {[catch {
|
||||
set fd [open [concat | git log --no-color -z --pretty=raw $show_notes \
|
||||
--parents --boundary $args --stdin \
|
||||
"<<[join [concat $revs "--" \
|
||||
[escape_filter_paths \
|
||||
$vfilelimit($view)]] "\\n"]"] r]
|
||||
set fd [safe_open_command_redirect [concat git log --no-color -z --pretty=raw $show_notes \
|
||||
--parents --boundary $args --stdin] \
|
||||
[list "<<[join [concat $revs "--" $vfilelimit($view)] "\n"]"]]
|
||||
} err]} {
|
||||
error_popup "[mc "Error executing git log:"] $err"
|
||||
return
|
||||
|
|
@ -1651,8 +1723,8 @@ proc getcommitlines {fd inst view updating} {
|
|||
# and if we already know about it, using the rewritten
|
||||
# parent as a substitute parent for $id's children.
|
||||
if {![catch {
|
||||
set rwid [exec git rev-list --first-parent --max-count=1 \
|
||||
$id -- $vfilelimit($view)]
|
||||
set rwid [safe_exec [list git rev-list --first-parent --max-count=1 \
|
||||
$id -- $vfilelimit($view)]]
|
||||
}]} {
|
||||
if {$rwid ne {} && [info exists varcid($view,$rwid)]} {
|
||||
# use $rwid in place of $id
|
||||
|
|
@ -1772,7 +1844,7 @@ proc do_readcommit {id} {
|
|||
global tclencoding
|
||||
|
||||
# Invoke git-log to handle automatic encoding conversion
|
||||
set fd [open [concat | git log --no-color --pretty=raw -1 $id] r]
|
||||
set fd [safe_open_command [concat git log --no-color --pretty=raw -1 $id]]
|
||||
# Read the results using i18n.logoutputencoding
|
||||
fconfigure $fd -translation lf -eofchar {}
|
||||
if {$tclencoding != {}} {
|
||||
|
|
@ -1908,7 +1980,7 @@ proc readrefs {} {
|
|||
foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
|
||||
unset -nocomplain $v
|
||||
}
|
||||
set refd [open [list | git show-ref -d] r]
|
||||
set refd [safe_open_command [list git show-ref -d]]
|
||||
if {$tclencoding != {}} {
|
||||
fconfigure $refd -encoding $tclencoding
|
||||
}
|
||||
|
|
@ -1956,7 +2028,7 @@ proc readrefs {} {
|
|||
set selectheadid {}
|
||||
if {$selecthead ne {}} {
|
||||
catch {
|
||||
set selectheadid [exec git rev-parse --verify $selecthead]
|
||||
set selectheadid [safe_exec [list git rev-parse --verify $selecthead]]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2220,7 +2292,7 @@ proc makewindow {} {
|
|||
{mc "Reread re&ferences" command rereadrefs}
|
||||
{mc "&List references" command showrefs -accelerator F2}
|
||||
{xx "" separator}
|
||||
{mc "Start git &gui" command {exec git gui &}}
|
||||
{mc "Start git &gui" command {safe_exec_redirect [list git gui] [list &]}}
|
||||
{xx "" separator}
|
||||
{mc "&Quit" command doquit -accelerator Meta1-Q}
|
||||
}}
|
||||
|
|
@ -3007,7 +3079,7 @@ proc savestuff {w} {
|
|||
set remove_tmp 0
|
||||
if {[catch {
|
||||
set try_count 0
|
||||
while {[catch {set f [open $config_file_tmp {WRONLY CREAT EXCL}]}]} {
|
||||
while {[catch {set f [safe_open_file $config_file_tmp {WRONLY CREAT EXCL}]}]} {
|
||||
if {[incr try_count] > 50} {
|
||||
error "Unable to write config file: $config_file_tmp exists"
|
||||
}
|
||||
|
|
@ -3723,7 +3795,7 @@ proc gitknewtmpdir {} {
|
|||
set tmpdir $gitdir
|
||||
}
|
||||
set gitktmpformat [file join $tmpdir ".gitk-tmp.XXXXXX"]
|
||||
if {[catch {set gitktmpdir [exec mktemp -d $gitktmpformat]}]} {
|
||||
if {[catch {set gitktmpdir [safe_exec [list mktemp -d $gitktmpformat]]}]} {
|
||||
set gitktmpdir [file join $gitdir [format ".gitk-tmp.%s" [pid]]]
|
||||
}
|
||||
if {[catch {file mkdir $gitktmpdir} err]} {
|
||||
|
|
@ -3745,7 +3817,7 @@ proc gitknewtmpdir {} {
|
|||
proc save_file_from_commit {filename output what} {
|
||||
global nullfile
|
||||
|
||||
if {[catch {exec git show $filename -- > $output} err]} {
|
||||
if {[catch {safe_exec_redirect [list git show $filename --] [list > $output]} err]} {
|
||||
if {[string match "fatal: bad revision *" $err]} {
|
||||
return $nullfile
|
||||
}
|
||||
|
|
@ -3810,7 +3882,7 @@ proc external_diff {} {
|
|||
|
||||
if {$difffromfile ne {} && $difftofile ne {}} {
|
||||
set cmd [list [shellsplit $extdifftool] $difffromfile $difftofile]
|
||||
if {[catch {set fl [open |$cmd r]} err]} {
|
||||
if {[catch {set fl [safe_open_command $cmd]} err]} {
|
||||
file delete -force $diffdir
|
||||
error_popup "$extdifftool: [mc "command failed:"] $err"
|
||||
} else {
|
||||
|
|
@ -3914,7 +3986,7 @@ proc external_blame_diff {} {
|
|||
# Find the SHA1 ID of the blob for file $fname in the index
|
||||
# at stage 0 or 2
|
||||
proc index_sha1 {fname} {
|
||||
set f [open [list | git ls-files -s $fname] r]
|
||||
set f [safe_open_command [list git ls-files -s $fname]]
|
||||
while {[gets $f line] >= 0} {
|
||||
set info [lindex [split $line "\t"] 0]
|
||||
set stage [lindex $info 2]
|
||||
|
|
@ -3974,7 +4046,7 @@ proc external_blame {parent_idx {line {}}} {
|
|||
# being given an absolute path...
|
||||
set f [make_relative $f]
|
||||
lappend cmdline $base_commit $f
|
||||
if {[catch {eval exec $cmdline &} err]} {
|
||||
if {[catch {safe_exec_redirect $cmdline [list &]} err]} {
|
||||
error_popup "[mc "git gui blame: command failed:"] $err"
|
||||
}
|
||||
}
|
||||
|
|
@ -4002,7 +4074,7 @@ proc show_line_source {} {
|
|||
# must be a merge in progress...
|
||||
if {[catch {
|
||||
# get the last line from .git/MERGE_HEAD
|
||||
set f [open [file join $gitdir MERGE_HEAD] r]
|
||||
set f [safe_open_file [file join $gitdir MERGE_HEAD] r]
|
||||
set id [lindex [split [read $f] "\n"] end-1]
|
||||
close $f
|
||||
} err]} {
|
||||
|
|
@ -4025,19 +4097,17 @@ proc show_line_source {} {
|
|||
}
|
||||
set line [lindex $h 1]
|
||||
}
|
||||
set blameargs {}
|
||||
set blamefile [file join $cdup $flist_menu_file]
|
||||
if {$from_index ne {}} {
|
||||
lappend blameargs | git cat-file blob $from_index
|
||||
}
|
||||
lappend blameargs | git blame -p -L$line,+1
|
||||
if {$from_index ne {}} {
|
||||
lappend blameargs --contents -
|
||||
set blameargs [list \
|
||||
[list git cat-file blob $from_index] \
|
||||
[list git blame -p -L$line,+1 --contents - -- $blamefile]]
|
||||
} else {
|
||||
lappend blameargs $id
|
||||
set blameargs [list \
|
||||
[list git blame -p -L$line,+1 $id -- $blamefile]]
|
||||
}
|
||||
lappend blameargs -- [file join $cdup $flist_menu_file]
|
||||
if {[catch {
|
||||
set f [open $blameargs r]
|
||||
set f [safe_open_pipeline $blameargs]
|
||||
} err]} {
|
||||
error_popup [mc "Couldn't start git blame: %s" $err]
|
||||
return
|
||||
|
|
@ -4962,8 +5032,8 @@ proc do_file_hl {serial} {
|
|||
# must be "containing:", i.e. we're searching commit info
|
||||
return
|
||||
}
|
||||
set cmd [concat | git diff-tree -r -s --stdin $gdtargs]
|
||||
set filehighlight [open $cmd r+]
|
||||
set cmd [concat git diff-tree -r -s --stdin $gdtargs]
|
||||
set filehighlight [safe_open_command_rw $cmd]
|
||||
fconfigure $filehighlight -blocking 0
|
||||
filerun $filehighlight readfhighlight
|
||||
set fhl_list {}
|
||||
|
|
@ -5392,8 +5462,8 @@ proc get_viewmainhead {view} {
|
|||
global viewmainheadid vfilelimit viewinstances mainheadid
|
||||
|
||||
catch {
|
||||
set rfd [open [concat | git rev-list -1 $mainheadid \
|
||||
-- $vfilelimit($view)] r]
|
||||
set rfd [safe_open_command [concat git rev-list -1 $mainheadid \
|
||||
-- $vfilelimit($view)]]
|
||||
set j [reg_instance $rfd]
|
||||
lappend viewinstances($view) $j
|
||||
fconfigure $rfd -blocking 0
|
||||
|
|
@ -5458,14 +5528,14 @@ proc dodiffindex {} {
|
|||
if {!$showlocalchanges || !$hasworktree} return
|
||||
incr lserial
|
||||
if {[package vcompare $git_version "1.7.2"] >= 0} {
|
||||
set cmd "|git diff-index --cached --ignore-submodules=dirty HEAD"
|
||||
set cmd "git diff-index --cached --ignore-submodules=dirty HEAD"
|
||||
} else {
|
||||
set cmd "|git diff-index --cached HEAD"
|
||||
set cmd "git diff-index --cached HEAD"
|
||||
}
|
||||
if {$vfilelimit($curview) ne {}} {
|
||||
set cmd [concat $cmd -- $vfilelimit($curview)]
|
||||
}
|
||||
set fd [open $cmd r]
|
||||
set fd [safe_open_command $cmd]
|
||||
fconfigure $fd -blocking 0
|
||||
set i [reg_instance $fd]
|
||||
filerun $fd [list readdiffindex $fd $lserial $i]
|
||||
|
|
@ -5490,11 +5560,11 @@ proc readdiffindex {fd serial inst} {
|
|||
}
|
||||
|
||||
# now see if there are any local changes not checked in to the index
|
||||
set cmd "|git diff-files"
|
||||
set cmd "git diff-files"
|
||||
if {$vfilelimit($curview) ne {}} {
|
||||
set cmd [concat $cmd -- $vfilelimit($curview)]
|
||||
}
|
||||
set fd [open $cmd r]
|
||||
set fd [safe_open_command $cmd]
|
||||
fconfigure $fd -blocking 0
|
||||
set i [reg_instance $fd]
|
||||
filerun $fd [list readdifffiles $fd $serial $i]
|
||||
|
|
@ -7283,8 +7353,8 @@ proc browseweb {url} {
|
|||
global web_browser
|
||||
|
||||
if {$web_browser eq {}} return
|
||||
# Use eval here in case $web_browser is a command plus some arguments
|
||||
if {[catch {eval exec $web_browser [list $url] &} err]} {
|
||||
# Use concat here in case $web_browser is a command plus some arguments
|
||||
if {[catch {safe_exec_redirect [concat $web_browser [list $url]] [list &]} err]} {
|
||||
error_popup "[mc "Error starting web browser:"] $err"
|
||||
}
|
||||
}
|
||||
|
|
@ -7790,13 +7860,13 @@ proc gettree {id} {
|
|||
if {![info exists treefilelist($id)]} {
|
||||
if {![info exists treepending]} {
|
||||
if {$id eq $nullid} {
|
||||
set cmd [list | git ls-files]
|
||||
set cmd [list git ls-files]
|
||||
} elseif {$id eq $nullid2} {
|
||||
set cmd [list | git ls-files --stage -t]
|
||||
set cmd [list git ls-files --stage -t]
|
||||
} else {
|
||||
set cmd [list | git ls-tree -r $id]
|
||||
set cmd [list git ls-tree -r $id]
|
||||
}
|
||||
if {[catch {set gtf [open $cmd r]}]} {
|
||||
if {[catch {set gtf [safe_open_command $cmd]}]} {
|
||||
return
|
||||
}
|
||||
set treepending $id
|
||||
|
|
@ -7860,13 +7930,13 @@ proc showfile {f} {
|
|||
return
|
||||
}
|
||||
if {$diffids eq $nullid} {
|
||||
if {[catch {set bf [open $f r]} err]} {
|
||||
if {[catch {set bf [safe_open_file $f r]} err]} {
|
||||
puts "oops, can't read $f: $err"
|
||||
return
|
||||
}
|
||||
} else {
|
||||
set blob [lindex $treeidlist($diffids) $i]
|
||||
if {[catch {set bf [open [concat | git cat-file blob $blob] r]} err]} {
|
||||
if {[catch {set bf [safe_open_command [concat git cat-file blob $blob]]} err]} {
|
||||
puts "oops, error reading blob $blob: $err"
|
||||
return
|
||||
}
|
||||
|
|
@ -8016,7 +8086,7 @@ proc diffcmd {ids flags} {
|
|||
if {$i >= 0} {
|
||||
if {[llength $ids] > 1 && $j < 0} {
|
||||
# comparing working directory with some specific revision
|
||||
set cmd [concat | git diff-index $flags]
|
||||
set cmd [concat git diff-index $flags]
|
||||
if {$i == 0} {
|
||||
lappend cmd -R [lindex $ids 1]
|
||||
} else {
|
||||
|
|
@ -8024,7 +8094,7 @@ proc diffcmd {ids flags} {
|
|||
}
|
||||
} else {
|
||||
# comparing working directory with index
|
||||
set cmd [concat | git diff-files $flags]
|
||||
set cmd [concat git diff-files $flags]
|
||||
if {$j == 1} {
|
||||
lappend cmd -R
|
||||
}
|
||||
|
|
@ -8033,7 +8103,7 @@ proc diffcmd {ids flags} {
|
|||
if {[package vcompare $git_version "1.7.2"] >= 0} {
|
||||
set flags "$flags --ignore-submodules=dirty"
|
||||
}
|
||||
set cmd [concat | git diff-index --cached $flags]
|
||||
set cmd [concat git diff-index --cached $flags]
|
||||
if {[llength $ids] > 1} {
|
||||
# comparing index with specific revision
|
||||
if {$j == 0} {
|
||||
|
|
@ -8049,7 +8119,7 @@ proc diffcmd {ids flags} {
|
|||
if {$log_showroot} {
|
||||
lappend flags --root
|
||||
}
|
||||
set cmd [concat | git diff-tree -r $flags $ids]
|
||||
set cmd [concat git diff-tree -r $flags $ids]
|
||||
}
|
||||
return $cmd
|
||||
}
|
||||
|
|
@ -8061,7 +8131,7 @@ proc gettreediffs {ids} {
|
|||
if {$limitdiffs && $vfilelimit($curview) ne {}} {
|
||||
set cmd [concat $cmd -- $vfilelimit($curview)]
|
||||
}
|
||||
if {[catch {set gdtf [open $cmd r]}]} return
|
||||
if {[catch {set gdtf [safe_open_command $cmd]}]} return
|
||||
|
||||
set treepending $ids
|
||||
set treediff {}
|
||||
|
|
@ -8181,7 +8251,7 @@ proc getblobdiffs {ids} {
|
|||
if {$limitdiffs && $vfilelimit($curview) ne {}} {
|
||||
set cmd [concat $cmd -- $vfilelimit($curview)]
|
||||
}
|
||||
if {[catch {set bdf [open $cmd r]} err]} {
|
||||
if {[catch {set bdf [safe_open_command $cmd]} err]} {
|
||||
error_popup [mc "Error getting diffs: %s" $err]
|
||||
return
|
||||
}
|
||||
|
|
@ -8899,7 +8969,7 @@ proc gotocommit {} {
|
|||
set id [lindex $matches 0]
|
||||
}
|
||||
} else {
|
||||
if {[catch {set id [exec git rev-parse --verify $sha1string]}]} {
|
||||
if {[catch {set id [safe_exec [list git rev-parse --verify $sha1string]]}]} {
|
||||
error_popup [mc "Revision %s is not known" $sha1string]
|
||||
return
|
||||
}
|
||||
|
|
@ -9205,10 +9275,8 @@ proc getpatchid {id} {
|
|||
|
||||
if {![info exists patchids($id)]} {
|
||||
set cmd [diffcmd [list $id] {-p --root}]
|
||||
# trim off the initial "|"
|
||||
set cmd [lrange $cmd 1 end]
|
||||
if {[catch {
|
||||
set x [eval exec $cmd | git patch-id]
|
||||
set x [safe_exec_redirect $cmd [list | git patch-id]]
|
||||
set patchids($id) [lindex $x 0]
|
||||
}]} {
|
||||
set patchids($id) "error"
|
||||
|
|
@ -9304,14 +9372,14 @@ proc diffcommits {a b} {
|
|||
set fna [file join $tmpdir "commit-[string range $a 0 7]"]
|
||||
set fnb [file join $tmpdir "commit-[string range $b 0 7]"]
|
||||
if {[catch {
|
||||
exec git diff-tree -p --pretty $a >$fna
|
||||
exec git diff-tree -p --pretty $b >$fnb
|
||||
safe_exec_redirect [list git diff-tree -p --pretty $a] [list >$fna]
|
||||
safe_exec_redirect [list git diff-tree -p --pretty $b] [list >$fnb]
|
||||
} err]} {
|
||||
error_popup [mc "Error writing commit to file: %s" $err]
|
||||
return
|
||||
}
|
||||
if {[catch {
|
||||
set fd [open "| diff -U$diffcontext $fna $fnb" r]
|
||||
set fd [safe_open_command "diff -U$diffcontext $fna $fnb"]
|
||||
} err]} {
|
||||
error_popup [mc "Error diffing commits: %s" $err]
|
||||
return
|
||||
|
|
@ -9451,10 +9519,7 @@ proc mkpatchgo {} {
|
|||
set newid [$patchtop.tosha1 get]
|
||||
set fname [$patchtop.fname get]
|
||||
set cmd [diffcmd [list $oldid $newid] -p]
|
||||
# trim off the initial "|"
|
||||
set cmd [lrange $cmd 1 end]
|
||||
lappend cmd >$fname &
|
||||
if {[catch {eval exec $cmd} err]} {
|
||||
if {[catch {safe_exec_redirect $cmd [list >$fname &]} err]} {
|
||||
error_popup "[mc "Error creating patch:"] $err" $patchtop
|
||||
}
|
||||
catch {destroy $patchtop}
|
||||
|
|
@ -9523,9 +9588,9 @@ proc domktag {} {
|
|||
}
|
||||
if {[catch {
|
||||
if {$msg != {}} {
|
||||
exec git tag -a -m $msg $tag $id
|
||||
safe_exec [list git tag -a -m $msg $tag $id]
|
||||
} else {
|
||||
exec git tag $tag $id
|
||||
safe_exec [list git tag $tag $id]
|
||||
}
|
||||
} err]} {
|
||||
error_popup "[mc "Error creating tag:"] $err" $mktagtop
|
||||
|
|
@ -9593,7 +9658,7 @@ proc copyreference {} {
|
|||
if {$autosellen < 40} {
|
||||
lappend cmd --abbrev=$autosellen
|
||||
}
|
||||
set reference [eval exec $cmd $rowmenuid]
|
||||
set reference [safe_exec [concat $cmd $rowmenuid]]
|
||||
|
||||
clipboard clear
|
||||
clipboard append $reference
|
||||
|
|
@ -9643,7 +9708,7 @@ proc wrcomgo {} {
|
|||
set id [$wrcomtop.sha1 get]
|
||||
set cmd "echo $id | [$wrcomtop.cmd get]"
|
||||
set fname [$wrcomtop.fname get]
|
||||
if {[catch {exec sh -c $cmd >$fname &} err]} {
|
||||
if {[catch {safe_exec_redirect [list sh -c $cmd] [list >$fname &]} err]} {
|
||||
error_popup "[mc "Error writing commit:"] $err" $wrcomtop
|
||||
}
|
||||
catch {destroy $wrcomtop}
|
||||
|
|
@ -9747,7 +9812,7 @@ proc mkbrgo {top} {
|
|||
nowbusy newbranch
|
||||
update
|
||||
if {[catch {
|
||||
eval exec git branch $cmdargs
|
||||
safe_exec [concat git branch $cmdargs]
|
||||
} err]} {
|
||||
notbusy newbranch
|
||||
error_popup $err
|
||||
|
|
@ -9788,7 +9853,7 @@ proc mvbrgo {top prevname} {
|
|||
nowbusy renamebranch
|
||||
update
|
||||
if {[catch {
|
||||
eval exec git branch $cmdargs
|
||||
safe_exec [concat git branch $cmdargs]
|
||||
} err]} {
|
||||
notbusy renamebranch
|
||||
error_popup $err
|
||||
|
|
@ -9829,7 +9894,7 @@ proc exec_citool {tool_args {baseid {}}} {
|
|||
}
|
||||
}
|
||||
|
||||
eval exec git citool $tool_args &
|
||||
safe_exec_redirect [concat git citool $tool_args] [list &]
|
||||
|
||||
array unset env GIT_AUTHOR_*
|
||||
array set env $save_env
|
||||
|
|
@ -9852,7 +9917,7 @@ proc cherrypick {} {
|
|||
update
|
||||
# Unfortunately git-cherry-pick writes stuff to stderr even when
|
||||
# no error occurs, and exec takes that as an indication of error...
|
||||
if {[catch {exec sh -c "git cherry-pick -r $rowmenuid 2>&1"} err]} {
|
||||
if {[catch {safe_exec [list sh -c "git cherry-pick -r $rowmenuid 2>&1"]} err]} {
|
||||
notbusy cherrypick
|
||||
if {[regexp -line \
|
||||
{Entry '(.*)' (would be overwritten by merge|not uptodate)} \
|
||||
|
|
@ -9914,7 +9979,7 @@ proc revert {} {
|
|||
nowbusy revert [mc "Reverting"]
|
||||
update
|
||||
|
||||
if [catch {exec git revert --no-edit $rowmenuid} err] {
|
||||
if [catch {safe_exec [list git revert --no-edit $rowmenuid]} err] {
|
||||
notbusy revert
|
||||
if [regexp {files would be overwritten by merge:(\n(( |\t)+[^\n]+\n)+)}\
|
||||
$err match files] {
|
||||
|
|
@ -9990,8 +10055,8 @@ proc resethead {} {
|
|||
bind $w <Visibility> "grab $w; focus $w"
|
||||
tkwait window $w
|
||||
if {!$confirm_ok} return
|
||||
if {[catch {set fd [open \
|
||||
[list | git reset --$resettype $rowmenuid 2>@1] r]} err]} {
|
||||
if {[catch {set fd [safe_open_command_redirect \
|
||||
[list git reset --$resettype $rowmenuid] [list 2>@1]]} err]} {
|
||||
error_popup $err
|
||||
} else {
|
||||
dohidelocalchanges
|
||||
|
|
@ -10062,7 +10127,7 @@ proc cobranch {} {
|
|||
|
||||
# check the tree is clean first??
|
||||
set newhead $headmenuhead
|
||||
set command [list | git checkout]
|
||||
set command [list git checkout]
|
||||
if {[string match "remotes/*" $newhead]} {
|
||||
set remote $newhead
|
||||
set newhead [string range $newhead [expr [string last / $newhead] + 1] end]
|
||||
|
|
@ -10076,12 +10141,11 @@ proc cobranch {} {
|
|||
} else {
|
||||
lappend command $newhead
|
||||
}
|
||||
lappend command 2>@1
|
||||
nowbusy checkout [mc "Checking out"]
|
||||
update
|
||||
dohidelocalchanges
|
||||
if {[catch {
|
||||
set fd [open $command r]
|
||||
set fd [safe_open_command_redirect $command [list 2>@1]]
|
||||
} err]} {
|
||||
notbusy checkout
|
||||
error_popup $err
|
||||
|
|
@ -10147,7 +10211,7 @@ proc rmbranch {} {
|
|||
}
|
||||
nowbusy rmbranch
|
||||
update
|
||||
if {[catch {exec git branch -D $head} err]} {
|
||||
if {[catch {safe_exec [list git branch -D $head]} err]} {
|
||||
notbusy rmbranch
|
||||
error_popup $err
|
||||
return
|
||||
|
|
@ -10338,7 +10402,7 @@ proc getallcommits {} {
|
|||
set cachedarcs 0
|
||||
set allccache [file join $gitdir "gitk.cache"]
|
||||
if {![catch {
|
||||
set f [open $allccache r]
|
||||
set f [safe_open_file $allccache r]
|
||||
set allcwait 1
|
||||
getcache $f
|
||||
}]} return
|
||||
|
|
@ -10347,7 +10411,7 @@ proc getallcommits {} {
|
|||
if {$allcwait} {
|
||||
return
|
||||
}
|
||||
set cmd [list | git rev-list --parents]
|
||||
set cmd [list git rev-list --parents]
|
||||
set allcupdate [expr {$seeds ne {}}]
|
||||
if {!$allcupdate} {
|
||||
set ids "--all"
|
||||
|
|
@ -10375,10 +10439,11 @@ proc getallcommits {} {
|
|||
if {$ids ne {}} {
|
||||
if {$ids eq "--all"} {
|
||||
set cmd [concat $cmd "--all"]
|
||||
set fd [safe_open_command $cmd]
|
||||
} else {
|
||||
set cmd [concat $cmd --stdin "<<[join $ids "\\n"]"]
|
||||
set cmd [concat $cmd --stdin]
|
||||
set fd [safe_open_command_redirect $cmd [list "<<[join $ids "\n"]"]]
|
||||
}
|
||||
set fd [open $cmd r]
|
||||
fconfigure $fd -blocking 0
|
||||
incr allcommits
|
||||
nowbusy allcommits
|
||||
|
|
@ -10768,7 +10833,7 @@ proc savecache {} {
|
|||
set cachearc 0
|
||||
set cachedarcs $nextarc
|
||||
catch {
|
||||
set f [open $allccache w]
|
||||
set f [safe_open_file $allccache w]
|
||||
puts $f [list 1 $cachedarcs]
|
||||
run writecache $f
|
||||
}
|
||||
|
|
@ -11471,7 +11536,7 @@ proc add_tag_ctext {tag} {
|
|||
|
||||
if {![info exists cached_tagcontent($tag)]} {
|
||||
catch {
|
||||
set cached_tagcontent($tag) [exec git cat-file -p $tag]
|
||||
set cached_tagcontent($tag) [safe_exec [list git cat-file -p $tag]]
|
||||
}
|
||||
}
|
||||
$ctext insert end "[mc "Tag"]: $tag\n" bold
|
||||
|
|
@ -12382,7 +12447,7 @@ proc gitattr {path attr default} {
|
|||
set r $path_attr_cache($attr,$path)
|
||||
} else {
|
||||
set r "unspecified"
|
||||
if {![catch {set line [exec git check-attr $attr -- $path]}]} {
|
||||
if {![catch {set line [safe_exec [list git check-attr $attr -- $path]]}]} {
|
||||
regexp "(.*): $attr: (.*)" $line m f r
|
||||
}
|
||||
set path_attr_cache($attr,$path) $r
|
||||
|
|
@ -12409,7 +12474,7 @@ proc cache_gitattr {attr pathlist} {
|
|||
while {$newlist ne {}} {
|
||||
set head [lrange $newlist 0 [expr {$lim - 1}]]
|
||||
set newlist [lrange $newlist $lim end]
|
||||
if {![catch {set rlist [eval exec git check-attr $attr -- $head]}]} {
|
||||
if {![catch {set rlist [safe_exec [concat git check-attr $attr -- $head]]}]} {
|
||||
foreach row [split $rlist "\n"] {
|
||||
if {[regexp "(.*): $attr: (.*)" $row m path value]} {
|
||||
if {[string index $path 0] eq "\""} {
|
||||
|
|
@ -12461,11 +12526,11 @@ if {[catch {package require Tk 8.4} err]} {
|
|||
|
||||
# on OSX bring the current Wish process window to front
|
||||
if {[tk windowingsystem] eq "aqua"} {
|
||||
exec osascript -e [format {
|
||||
safe_exec [list osascript -e [format {
|
||||
tell application "System Events"
|
||||
set frontmost of processes whose unix id is %d to true
|
||||
end tell
|
||||
} [pid] ]
|
||||
} [pid] ]]
|
||||
}
|
||||
|
||||
# Unset GIT_TRACE var if set
|
||||
|
|
@ -12713,7 +12778,7 @@ if {$selecthead eq "HEAD"} {
|
|||
if {$i >= [llength $argv] && $revtreeargs ne {}} {
|
||||
# no -- on command line, but some arguments (other than --argscmd)
|
||||
if {[catch {
|
||||
set f [eval exec git rev-parse --no-revs --no-flags $revtreeargs]
|
||||
set f [safe_exec [concat git rev-parse --no-revs --no-flags $revtreeargs]]
|
||||
set cmdline_files [split $f "\n"]
|
||||
set n [llength $cmdline_files]
|
||||
set revtreeargs [lrange $revtreeargs 0 end-$n]
|
||||
|
|
|
|||
|
|
@ -2851,4 +2851,15 @@ test_expect_success 'writing to stdin is rejected' '
|
|||
|
||||
done
|
||||
|
||||
test_expect_success 'writing value with trailing CR not stripped on read' '
|
||||
test_when_finished "rm -rf cr-test" &&
|
||||
|
||||
printf "bar\r\n" >expect &&
|
||||
git init cr-test &&
|
||||
git -C cr-test config set core.foo $(printf "bar\r") &&
|
||||
git -C cr-test config get core.foo >actual &&
|
||||
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
|
|||
|
|
@ -1279,6 +1279,29 @@ test_expect_success 'bundles are downloaded once during fetch --all' '
|
|||
trace-mult.txt >bundle-fetches &&
|
||||
test_line_count = 1 bundle-fetches
|
||||
'
|
||||
|
||||
test_expect_success 'bundles with space in URI are rejected' '
|
||||
test_when_finished "rm -rf busted repo" &&
|
||||
mkdir -p "$HOME/busted/ /$HOME/repo/.git/objects/bundles" &&
|
||||
git clone --bundle-uri="$HTTPD_URL/bogus $HOME/busted/" "$HTTPD_URL/smart/fetch.git" repo 2>err &&
|
||||
test_grep "error: bundle-uri: URI is malformed: " err &&
|
||||
find busted -type f >files &&
|
||||
test_must_be_empty files
|
||||
'
|
||||
|
||||
test_expect_success 'bundles with newline in URI are rejected' '
|
||||
test_when_finished "rm -rf busted repo" &&
|
||||
git clone --bundle-uri="$HTTPD_URL/bogus\nget $HTTPD_URL/bogus $HOME/busted" "$HTTPD_URL/smart/fetch.git" repo 2>err &&
|
||||
test_grep "error: bundle-uri: URI is malformed: " err &&
|
||||
test_path_is_missing "$HOME/busted"
|
||||
'
|
||||
|
||||
test_expect_success 'bundles with newline in target path are rejected' '
|
||||
git clone --bundle-uri="$HTTPD_URL/bogus" "$HTTPD_URL/smart/fetch.git" "$(printf "escape\nget $HTTPD_URL/bogus .")" 2>err &&
|
||||
test_grep "error: bundle-uri: filename is malformed: " err &&
|
||||
test_path_is_missing escape
|
||||
'
|
||||
|
||||
# Do not add tests here unless they use the HTTP server, as they will
|
||||
# not run unless the HTTP dependencies exist.
|
||||
|
||||
|
|
|
|||
|
|
@ -372,4 +372,37 @@ test_expect_success 'checkout -f --recurse-submodules must not use a nested gitd
|
|||
test_path_is_missing nested_checkout/thing2/.git
|
||||
'
|
||||
|
||||
test_expect_success SYMLINKS,!WINDOWS,!MINGW 'submodule must not checkout into different directory' '
|
||||
test_when_finished "rm -rf sub repo bad-clone" &&
|
||||
|
||||
git init sub &&
|
||||
write_script sub/post-checkout <<-\EOF &&
|
||||
touch "$PWD/foo"
|
||||
EOF
|
||||
git -C sub add post-checkout &&
|
||||
git -C sub commit -m hook &&
|
||||
|
||||
git init repo &&
|
||||
git -C repo -c protocol.file.allow=always submodule add "$PWD/sub" sub &&
|
||||
git -C repo mv sub $(printf "sub\r") &&
|
||||
|
||||
# Ensure config values containing CR are wrapped in quotes.
|
||||
git config unset -f repo/.gitmodules submodule.sub.path &&
|
||||
printf "\tpath = \"sub\r\"\n" >>repo/.gitmodules &&
|
||||
|
||||
git config unset -f repo/.git/modules/sub/config core.worktree &&
|
||||
{
|
||||
printf "[core]\n" &&
|
||||
printf "\tworktree = \"../../../sub\r\"\n"
|
||||
} >>repo/.git/modules/sub/config &&
|
||||
|
||||
ln -s .git/modules/sub/hooks repo/sub &&
|
||||
git -C repo add -A &&
|
||||
git -C repo commit -m submodule &&
|
||||
|
||||
git -c protocol.file.allow=always clone --recurse-submodules repo bad-clone &&
|
||||
! test -f "$PWD/foo" &&
|
||||
test -f $(printf "bad-clone/sub\r/post-checkout")
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
|
|||
Loading…
Reference in New Issue