Git fork

Sync with 2.45.4

* maint-2.45:
Git 2.45.4
Git 2.44.4
Git 2.43.7
wincred: avoid buffer overflow in wcsncat()
bundle-uri: fix arbitrary file writes via parameter injection
config: quote values containing CR character
git-gui: sanitize 'exec' arguments: convert new 'cygpath' calls
git-gui: do not mistake command arguments as redirection operators
git-gui: introduce function git_redir for git calls with redirections
git-gui: pass redirections as separate argument to git_read
git-gui: pass redirections as separate argument to _open_stdout_stderr
git-gui: convert git_read*, git_write to be non-variadic
git-gui: override exec and open only on Windows
gitk: sanitize 'open' arguments: revisit recently updated 'open' calls
git-gui: use git_read in githook_read
git-gui: sanitize $PATH on all platforms
git-gui: break out a separate function git_read_nice
git-gui: assure PATH has only absolute elements.
git-gui: remove option --stderr from git_read
git-gui: cleanup git-bash menu item
git-gui: sanitize 'exec' arguments: background
git-gui: avoid auto_execok in do_windows_shortcut
git-gui: sanitize 'exec' arguments: simple cases
git-gui: avoid auto_execok for git-bash menu item
git-gui: treat file names beginning with "|" as relative paths
git-gui: remove unused proc is_shellscript
git-gui: remove git config --list handling for git < 1.5.3
git-gui: remove special treatment of Windows from open_cmd_pipe
git-gui: remove HEAD detachment implementation for git < 1.5.3
git-gui: use only the configured shell
git-gui: remove Tcl 8.4 workaround on 2>@1 redirection
git-gui: make _shellpath usable on startup
git-gui: use [is_Windows], not bad _shellpath
git-gui: _which, only add .exe suffix if not present
gitk: encode arguments correctly with "open"
gitk: sanitize 'open' arguments: command pipeline
gitk: collect construction of blameargs into a single conditional
gitk: sanitize 'open' arguments: simple commands, readable and writable
gitk: sanitize 'open' arguments: simple commands with redirections
gitk: sanitize 'open' arguments: simple commands
gitk: sanitize 'exec' arguments: redirect to process
gitk: sanitize 'exec' arguments: redirections and background
gitk: sanitize 'exec' arguments: redirections
gitk: sanitize 'exec' arguments: 'eval exec'
gitk: sanitize 'exec' arguments: simple cases
gitk: have callers of diffcmd supply pipe symbol when necessary
gitk: treat file names beginning with "|" as relative paths

Signed-off-by: Taylor Blau <me@ttaylorr.com>

+715 -449
+73
Documentation/RelNotes/2.43.7.txt
···
··· 1 + Git v2.43.7 Release Notes 2 + ========================= 3 + 4 + This release includes fixes for CVE-2025-27613, CVE-2025-27614, 5 + CVE-2025-46334, CVE-2025-46835, CVE-2025-48384, CVE-2025-48385, and 6 + CVE-2025-48386. 7 + 8 + Fixes since v2.43.6 9 + ------------------- 10 + 11 + * CVE-2025-27613, Gitk: 12 + 13 + When a user clones an untrusted repository and runs Gitk without 14 + additional command arguments, any writable file can be created and 15 + truncated. The option "Support per-file encoding" must have been 16 + enabled. The operation "Show origin of this line" is affected as 17 + well, regardless of the option being enabled or not. 18 + 19 + * CVE-2025-27614, Gitk: 20 + 21 + A Git repository can be crafted in such a way that a user who has 22 + cloned the repository can be tricked into running any script 23 + supplied by the attacker by invoking `gitk filename`, where 24 + `filename` has a particular structure. 25 + 26 + * CVE-2025-46334, Git GUI (Windows only): 27 + 28 + A malicious repository can ship versions of sh.exe or typical 29 + textconv filter programs such as astextplain. On Windows, path 30 + lookup can find such executables in the worktree. These programs 31 + are invoked when the user selects "Git Bash" or "Browse Files" from 32 + the menu. 33 + 34 + * CVE-2025-46835, Git GUI: 35 + 36 + When a user clones an untrusted repository and is tricked into 37 + editing a file located in a maliciously named directory in the 38 + repository, then Git GUI can create and overwrite any writable 39 + file. 40 + 41 + * CVE-2025-48384, Git: 42 + 43 + When reading a config value, Git strips any trailing carriage 44 + return and line feed (CRLF). When writing a config entry, values 45 + with a trailing CR are not quoted, causing the CR to be lost when 46 + the config is later read. When initializing a submodule, if the 47 + submodule path contains a trailing CR, the altered path is read 48 + resulting in the submodule being checked out to an incorrect 49 + location. If a symlink exists that points the altered path to the 50 + submodule hooks directory, and the submodule contains an executable 51 + post-checkout hook, the script may be unintentionally executed 52 + after checkout. 53 + 54 + * CVE-2025-48385, Git: 55 + 56 + When cloning a repository Git knows to optionally fetch a bundle 57 + advertised by the remote server, which allows the server-side to 58 + offload parts of the clone to a CDN. The Git client does not 59 + perform sufficient validation of the advertised bundles, which 60 + allows the remote side to perform protocol injection. 61 + 62 + This protocol injection can cause the client to write the fetched 63 + bundle to a location controlled by the adversary. The fetched 64 + content is fully controlled by the server, which can in the worst 65 + case lead to arbitrary code execution. 66 + 67 + * CVE-2025-48386, Git: 68 + 69 + The wincred credential helper uses a static buffer (`target`) as a 70 + unique key for storing and comparing against internal storage. This 71 + credential helper does not properly bounds check the available 72 + space remaining in the buffer before appending to it with 73 + `wcsncat()`, leading to potential buffer overflows.
+7
Documentation/RelNotes/2.44.4.txt
···
··· 1 + Git v2.44.4 Release Notes 2 + ========================= 3 + 4 + This release merges up the fixes that appears in v2.43.7 to address 5 + the following CVEs: CVE-2025-27613, CVE-2025-27614, CVE-2025-46334, 6 + CVE-2025-46835, CVE-2025-48384, CVE-2025-48385, and CVE-2025-48386. 7 + See the release notes for v2.43.7 for details.
+7
Documentation/RelNotes/2.45.4.txt
···
··· 1 + Git v2.45.4 Release Notes 2 + ========================= 3 + 4 + This release merges up the fixes that appears in v2.43.7, and v2.44.4 5 + to address the following CVEs: CVE-2025-27613, CVE-2025-27614, 6 + CVE-2025-46334, CVE-2025-46835, CVE-2025-48384, CVE-2025-48385, and 7 + CVE-2025-48386. See the release notes for v2.43.7 for details.
+22
bundle-uri.c
··· 295 struct strbuf line = STRBUF_INIT; 296 int found_get = 0; 297 298 strvec_pushl(&cp.args, "git-remote-https", uri, NULL); 299 cp.err = -1; 300 cp.in = -1;
··· 295 struct strbuf line = STRBUF_INIT; 296 int found_get = 0; 297 298 + /* 299 + * The protocol we speak with git-remote-https(1) uses a space to 300 + * separate between URI and file, so the URI itself must not contain a 301 + * space. If it did, an adversary could change the location where the 302 + * downloaded file is being written to. 303 + * 304 + * Similarly, we use newlines to separate commands from one another. 305 + * Consequently, neither the URI nor the file must contain a newline or 306 + * otherwise an adversary could inject arbitrary commands. 307 + * 308 + * TODO: Restricting newlines in the target paths may break valid 309 + * usecases, even if those are a bit more on the esoteric side. 310 + * If this ever becomes a problem we should probably think about 311 + * alternatives. One alternative could be to use NUL-delimited 312 + * requests in git-remote-http(1). Another alternative could be 313 + * to use URL quoting. 314 + */ 315 + if (strpbrk(uri, " \n")) 316 + return error("bundle-uri: URI is malformed: '%s'", file); 317 + if (strchr(file, '\n')) 318 + return error("bundle-uri: filename is malformed: '%s'", file); 319 + 320 strvec_pushl(&cp.args, "git-remote-https", uri, NULL); 321 cp.err = -1; 322 cp.in = -1;
+1 -1
config.c
··· 3063 if (value[0] == ' ') 3064 quote = "\""; 3065 for (i = 0; value[i]; i++) 3066 - if (value[i] == ';' || value[i] == '#') 3067 quote = "\""; 3068 if (i && value[i - 1] == ' ') 3069 quote = "\"";
··· 3063 if (value[0] == ' ') 3064 quote = "\""; 3065 for (i = 0; value[i]; i++) 3066 + if (value[i] == ';' || value[i] == '#' || value[i] == '\r') 3067 quote = "\""; 3068 if (i && value[i - 1] == ' ') 3069 quote = "\"";
+15 -7
contrib/credential/wincred/git-credential-wincred.c
··· 37 static WCHAR *wusername, *password, *protocol, *host, *path, target[1024], 38 *password_expiry_utc, *oauth_refresh_token; 39 40 static void write_item(const char *what, LPCWSTR wbuf, int wlen) 41 { 42 char *buf; ··· 328 329 /* prepare 'target', the unique key for the credential */ 330 wcscpy(target, L"git:"); 331 - wcsncat(target, protocol, ARRAY_SIZE(target)); 332 - wcsncat(target, L"://", ARRAY_SIZE(target)); 333 if (wusername) { 334 - wcsncat(target, wusername, ARRAY_SIZE(target)); 335 - wcsncat(target, L"@", ARRAY_SIZE(target)); 336 } 337 if (host) 338 - wcsncat(target, host, ARRAY_SIZE(target)); 339 if (path) { 340 - wcsncat(target, L"/", ARRAY_SIZE(target)); 341 - wcsncat(target, path, ARRAY_SIZE(target)); 342 } 343 344 if (!strcmp(argv[1], "get"))
··· 37 static WCHAR *wusername, *password, *protocol, *host, *path, target[1024], 38 *password_expiry_utc, *oauth_refresh_token; 39 40 + static void target_append(const WCHAR *src) 41 + { 42 + size_t avail = ARRAY_SIZE(target) - wcslen(target) - 1; /* -1 for NUL */ 43 + if (avail < wcslen(src)) 44 + die("target buffer overflow"); 45 + wcsncat(target, src, avail); 46 + } 47 + 48 static void write_item(const char *what, LPCWSTR wbuf, int wlen) 49 { 50 char *buf; ··· 336 337 /* prepare 'target', the unique key for the credential */ 338 wcscpy(target, L"git:"); 339 + target_append(protocol); 340 + target_append(L"://"); 341 if (wusername) { 342 + target_append(wusername); 343 + target_append(L"@"); 344 } 345 if (host) 346 + target_append(host); 347 if (path) { 348 + target_append(L"/"); 349 + target_append(path); 350 } 351 352 if (!strcmp(argv[1], "get"))
+266 -242
git-gui/git-gui.sh
··· 77 78 ###################################################################### 79 ## 80 - ## PATH lookup 81 82 set _search_path {} 83 - proc _which {what args} { 84 - global env _search_exe _search_path 85 86 - if {$_search_path eq {}} { 87 - if {[is_Windows]} { 88 - set gitguidir [file dirname [info script]] 89 - regsub -all ";" $gitguidir "\\;" gitguidir 90 - set env(PATH) "$gitguidir;$env(PATH)" 91 - set _search_path [split $env(PATH) {;}] 92 - # Skip empty `PATH` elements 93 - set _search_path [lsearch -all -inline -not -exact \ 94 - $_search_path ""] 95 - set _search_exe .exe 96 } else { 97 - set _search_path [split $env(PATH) :] 98 - set _search_exe {} 99 } 100 } 101 102 - if {[is_Windows] && [lsearch -exact $args -script] >= 0} { 103 - set suffix {} 104 - } else { 105 - set suffix $_search_exe 106 - } 107 108 - foreach p $_search_path { 109 - set p [file join $p $what$suffix] 110 - if {[file exists $p]} { 111 - return [file normalize $p] 112 } 113 } 114 - return {} 115 - } 116 117 - proc sanitize_command_line {command_line from_index} { 118 - set i $from_index 119 - while {$i < [llength $command_line]} { 120 - set cmd [lindex $command_line $i] 121 - if {[llength [file split $cmd]] < 2} { 122 - set fullpath [_which $cmd] 123 - if {$fullpath eq ""} { 124 - throw {NOT-FOUND} "$cmd not found in PATH" 125 - } 126 - lset command_line $i $fullpath 127 - } 128 129 - # handle piped commands, e.g. `exec A | B` 130 - for {incr i} {$i < [llength $command_line]} {incr i} { 131 - if {[lindex $command_line $i] eq "|"} { 132 incr i 133 break 134 } 135 } 136 } 137 - return $command_line 138 - } 139 140 - # Override `exec` to avoid unsafe PATH lookup 141 142 - rename exec real_exec 143 144 - proc exec {args} { 145 - # skip options 146 - for {set i 0} {$i < [llength $args]} {incr i} { 147 - set arg [lindex $args $i] 148 - if {$arg eq "--"} { 149 - incr i 150 - break 151 - } 152 - if {[string range $arg 0 0] ne "-"} { 153 - break 154 } 155 } 156 - set args [sanitize_command_line $args $i] 157 - uplevel 1 real_exec $args 158 } 159 160 - # Override `open` to avoid unsafe PATH lookup 161 162 - rename open real_open 163 164 - proc open {args} { 165 - set arg0 [lindex $args 0] 166 - if {[string range $arg0 0 0] eq "|"} { 167 - set command_line [string trim [string range $arg0 1 end]] 168 - lset args 0 "| [sanitize_command_line $command_line 0]" 169 } 170 - uplevel 1 real_open $args 171 } 172 173 ###################################################################### 174 ## ··· 270 271 if {[tk windowingsystem] eq "aqua"} { 272 catch { 273 - exec osascript -e [format { 274 tell application "System Events" 275 set frontmost of processes whose unix id is %d to true 276 end tell 277 - } [pid]] 278 } 279 } 280 ··· 304 # branches). 305 set _last_merged_branch {} 306 307 proc shellpath {} { 308 - global _shellpath env 309 - if {[string match @@* $_shellpath]} { 310 - if {[info exists env(SHELL)]} { 311 - return $env(SHELL) 312 - } else { 313 - return /bin/sh 314 - } 315 - } 316 return $_shellpath 317 } 318 ··· 494 # Tcl on Windows doesn't know it. 495 # 496 set p [gitexec git-$name] 497 - set f [open $p r] 498 set s [gets $f] 499 close $f 500 ··· 524 return $v 525 } 526 527 - # Test a file for a hashbang to identify executable scripts on Windows. 528 - proc is_shellscript {filename} { 529 - if {![file exists $filename]} {return 0} 530 - set f [open $filename r] 531 - fconfigure $f -encoding binary 532 - set magic [read $f 2] 533 - close $f 534 - return [expr {$magic eq "#!"}] 535 - } 536 - 537 - # Run a command connected via pipes on stdout. 538 # This is for use with textconv filters and uses sh -c "..." to allow it to 539 - # contain a command with arguments. On windows we must check for shell 540 - # scripts specifically otherwise just call the filter command. 541 proc open_cmd_pipe {cmd path} { 542 - global env 543 - if {![file executable [shellpath]]} { 544 - set exe [auto_execok [lindex $cmd 0]] 545 - if {[is_shellscript [lindex $exe 0]]} { 546 - set run [linsert [auto_execok sh] end -c "$cmd \"\$0\"" $path] 547 - } else { 548 - set run [concat $exe [lrange $cmd 1 end] $path] 549 - } 550 - } else { 551 - set run [list [shellpath] -c "$cmd \"\$0\"" $path] 552 - } 553 return [open |$run r] 554 } 555 ··· 559 560 if {![info exists _nice]} { 561 set _nice [_which nice] 562 - if {[catch {exec $_nice git version}]} { 563 set _nice {} 564 } elseif {[is_Windows] && [file dirname $_nice] ne [file dirname $::_git]} { 565 set _nice {} ··· 571 } 572 573 proc git {args} { 574 - set fd [eval [list git_read] $args] 575 fconfigure $fd -translation binary -encoding utf-8 576 set result [string trimright [read $fd] "\n"] 577 close $fd ··· 581 return $result 582 } 583 584 - proc _open_stdout_stderr {cmd} { 585 - _trace_exec $cmd 586 if {[catch { 587 - set fd [open [concat [list | ] $cmd] r] 588 - } err]} { 589 - if { [lindex $cmd end] eq {2>@1} 590 - && $err eq {can not find channel named "1"} 591 - } { 592 - # Older versions of Tcl 8.4 don't have this 2>@1 IO 593 - # redirect operator. Fallback to |& cat for those. 594 - # The command was not actually started, so its safe 595 - # to try to start it a second time. 596 - # 597 - set fd [open [concat \ 598 - [list | ] \ 599 - [lrange $cmd 0 end-1] \ 600 - [list |& cat] \ 601 - ] r] 602 - } else { 603 - error $err 604 - } 605 } 606 fconfigure $fd -eofchar {} 607 return $fd 608 } 609 610 - proc git_read {args} { 611 - set opt [list] 612 - 613 - while {1} { 614 - switch -- [lindex $args 0] { 615 - --nice { 616 - _lappend_nice opt 617 - } 618 - 619 - --stderr { 620 - lappend args 2>@1 621 - } 622 - 623 - default { 624 - break 625 - } 626 627 - } 628 - 629 - set args [lrange $args 1 end] 630 - } 631 - 632 - set cmdp [_git_cmd [lindex $args 0]] 633 - set args [lrange $args 1 end] 634 - 635 - return [_open_stdout_stderr [concat $opt $cmdp $args]] 636 } 637 638 - proc git_write {args} { 639 set opt [list] 640 641 - while {1} { 642 - switch -- [lindex $args 0] { 643 - --nice { 644 - _lappend_nice opt 645 - } 646 647 - default { 648 - break 649 - } 650 651 - } 652 653 - set args [lrange $args 1 end] 654 - } 655 656 - set cmdp [_git_cmd [lindex $args 0]] 657 - set args [lrange $args 1 end] 658 - 659 - _trace_exec [concat $opt $cmdp $args] 660 - return [open [concat [list | ] $opt $cmdp $args] w] 661 } 662 663 proc githook_read {hook_name args} { 664 - set cmd [concat git hook run --ignore-missing $hook_name -- $args 2>@1] 665 - return [_open_stdout_stderr $cmd] 666 } 667 668 proc kill_file_process {fd} { ··· 670 671 catch { 672 if {[is_Windows]} { 673 - exec taskkill /pid $process 674 } else { 675 - exec kill $process 676 } 677 } 678 } ··· 698 proc load_current_branch {} { 699 global current_branch is_detached 700 701 - set fd [open [gitdir HEAD] r] 702 fconfigure $fd -translation binary -encoding utf-8 703 if {[gets $fd ref] < 1} { 704 set ref {} ··· 1060 ## configure our library 1061 1062 set idx [file join $oguilib tclIndex] 1063 - if {[catch {set fd [open $idx r]} err]} { 1064 catch {wm withdraw .} 1065 tk_messageBox \ 1066 -icon error \ ··· 1098 ## 1099 ## config file parsing 1100 1101 - git-version proc _parse_config {arr_name args} { 1102 - >= 1.5.3 { 1103 - upvar $arr_name arr 1104 - array unset arr 1105 - set buf {} 1106 - catch { 1107 - set fd_rc [eval \ 1108 - [list git_read config] \ 1109 - $args \ 1110 - [list --null --list]] 1111 - fconfigure $fd_rc -translation binary -encoding utf-8 1112 - set buf [read $fd_rc] 1113 - close $fd_rc 1114 - } 1115 - foreach line [split $buf "\0"] { 1116 - if {[regexp {^([^\n]+)\n(.*)$} $line line name value]} { 1117 - if {[is_many_config $name]} { 1118 - lappend arr($name) $value 1119 - } else { 1120 - set arr($name) $value 1121 - } 1122 - } elseif {[regexp {^([^\n]+)$} $line line name]} { 1123 - # no value given, but interpreting them as 1124 - # boolean will be handled as true 1125 - set arr($name) {} 1126 - } 1127 - } 1128 } 1129 - default { 1130 - upvar $arr_name arr 1131 - array unset arr 1132 - catch { 1133 - set fd_rc [eval [list git_read config --list] $args] 1134 - while {[gets $fd_rc line] >= 0} { 1135 - if {[regexp {^([^=]+)=(.*)$} $line line name value]} { 1136 - if {[is_many_config $name]} { 1137 - lappend arr($name) $value 1138 - } else { 1139 - set arr($name) $value 1140 - } 1141 - } elseif {[regexp {^([^=]+)$} $line line name]} { 1142 - # no value given, but interpreting them as 1143 - # boolean will be handled as true 1144 - set arr($name) {} 1145 - } 1146 } 1147 - close $fd_rc 1148 } 1149 } 1150 } ··· 1420 set merge_head [gitdir MERGE_HEAD] 1421 if {[file exists $merge_head]} { 1422 set ct merge 1423 - set fd_mh [open $merge_head r] 1424 while {[gets $fd_mh line] >= 0} { 1425 lappend mh $line 1426 } ··· 1439 return $p 1440 } 1441 if {$empty_tree eq {}} { 1442 - set empty_tree [git mktree << {}] 1443 } 1444 return $empty_tree 1445 } ··· 1498 } else { 1499 set rescan_active 1 1500 ui_status [mc "Refreshing file status..."] 1501 - set fd_rf [git_read update-index \ 1502 -q \ 1503 --unmerged \ 1504 --ignore-missing \ 1505 --refresh \ 1506 - ] 1507 fconfigure $fd_rf -blocking 0 -translation binary 1508 fileevent $fd_rf readable \ 1509 [list rescan_stage2 $fd_rf $after] ··· 1543 set rescan_active 2 1544 ui_status [mc "Scanning for modified files ..."] 1545 if {[git-version >= "1.7.2"]} { 1546 - set fd_di [git_read diff-index --cached --ignore-submodules=dirty -z [PARENT]] 1547 } else { 1548 - set fd_di [git_read diff-index --cached -z [PARENT]] 1549 } 1550 - set fd_df [git_read diff-files -z] 1551 1552 fconfigure $fd_di -blocking 0 -translation binary -encoding binary 1553 fconfigure $fd_df -blocking 0 -translation binary -encoding binary ··· 1556 fileevent $fd_df readable [list read_diff_files $fd_df $after] 1557 1558 if {[is_config_true gui.displayuntracked]} { 1559 - set fd_lo [eval git_read ls-files --others -z $ls_others] 1560 fconfigure $fd_lo -blocking 0 -translation binary -encoding binary 1561 fileevent $fd_lo readable [list read_ls_others $fd_lo $after] 1562 incr rescan_active ··· 1568 1569 set f [gitdir $file] 1570 if {[file isfile $f]} { 1571 - if {[catch {set fd [open $f r]}]} { 1572 return 0 1573 } 1574 fconfigure $fd -eofchar {} ··· 1592 # it will be .git/MERGE_MSG (merge), .git/SQUASH_MSG (squash), or an 1593 # empty file but existent file. 1594 1595 - set fd_pcm [open [gitdir PREPARE_COMMIT_MSG] a] 1596 1597 if {[file isfile [gitdir MERGE_MSG]]} { 1598 set pcm_source "merge" 1599 - set fd_mm [open [gitdir MERGE_MSG] r] 1600 fconfigure $fd_mm -encoding utf-8 1601 puts -nonewline $fd_pcm [read $fd_mm] 1602 close $fd_mm 1603 } elseif {[file isfile [gitdir SQUASH_MSG]]} { 1604 set pcm_source "squash" 1605 - set fd_sm [open [gitdir SQUASH_MSG] r] 1606 fconfigure $fd_sm -encoding utf-8 1607 puts -nonewline $fd_pcm [read $fd_sm] 1608 close $fd_sm 1609 } elseif {[file isfile [get_config commit.template]]} { 1610 set pcm_source "template" 1611 - set fd_sm [open [get_config commit.template] r] 1612 fconfigure $fd_sm -encoding utf-8 1613 puts -nonewline $fd_pcm [read $fd_sm] 1614 close $fd_sm ··· 2198 unset env(GIT_DIR) 2199 unset env(GIT_WORK_TREE) 2200 } 2201 - eval exec $cmd $revs "--" "--" & 2202 2203 set env(GIT_DIR) $_gitdir 2204 set env(GIT_WORK_TREE) $_gitworktree ··· 2235 set pwd [pwd] 2236 cd $current_diff_path 2237 2238 - eval exec $exe gui & 2239 2240 set env(GIT_DIR) $_gitdir 2241 set env(GIT_WORK_TREE) $_gitworktree ··· 2266 2267 proc do_explore {} { 2268 global _gitworktree 2269 - set explorer [get_explorer] 2270 - eval exec $explorer [list [file nativename $_gitworktree]] & 2271 } 2272 2273 # Open file relative to the working tree by the default associated app. 2274 proc do_file_open {file} { 2275 global _gitworktree 2276 - set explorer [get_explorer] 2277 set full_file_path [file join $_gitworktree $file] 2278 - exec $explorer [file nativename $full_file_path] & 2279 } 2280 2281 set is_quitting 0 ··· 2309 if {![string match amend* $commit_type] 2310 && $msg ne {}} { 2311 catch { 2312 - set fd [open $save w] 2313 fconfigure $fd -encoding utf-8 2314 puts -nonewline $fd $msg 2315 close $fd ··· 2753 2754 if {[is_Windows]} { 2755 # Use /git-bash.exe if available 2756 - set normalized [file normalize $::argv0] 2757 - regsub "/mingw../libexec/git-core/git-gui$" \ 2758 - $normalized "/git-bash.exe" cmdLine 2759 - if {$cmdLine != $normalized && [file exists $cmdLine]} { 2760 - set cmdLine [list "Git Bash" $cmdLine &] 2761 } else { 2762 - set cmdLine [list "Git Bash" bash --login -l &] 2763 } 2764 .mbar.repository add command \ 2765 -label [mc "Git Bash"] \ 2766 - -command {eval exec [auto_execok start] $cmdLine} 2767 } 2768 2769 if {[is_Windows] || ![is_bare]} { ··· 4070 } 4071 } elseif {$m} { 4072 catch { 4073 - set fd [open [gitdir GITGUI_BCK] w] 4074 fconfigure $fd -encoding utf-8 4075 puts -nonewline $fd $msg 4076 close $fd
··· 77 78 ###################################################################### 79 ## 80 + ## PATH lookup. Sanitize $PATH, assure exec/open use only that 81 + 82 + if {[is_Windows]} { 83 + set _path_sep {;} 84 + set _search_exe .exe 85 + } else { 86 + set _path_sep {:} 87 + set _search_exe {} 88 + } 89 + 90 + if {[is_Windows]} { 91 + set gitguidir [file dirname [info script]] 92 + regsub -all ";" $gitguidir "\\;" gitguidir 93 + set env(PATH) "$gitguidir;$env(PATH)" 94 + } 95 96 set _search_path {} 97 + set _path_seen [dict create] 98 + foreach p [split $env(PATH) $_path_sep] { 99 + # Keep only absolute paths, getting rid of ., empty, etc. 100 + if {[file pathtype $p] ne {absolute}} { 101 + continue 102 + } 103 + # Keep only the first occurence of any duplicates. 104 + set norm_p [file normalize $p] 105 + if {[dict exists $_path_seen $norm_p]} { 106 + continue 107 + } 108 + dict set _path_seen $norm_p 1 109 + lappend _search_path $norm_p 110 + } 111 + unset _path_seen 112 113 + set env(PATH) [join $_search_path $_path_sep] 114 + 115 + if {[is_Windows]} { 116 + proc _which {what args} { 117 + global _search_exe _search_path 118 + 119 + if {[lsearch -exact $args -script] >= 0} { 120 + set suffix {} 121 + } elseif {[string match *$_search_exe [string tolower $what]]} { 122 + # The search string already has the file extension 123 + set suffix {} 124 } else { 125 + set suffix $_search_exe 126 + } 127 + 128 + foreach p $_search_path { 129 + set p [file join $p $what$suffix] 130 + if {[file exists $p]} { 131 + return [file normalize $p] 132 + } 133 } 134 + return {} 135 } 136 137 + proc sanitize_command_line {command_line from_index} { 138 + set i $from_index 139 + while {$i < [llength $command_line]} { 140 + set cmd [lindex $command_line $i] 141 + if {[llength [file split $cmd]] < 2} { 142 + set fullpath [_which $cmd] 143 + if {$fullpath eq ""} { 144 + throw {NOT-FOUND} "$cmd not found in PATH" 145 + } 146 + lset command_line $i $fullpath 147 + } 148 149 + # handle piped commands, e.g. `exec A | B` 150 + for {incr i} {$i < [llength $command_line]} {incr i} { 151 + if {[lindex $command_line $i] eq "|"} { 152 + incr i 153 + break 154 + } 155 + } 156 } 157 + return $command_line 158 } 159 + 160 + # Override `exec` to avoid unsafe PATH lookup 161 162 + rename exec real_exec 163 164 + proc exec {args} { 165 + # skip options 166 + for {set i 0} {$i < [llength $args]} {incr i} { 167 + set arg [lindex $args $i] 168 + if {$arg eq "--"} { 169 incr i 170 + break 171 + } 172 + if {[string range $arg 0 0] ne "-"} { 173 break 174 } 175 } 176 + set args [sanitize_command_line $args $i] 177 + uplevel 1 real_exec $args 178 } 179 180 + # Override `open` to avoid unsafe PATH lookup 181 182 + rename open real_open 183 184 + proc open {args} { 185 + set arg0 [lindex $args 0] 186 + if {[string range $arg0 0 0] eq "|"} { 187 + set command_line [string trim [string range $arg0 1 end]] 188 + lset args 0 "| [sanitize_command_line $command_line 0]" 189 } 190 + uplevel 1 real_open $args 191 } 192 + 193 + } else { 194 + # On non-Windows platforms, auto_execok, exec, and open are safe, and will 195 + # use the sanitized search path. But, we need _which for these. 196 + 197 + proc _which {what args} { 198 + return [lindex [auto_execok $what] 0] 199 + } 200 } 201 202 + # Wrap exec/open to sanitize arguments 203 204 + # unsafe arguments begin with redirections or the pipe or background operators 205 + proc is_arg_unsafe {arg} { 206 + regexp {^([<|>&]|2>)} $arg 207 + } 208 + 209 + proc make_arg_safe {arg} { 210 + if {[is_arg_unsafe $arg]} { 211 + set arg [file join . $arg] 212 + } 213 + return $arg 214 + } 215 + 216 + proc make_arglist_safe {arglist} { 217 + set res {} 218 + foreach arg $arglist { 219 + lappend res [make_arg_safe $arg] 220 + } 221 + return $res 222 + } 223 + 224 + # executes one command 225 + # no redirections or pipelines are possible 226 + # cmd is a list that specifies the command and its arguments 227 + # calls `exec` and returns its value 228 + proc safe_exec {cmd} { 229 + eval exec [make_arglist_safe $cmd] 230 + } 231 + 232 + # executes one command in the background 233 + # no redirections or pipelines are possible 234 + # cmd is a list that specifies the command and its arguments 235 + # calls `exec` and returns its value 236 + proc safe_exec_bg {cmd} { 237 + eval exec [make_arglist_safe $cmd] & 238 + } 239 240 + proc safe_open_file {filename flags} { 241 + # a file name starting with "|" would attempt to run a process 242 + # but such a file name must be treated as a relative path 243 + # hide the "|" behind "./" 244 + if {[string index $filename 0] eq "|"} { 245 + set filename [file join . $filename] 246 } 247 + open $filename $flags 248 } 249 + 250 + # End exec/open wrappers 251 252 ###################################################################### 253 ## ··· 349 350 if {[tk windowingsystem] eq "aqua"} { 351 catch { 352 + safe_exec [list osascript -e [format { 353 tell application "System Events" 354 set frontmost of processes whose unix id is %d to true 355 end tell 356 + } [pid]]] 357 } 358 } 359 ··· 383 # branches). 384 set _last_merged_branch {} 385 386 + # for testing, allow unconfigured _shellpath 387 + if {[string match @@* $_shellpath]} { 388 + if {[info exists env(SHELL)]} { 389 + set _shellpath $env(SHELL) 390 + } else { 391 + set _shellpath /bin/sh 392 + } 393 + } 394 + 395 + if {[is_Windows]} { 396 + set _shellpath [safe_exec [list cygpath -m $_shellpath]] 397 + } 398 + 399 + if {![file executable $_shellpath] || \ 400 + !([file pathtype $_shellpath] eq {absolute})} { 401 + set errmsg "The defined shell ('$_shellpath') is not usable, \ 402 + it must be an absolute path to an executable." 403 + puts stderr $errmsg 404 + 405 + catch {wm withdraw .} 406 + tk_messageBox \ 407 + -icon error \ 408 + -type ok \ 409 + -title "git-gui: configuration error" \ 410 + -message $errmsg 411 + exit 1 412 + } 413 + 414 + 415 proc shellpath {} { 416 + global _shellpath 417 return $_shellpath 418 } 419 ··· 595 # Tcl on Windows doesn't know it. 596 # 597 set p [gitexec git-$name] 598 + set f [safe_open_file $p r] 599 set s [gets $f] 600 close $f 601 ··· 625 return $v 626 } 627 628 + # Run a shell command connected via pipes on stdout. 629 # This is for use with textconv filters and uses sh -c "..." to allow it to 630 + # contain a command with arguments. We presume this 631 + # to be a shellscript that the configured shell (/bin/sh by default) knows 632 + # how to run. 633 proc open_cmd_pipe {cmd path} { 634 + set run [list [shellpath] -c "$cmd \"\$0\"" $path] 635 + set run [make_arglist_safe $run] 636 return [open |$run r] 637 } 638 ··· 642 643 if {![info exists _nice]} { 644 set _nice [_which nice] 645 + if {[catch {safe_exec [list $_nice git version]}]} { 646 set _nice {} 647 } elseif {[is_Windows] && [file dirname $_nice] ne [file dirname $::_git]} { 648 set _nice {} ··· 654 } 655 656 proc git {args} { 657 + git_redir $args {} 658 + } 659 + 660 + proc git_redir {cmd redir} { 661 + set fd [git_read $cmd $redir] 662 fconfigure $fd -translation binary -encoding utf-8 663 set result [string trimright [read $fd] "\n"] 664 close $fd ··· 668 return $result 669 } 670 671 + proc safe_open_command {cmd {redir {}}} { 672 + set cmd [make_arglist_safe $cmd] 673 + _trace_exec [concat $cmd $redir] 674 if {[catch { 675 + set fd [open [concat [list | ] $cmd $redir] r] 676 + } err]} { 677 + error $err 678 } 679 fconfigure $fd -eofchar {} 680 return $fd 681 } 682 683 + proc git_read {cmd {redir {}}} { 684 + set cmdp [_git_cmd [lindex $cmd 0]] 685 + set cmd [lrange $cmd 1 end] 686 687 + return [safe_open_command [concat $cmdp $cmd] $redir] 688 } 689 690 + proc git_read_nice {cmd} { 691 set opt [list] 692 693 + _lappend_nice opt 694 695 + set cmdp [_git_cmd [lindex $cmd 0]] 696 + set cmd [lrange $cmd 1 end] 697 698 + return [safe_open_command [concat $opt $cmdp $cmd]] 699 + } 700 701 + proc git_write {cmd} { 702 + set cmd [make_arglist_safe $cmd] 703 + set cmdp [_git_cmd [lindex $cmd 0]] 704 + set cmd [lrange $cmd 1 end] 705 706 + _trace_exec [concat $cmdp $cmd] 707 + return [open [concat [list | ] $cmdp $cmd] w] 708 } 709 710 proc githook_read {hook_name args} { 711 + git_read [concat [list hook run --ignore-missing $hook_name --] $args] [list 2>@1] 712 } 713 714 proc kill_file_process {fd} { ··· 716 717 catch { 718 if {[is_Windows]} { 719 + safe_exec [list taskkill /pid $process] 720 } else { 721 + safe_exec [list kill $process] 722 } 723 } 724 } ··· 744 proc load_current_branch {} { 745 global current_branch is_detached 746 747 + set fd [safe_open_file [gitdir HEAD] r] 748 fconfigure $fd -translation binary -encoding utf-8 749 if {[gets $fd ref] < 1} { 750 set ref {} ··· 1106 ## configure our library 1107 1108 set idx [file join $oguilib tclIndex] 1109 + if {[catch {set fd [safe_open_file $idx r]} err]} { 1110 catch {wm withdraw .} 1111 tk_messageBox \ 1112 -icon error \ ··· 1144 ## 1145 ## config file parsing 1146 1147 + proc _parse_config {arr_name args} { 1148 + upvar $arr_name arr 1149 + array unset arr 1150 + set buf {} 1151 + catch { 1152 + set fd_rc [git_read \ 1153 + [concat config \ 1154 + $args \ 1155 + --null --list]] 1156 + fconfigure $fd_rc -translation binary -encoding utf-8 1157 + set buf [read $fd_rc] 1158 + close $fd_rc 1159 } 1160 + foreach line [split $buf "\0"] { 1161 + if {[regexp {^([^\n]+)\n(.*)$} $line line name value]} { 1162 + if {[is_many_config $name]} { 1163 + lappend arr($name) $value 1164 + } else { 1165 + set arr($name) $value 1166 } 1167 + } elseif {[regexp {^([^\n]+)$} $line line name]} { 1168 + # no value given, but interpreting them as 1169 + # boolean will be handled as true 1170 + set arr($name) {} 1171 } 1172 } 1173 } ··· 1443 set merge_head [gitdir MERGE_HEAD] 1444 if {[file exists $merge_head]} { 1445 set ct merge 1446 + set fd_mh [safe_open_file $merge_head r] 1447 while {[gets $fd_mh line] >= 0} { 1448 lappend mh $line 1449 } ··· 1462 return $p 1463 } 1464 if {$empty_tree eq {}} { 1465 + set empty_tree [git_redir [list mktree] [list << {}]] 1466 } 1467 return $empty_tree 1468 } ··· 1521 } else { 1522 set rescan_active 1 1523 ui_status [mc "Refreshing file status..."] 1524 + set fd_rf [git_read [list update-index \ 1525 -q \ 1526 --unmerged \ 1527 --ignore-missing \ 1528 --refresh \ 1529 + ]] 1530 fconfigure $fd_rf -blocking 0 -translation binary 1531 fileevent $fd_rf readable \ 1532 [list rescan_stage2 $fd_rf $after] ··· 1566 set rescan_active 2 1567 ui_status [mc "Scanning for modified files ..."] 1568 if {[git-version >= "1.7.2"]} { 1569 + set fd_di [git_read [list diff-index --cached --ignore-submodules=dirty -z [PARENT]]] 1570 } else { 1571 + set fd_di [git_read [list diff-index --cached -z [PARENT]]] 1572 } 1573 + set fd_df [git_read [list diff-files -z]] 1574 1575 fconfigure $fd_di -blocking 0 -translation binary -encoding binary 1576 fconfigure $fd_df -blocking 0 -translation binary -encoding binary ··· 1579 fileevent $fd_df readable [list read_diff_files $fd_df $after] 1580 1581 if {[is_config_true gui.displayuntracked]} { 1582 + set fd_lo [git_read [concat ls-files --others -z $ls_others]] 1583 fconfigure $fd_lo -blocking 0 -translation binary -encoding binary 1584 fileevent $fd_lo readable [list read_ls_others $fd_lo $after] 1585 incr rescan_active ··· 1591 1592 set f [gitdir $file] 1593 if {[file isfile $f]} { 1594 + if {[catch {set fd [safe_open_file $f r]}]} { 1595 return 0 1596 } 1597 fconfigure $fd -eofchar {} ··· 1615 # it will be .git/MERGE_MSG (merge), .git/SQUASH_MSG (squash), or an 1616 # empty file but existent file. 1617 1618 + set fd_pcm [safe_open_file [gitdir PREPARE_COMMIT_MSG] a] 1619 1620 if {[file isfile [gitdir MERGE_MSG]]} { 1621 set pcm_source "merge" 1622 + set fd_mm [safe_open_file [gitdir MERGE_MSG] r] 1623 fconfigure $fd_mm -encoding utf-8 1624 puts -nonewline $fd_pcm [read $fd_mm] 1625 close $fd_mm 1626 } elseif {[file isfile [gitdir SQUASH_MSG]]} { 1627 set pcm_source "squash" 1628 + set fd_sm [safe_open_file [gitdir SQUASH_MSG] r] 1629 fconfigure $fd_sm -encoding utf-8 1630 puts -nonewline $fd_pcm [read $fd_sm] 1631 close $fd_sm 1632 } elseif {[file isfile [get_config commit.template]]} { 1633 set pcm_source "template" 1634 + set fd_sm [safe_open_file [get_config commit.template] r] 1635 fconfigure $fd_sm -encoding utf-8 1636 puts -nonewline $fd_pcm [read $fd_sm] 1637 close $fd_sm ··· 2221 unset env(GIT_DIR) 2222 unset env(GIT_WORK_TREE) 2223 } 2224 + safe_exec_bg [concat $cmd $revs "--" "--"] 2225 2226 set env(GIT_DIR) $_gitdir 2227 set env(GIT_WORK_TREE) $_gitworktree ··· 2258 set pwd [pwd] 2259 cd $current_diff_path 2260 2261 + safe_exec_bg [concat $exe gui] 2262 2263 set env(GIT_DIR) $_gitdir 2264 set env(GIT_WORK_TREE) $_gitworktree ··· 2289 2290 proc do_explore {} { 2291 global _gitworktree 2292 + set cmd [get_explorer] 2293 + lappend cmd [file nativename $_gitworktree] 2294 + safe_exec_bg $cmd 2295 } 2296 2297 # Open file relative to the working tree by the default associated app. 2298 proc do_file_open {file} { 2299 global _gitworktree 2300 + set cmd [get_explorer] 2301 set full_file_path [file join $_gitworktree $file] 2302 + lappend cmd [file nativename $full_file_path] 2303 + safe_exec_bg $cmd 2304 } 2305 2306 set is_quitting 0 ··· 2334 if {![string match amend* $commit_type] 2335 && $msg ne {}} { 2336 catch { 2337 + set fd [safe_open_file $save w] 2338 fconfigure $fd -encoding utf-8 2339 puts -nonewline $fd $msg 2340 close $fd ··· 2778 2779 if {[is_Windows]} { 2780 # Use /git-bash.exe if available 2781 + set _git_bash [safe_exec [list cygpath -m /git-bash.exe]] 2782 + if {[file executable $_git_bash]} { 2783 + set _bash_cmdline [list "Git Bash" $_git_bash] 2784 } else { 2785 + set _bash_cmdline [list "Git Bash" bash --login -l] 2786 } 2787 .mbar.repository add command \ 2788 -label [mc "Git Bash"] \ 2789 + -command {safe_exec_bg [concat [list [_which cmd] /c start] $_bash_cmdline]} 2790 + unset _git_bash 2791 } 2792 2793 if {[is_Windows] || ![is_bare]} { ··· 4094 } 4095 } elseif {$m} { 4096 catch { 4097 + set fd [safe_open_file [gitdir GITGUI_BCK] w] 4098 fconfigure $fd -encoding utf-8 4099 puts -nonewline $fd $msg 4100 close $fd
+6 -6
git-gui/lib/blame.tcl
··· 481 if {$do_textconv ne 0} { 482 set fd [open_cmd_pipe $textconv $path] 483 } else { 484 - set fd [open $path r] 485 } 486 fconfigure $fd -eofchar {} 487 } else { 488 if {$do_textconv ne 0} { 489 - set fd [git_read cat-file --textconv "$commit:$path"] 490 } else { 491 - set fd [git_read cat-file blob "$commit:$path"] 492 } 493 } 494 fconfigure $fd \ ··· 617 } 618 619 lappend options -- $path 620 - set fd [eval git_read --nice blame $options] 621 fconfigure $fd -blocking 0 -translation lf -encoding utf-8 622 fileevent $fd readable [cb _read_blame $fd $cur_w $cur_d] 623 set current_fd $fd ··· 986 if {[catch {set msg $header($cmit,message)}]} { 987 set msg {} 988 catch { 989 - set fd [git_read cat-file commit $cmit] 990 fconfigure $fd -encoding binary -translation lf 991 # By default commits are assumed to be in utf-8 992 set enc utf-8 ··· 1134 } else { 1135 set diffcmd [list diff-tree --unified=0 $cparent $cmit -- $new_path] 1136 } 1137 - if {[catch {set fd [eval git_read $diffcmd]} err]} { 1138 $status_operation stop [mc "Unable to display parent"] 1139 error_popup [strcat [mc "Error loading diff:"] "\n\n$err"] 1140 return
··· 481 if {$do_textconv ne 0} { 482 set fd [open_cmd_pipe $textconv $path] 483 } else { 484 + set fd [safe_open_file $path r] 485 } 486 fconfigure $fd -eofchar {} 487 } else { 488 if {$do_textconv ne 0} { 489 + set fd [git_read [list cat-file --textconv "$commit:$path"]] 490 } else { 491 + set fd [git_read [list cat-file blob "$commit:$path"]] 492 } 493 } 494 fconfigure $fd \ ··· 617 } 618 619 lappend options -- $path 620 + set fd [git_read_nice [concat blame $options]] 621 fconfigure $fd -blocking 0 -translation lf -encoding utf-8 622 fileevent $fd readable [cb _read_blame $fd $cur_w $cur_d] 623 set current_fd $fd ··· 986 if {[catch {set msg $header($cmit,message)}]} { 987 set msg {} 988 catch { 989 + set fd [git_read [list cat-file commit $cmit]] 990 fconfigure $fd -encoding binary -translation lf 991 # By default commits are assumed to be in utf-8 992 set enc utf-8 ··· 1134 } else { 1135 set diffcmd [list diff-tree --unified=0 $cparent $cmit -- $new_path] 1136 } 1137 + if {[catch {set fd [git_read $diffcmd]} err]} { 1138 $status_operation stop [mc "Unable to display parent"] 1139 error_popup [strcat [mc "Error loading diff:"] "\n\n$err"] 1140 return
+3 -3
git-gui/lib/branch.tcl
··· 7 set rh refs/heads 8 set rh_len [expr {[string length $rh] + 1}] 9 set all_heads [list] 10 - set fd [git_read for-each-ref --format=%(refname) $rh] 11 fconfigure $fd -translation binary -encoding utf-8 12 while {[gets $fd line] > 0} { 13 if {!$some_heads_tracking || ![is_tracking_branch $line]} { ··· 21 22 proc load_all_tags {} { 23 set all_tags [list] 24 - set fd [git_read for-each-ref \ 25 --sort=-taggerdate \ 26 --format=%(refname) \ 27 - refs/tags] 28 fconfigure $fd -translation binary -encoding utf-8 29 while {[gets $fd line] > 0} { 30 if {![regsub ^refs/tags/ $line {} name]} continue
··· 7 set rh refs/heads 8 set rh_len [expr {[string length $rh] + 1}] 9 set all_heads [list] 10 + set fd [git_read [list for-each-ref --format=%(refname) $rh]] 11 fconfigure $fd -translation binary -encoding utf-8 12 while {[gets $fd line] > 0} { 13 if {!$some_heads_tracking || ![is_tracking_branch $line]} { ··· 21 22 proc load_all_tags {} { 23 set all_tags [list] 24 + set fd [git_read [list for-each-ref \ 25 --sort=-taggerdate \ 26 --format=%(refname) \ 27 + refs/tags]] 28 fconfigure $fd -translation binary -encoding utf-8 29 while {[gets $fd line] > 0} { 30 if {![regsub ^refs/tags/ $line {} name]} continue
+1 -1
git-gui/lib/browser.tcl
··· 196 lappend browser_stack [list $tree_id $name] 197 $w conf -state disabled 198 199 - set fd [git_read ls-tree -z $tree_id] 200 fconfigure $fd -blocking 0 -translation binary -encoding utf-8 201 fileevent $fd readable [cb _read $fd] 202 }
··· 196 lappend browser_stack [list $tree_id $name] 197 $w conf -state disabled 198 199 + set fd [git_read [list ls-tree -z $tree_id]] 200 fconfigure $fd -blocking 0 -translation binary -encoding utf-8 201 fileevent $fd readable [cb _read $fd] 202 }
+8 -17
git-gui/lib/checkout_op.tcl
··· 304 _readtree $this 305 } else { 306 ui_status [mc "Refreshing file status..."] 307 - set fd [git_read update-index \ 308 -q \ 309 --unmerged \ 310 --ignore-missing \ 311 --refresh \ 312 - ] 313 fconfigure $fd -blocking 0 -translation binary 314 fileevent $fd readable [cb _refresh_wait $fd] 315 } ··· 345 [mc "Updating working directory to '%s'..." [_name $this]] \ 346 [mc "files checked out"]] 347 348 - set fd [git_read --stderr read-tree \ 349 -m \ 350 -u \ 351 -v \ 352 --exclude-per-directory=.gitignore \ 353 $HEAD \ 354 $new_hash \ 355 - ] 356 fconfigure $fd -blocking 0 -translation binary 357 fileevent $fd readable [cb _readtree_wait $fd $status_bar_operation] 358 } ··· 510 delete_this 511 } 512 513 - git-version proc _detach_HEAD {log new} { 514 - >= 1.5.3 { 515 - git update-ref --no-deref -m $log HEAD $new 516 - } 517 - default { 518 - set p [gitdir HEAD] 519 - file delete $p 520 - set fd [open $p w] 521 - fconfigure $fd -translation lf -encoding utf-8 522 - puts $fd $new 523 - close $fd 524 - } 525 } 526 527 method _confirm_reset {cur} { ··· 582 pack $w.buttons.cancel -side right -padx 5 583 pack $w.buttons -side bottom -fill x -pady 10 -padx 10 584 585 - set fd [git_read rev-list --pretty=oneline $cur ^$new_hash] 586 while {[gets $fd line] > 0} { 587 set abbr [string range $line 0 7] 588 set subj [string range $line 41 end]
··· 304 _readtree $this 305 } else { 306 ui_status [mc "Refreshing file status..."] 307 + set fd [git_read [list update-index \ 308 -q \ 309 --unmerged \ 310 --ignore-missing \ 311 --refresh \ 312 + ]] 313 fconfigure $fd -blocking 0 -translation binary 314 fileevent $fd readable [cb _refresh_wait $fd] 315 } ··· 345 [mc "Updating working directory to '%s'..." [_name $this]] \ 346 [mc "files checked out"]] 347 348 + set fd [git_read [list read-tree \ 349 -m \ 350 -u \ 351 -v \ 352 --exclude-per-directory=.gitignore \ 353 $HEAD \ 354 $new_hash \ 355 + ] \ 356 + [list 2>@1]] 357 fconfigure $fd -blocking 0 -translation binary 358 fileevent $fd readable [cb _readtree_wait $fd $status_bar_operation] 359 } ··· 511 delete_this 512 } 513 514 + proc _detach_HEAD {log new} { 515 + git update-ref --no-deref -m $log HEAD $new 516 } 517 518 method _confirm_reset {cur} { ··· 573 pack $w.buttons.cancel -side right -padx 5 574 pack $w.buttons -side bottom -fill x -pady 10 -padx 10 575 576 + set fd [git_read [list rev-list --pretty=oneline $cur ^$new_hash]] 577 while {[gets $fd line] > 0} { 578 set abbr [string range $line 0 7] 579 set subj [string range $line 41 end]
+12 -11
git-gui/lib/choose_repository.tcl
··· 641 set pwd [pwd] 642 if {[catch { 643 file mkdir [gitdir objects info] 644 - set f_in [open [file join $objdir info alternates] r] 645 - set f_cp [open [gitdir objects info alternates] w] 646 fconfigure $f_in -translation binary -encoding binary 647 fconfigure $f_cp -translation binary -encoding binary 648 cd $objdir ··· 727 [cb _do_clone_tags] 728 } 729 shared { 730 - set fd [open [gitdir objects info alternates] w] 731 fconfigure $fd -translation binary 732 puts $fd $objdir 733 close $fd ··· 760 } 761 foreach p $tocopy { 762 if {[catch { 763 - set f_in [open [file join $objdir $p] r] 764 - set f_cp [open [file join .git objects $p] w] 765 fconfigure $f_in -translation binary -encoding binary 766 fconfigure $f_cp -translation binary -encoding binary 767 ··· 818 error_popup [mc "Not a Git repository: %s" [file tail $origin_url]] 819 return 0 820 } 821 - set fd_in [git_read for-each-ref \ 822 --tcl \ 823 - {--format=list %(refname) %(objectname) %(*objectname)}] 824 cd $pwd 825 826 - set fd [open [gitdir packed-refs] w] 827 fconfigure $fd -translation binary 828 puts $fd "# pack-refs with: peeled" 829 while {[gets $fd_in line] >= 0} { ··· 877 878 set HEAD {} 879 if {[file exists [gitdir FETCH_HEAD]]} { 880 - set fd [open [gitdir FETCH_HEAD] r] 881 while {[gets $fd line] >= 0} { 882 if {[regexp "^(.{40})\t\t" $line line HEAD]} { 883 break ··· 953 [mc "files"]] 954 955 set readtree_err {} 956 - set fd [git_read --stderr read-tree \ 957 -m \ 958 -u \ 959 -v \ 960 HEAD \ 961 HEAD \ 962 - ] 963 fconfigure $fd -blocking 0 -translation binary 964 fileevent $fd readable [cb _readtree_wait $fd] 965 }
··· 641 set pwd [pwd] 642 if {[catch { 643 file mkdir [gitdir objects info] 644 + set f_in [safe_open_file [file join $objdir info alternates] r] 645 + set f_cp [safe_open_file [gitdir objects info alternates] w] 646 fconfigure $f_in -translation binary -encoding binary 647 fconfigure $f_cp -translation binary -encoding binary 648 cd $objdir ··· 727 [cb _do_clone_tags] 728 } 729 shared { 730 + set fd [safe_open_file [gitdir objects info alternates] w] 731 fconfigure $fd -translation binary 732 puts $fd $objdir 733 close $fd ··· 760 } 761 foreach p $tocopy { 762 if {[catch { 763 + set f_in [safe_open_file [file join $objdir $p] r] 764 + set f_cp [safe_open_file [file join .git objects $p] w] 765 fconfigure $f_in -translation binary -encoding binary 766 fconfigure $f_cp -translation binary -encoding binary 767 ··· 818 error_popup [mc "Not a Git repository: %s" [file tail $origin_url]] 819 return 0 820 } 821 + set fd_in [git_read [list for-each-ref \ 822 --tcl \ 823 + {--format=list %(refname) %(objectname) %(*objectname)}]] 824 cd $pwd 825 826 + set fd [safe_open_file [gitdir packed-refs] w] 827 fconfigure $fd -translation binary 828 puts $fd "# pack-refs with: peeled" 829 while {[gets $fd_in line] >= 0} { ··· 877 878 set HEAD {} 879 if {[file exists [gitdir FETCH_HEAD]]} { 880 + set fd [safe_open_file [gitdir FETCH_HEAD] r] 881 while {[gets $fd line] >= 0} { 882 if {[regexp "^(.{40})\t\t" $line line HEAD]} { 883 break ··· 953 [mc "files"]] 954 955 set readtree_err {} 956 + set fd [git_read [list read-tree \ 957 -m \ 958 -u \ 959 -v \ 960 HEAD \ 961 HEAD \ 962 + ] \ 963 + [list 2>@1]] 964 fconfigure $fd -blocking 0 -translation binary 965 fileevent $fd readable [cb _readtree_wait $fd] 966 }
+4 -4
git-gui/lib/choose_rev.tcl
··· 146 append fmt { %(*subject)} 147 append fmt {]} 148 set all_refn [list] 149 - set fr_fd [git_read for-each-ref \ 150 --tcl \ 151 --sort=-taggerdate \ 152 --format=$fmt \ 153 refs/heads \ 154 refs/remotes \ 155 refs/tags \ 156 - ] 157 fconfigure $fr_fd -translation lf -encoding utf-8 158 while {[gets $fr_fd line] > 0} { 159 set line [eval $line] ··· 176 close $fr_fd 177 178 if {$unmerged_only} { 179 - set fr_fd [git_read rev-list --all ^$::HEAD] 180 while {[gets $fr_fd sha1] > 0} { 181 if {[catch {set rlst $cmt_refn($sha1)}]} continue 182 foreach refn $rlst { ··· 579 580 set last {} 581 if {[catch {set last [file mtime [gitdir $name]]}] 582 - && ![catch {set g [open [gitdir logs $name] r]}]} { 583 fconfigure $g -translation binary 584 while {[gets $g line] >= 0} { 585 if {[regexp {> ([1-9][0-9]*) } $line line when]} {
··· 146 append fmt { %(*subject)} 147 append fmt {]} 148 set all_refn [list] 149 + set fr_fd [git_read [list for-each-ref \ 150 --tcl \ 151 --sort=-taggerdate \ 152 --format=$fmt \ 153 refs/heads \ 154 refs/remotes \ 155 refs/tags \ 156 + ]] 157 fconfigure $fr_fd -translation lf -encoding utf-8 158 while {[gets $fr_fd line] > 0} { 159 set line [eval $line] ··· 176 close $fr_fd 177 178 if {$unmerged_only} { 179 + set fr_fd [git_read [list rev-list --all ^$::HEAD]] 180 while {[gets $fr_fd sha1] > 0} { 181 if {[catch {set rlst $cmt_refn($sha1)}]} continue 182 foreach refn $rlst { ··· 579 580 set last {} 581 if {[catch {set last [file mtime [gitdir $name]]}] 582 + && ![catch {set g [safe_open_file [gitdir logs $name] r]}]} { 583 fconfigure $g -translation binary 584 while {[gets $g line] >= 0} { 585 if {[regexp {> ([1-9][0-9]*) } $line line when]} {
+7 -7
git-gui/lib/commit.tcl
··· 27 if {[catch { 28 set name "" 29 set email "" 30 - set fd [git_read cat-file commit $curHEAD] 31 fconfigure $fd -encoding binary -translation lf 32 # By default commits are assumed to be in utf-8 33 set enc utf-8 ··· 225 # -- Build the message file. 226 # 227 set msg_p [gitdir GITGUI_EDITMSG] 228 - set msg_wt [open $msg_p w] 229 fconfigure $msg_wt -translation lf 230 setup_commit_encoding $msg_wt 231 puts $msg_wt $msg ··· 325 326 proc commit_writetree {curHEAD msg_p} { 327 ui_status [mc "Committing changes..."] 328 - set fd_wt [git_read write-tree] 329 fileevent $fd_wt readable \ 330 [list commit_committree $fd_wt $curHEAD $msg_p] 331 } ··· 350 # -- Verify this wasn't an empty change. 351 # 352 if {$commit_type eq {normal}} { 353 - set fd_ot [git_read cat-file commit $PARENT] 354 fconfigure $fd_ot -encoding binary -translation lf 355 set old_tree [gets $fd_ot] 356 close $fd_ot ··· 388 foreach p [concat $PARENT $MERGE_HEAD] { 389 lappend cmd -p $p 390 } 391 - lappend cmd <$msg_p 392 - if {[catch {set cmt_id [eval git $cmd]} err]} { 393 catch {file delete $msg_p} 394 error_popup [strcat [mc "commit-tree failed:"] "\n\n$err"] 395 ui_status [mc "Commit failed."] ··· 409 if {$commit_type ne {normal}} { 410 append reflogm " ($commit_type)" 411 } 412 - set msg_fd [open $msg_p r] 413 setup_commit_encoding $msg_fd 1 414 gets $msg_fd subject 415 close $msg_fd
··· 27 if {[catch { 28 set name "" 29 set email "" 30 + set fd [git_read [list cat-file commit $curHEAD]] 31 fconfigure $fd -encoding binary -translation lf 32 # By default commits are assumed to be in utf-8 33 set enc utf-8 ··· 225 # -- Build the message file. 226 # 227 set msg_p [gitdir GITGUI_EDITMSG] 228 + set msg_wt [safe_open_file $msg_p w] 229 fconfigure $msg_wt -translation lf 230 setup_commit_encoding $msg_wt 231 puts $msg_wt $msg ··· 325 326 proc commit_writetree {curHEAD msg_p} { 327 ui_status [mc "Committing changes..."] 328 + set fd_wt [git_read [list write-tree]] 329 fileevent $fd_wt readable \ 330 [list commit_committree $fd_wt $curHEAD $msg_p] 331 } ··· 350 # -- Verify this wasn't an empty change. 351 # 352 if {$commit_type eq {normal}} { 353 + set fd_ot [git_read [list cat-file commit $PARENT]] 354 fconfigure $fd_ot -encoding binary -translation lf 355 set old_tree [gets $fd_ot] 356 close $fd_ot ··· 388 foreach p [concat $PARENT $MERGE_HEAD] { 389 lappend cmd -p $p 390 } 391 + set msgtxt [list <$msg_p] 392 + if {[catch {set cmt_id [git_redir $cmd $msgtxt]} err]} { 393 catch {file delete $msg_p} 394 error_popup [strcat [mc "commit-tree failed:"] "\n\n$err"] 395 ui_status [mc "Commit failed."] ··· 409 if {$commit_type ne {normal}} { 410 append reflogm " ($commit_type)" 411 } 412 + set msg_fd [safe_open_file $msg_p r] 413 setup_commit_encoding $msg_fd 1 414 gets $msg_fd subject 415 close $msg_fd
+2 -3
git-gui/lib/console.tcl
··· 92 93 method exec {cmd {after {}}} { 94 if {[lindex $cmd 0] eq {git}} { 95 - set fd_f [eval git_read --stderr [lrange $cmd 1 end]] 96 } else { 97 - lappend cmd 2>@1 98 - set fd_f [_open_stdout_stderr $cmd] 99 } 100 fconfigure $fd_f -blocking 0 -translation binary 101 fileevent $fd_f readable [cb _read $fd_f $after]
··· 92 93 method exec {cmd {after {}}} { 94 if {[lindex $cmd 0] eq {git}} { 95 + set fd_f [git_read [lrange $cmd 1 end] [list 2>@1]] 96 } else { 97 + set fd_f [safe_open_command $cmd [list 2>@1]] 98 } 99 fconfigure $fd_f -blocking 0 -translation binary 100 fileevent $fd_f readable [cb _read $fd_f $after]
+1 -1
git-gui/lib/database.tcl
··· 3 4 proc do_stats {} { 5 global use_ttk NS 6 - set fd [git_read count-objects -v] 7 while {[gets $fd line] > 0} { 8 if {[regexp {^([^:]+): (\d+)$} $line _ name value]} { 9 set stats($name) $value
··· 3 4 proc do_stats {} { 5 global use_ttk NS 6 + set fd [git_read [list count-objects -v]] 7 while {[gets $fd line] > 0} { 8 if {[regexp {^([^:]+): (\d+)$} $line _ name value]} { 9 set stats($name) $value
+6 -6
git-gui/lib/diff.tcl
··· 202 set sz [string length $content] 203 } 204 file { 205 - set fd [open $path r] 206 fconfigure $fd \ 207 -eofchar {} \ 208 -encoding [get_path_encoding $path] ··· 226 $ui_diff insert end \ 227 "* [mc "Git Repository (subproject)"]\n" \ 228 d_info 229 - } elseif {![catch {set type [exec file $path]}]} { 230 set n [string length $path] 231 if {[string equal -length $n $path $type]} { 232 set type [string range $type $n end] ··· 338 } 339 } 340 341 - if {[catch {set fd [eval git_read --nice $cmd]} err]} { 342 set diff_active 0 343 unlock_index 344 ui_status [mc "Unable to display %s" [escape_path $path]] ··· 617 618 if {[catch { 619 set enc [get_path_encoding $current_diff_path] 620 - set p [eval git_write $apply_cmd] 621 fconfigure $p -translation binary -encoding $enc 622 puts -nonewline $p $wholepatch 623 close $p} err]} { ··· 853 854 if {[catch { 855 set enc [get_path_encoding $current_diff_path] 856 - set p [eval git_write $apply_cmd] 857 fconfigure $p -translation binary -encoding $enc 858 puts -nonewline $p $current_diff_header 859 puts -nonewline $p $wholepatch ··· 890 891 if {[catch { 892 set enc $last_revert_enc 893 - set p [eval git_write $apply_cmd] 894 fconfigure $p -translation binary -encoding $enc 895 puts -nonewline $p $last_revert 896 close $p} err]} {
··· 202 set sz [string length $content] 203 } 204 file { 205 + set fd [safe_open_file $path r] 206 fconfigure $fd \ 207 -eofchar {} \ 208 -encoding [get_path_encoding $path] ··· 226 $ui_diff insert end \ 227 "* [mc "Git Repository (subproject)"]\n" \ 228 d_info 229 + } elseif {![catch {set type [safe_exec [list file $path]]}]} { 230 set n [string length $path] 231 if {[string equal -length $n $path $type]} { 232 set type [string range $type $n end] ··· 338 } 339 } 340 341 + if {[catch {set fd [git_read_nice $cmd]} err]} { 342 set diff_active 0 343 unlock_index 344 ui_status [mc "Unable to display %s" [escape_path $path]] ··· 617 618 if {[catch { 619 set enc [get_path_encoding $current_diff_path] 620 + set p [git_write $apply_cmd] 621 fconfigure $p -translation binary -encoding $enc 622 puts -nonewline $p $wholepatch 623 close $p} err]} { ··· 853 854 if {[catch { 855 set enc [get_path_encoding $current_diff_path] 856 + set p [git_write $apply_cmd] 857 fconfigure $p -translation binary -encoding $enc 858 puts -nonewline $p $current_diff_header 859 puts -nonewline $p $wholepatch ··· 890 891 if {[catch { 892 set enc $last_revert_enc 893 + set p [git_write $apply_cmd] 894 fconfigure $p -translation binary -encoding $enc 895 puts -nonewline $p $last_revert 896 close $p} err]} {
+4 -4
git-gui/lib/index.tcl
··· 75 if {$batch > 25} {set batch 25} 76 77 set status_bar_operation [$::main_status start $msg [mc "files"]] 78 - set fd [git_write update-index -z --index-info] 79 fconfigure $fd \ 80 -blocking 0 \ 81 -buffering full \ ··· 144 if {$batch > 25} {set batch 25} 145 146 set status_bar_operation [$::main_status start $msg [mc "files"]] 147 - set fd [git_write update-index --add --remove -z --stdin] 148 fconfigure $fd \ 149 -blocking 0 \ 150 -buffering full \ ··· 218 if {$batch > 25} {set batch 25} 219 220 set status_bar_operation [$::main_status start $msg [mc "files"]] 221 - set fd [git_write checkout-index \ 222 --index \ 223 --quiet \ 224 --force \ 225 -z \ 226 --stdin \ 227 - ] 228 fconfigure $fd \ 229 -blocking 0 \ 230 -buffering full \
··· 75 if {$batch > 25} {set batch 25} 76 77 set status_bar_operation [$::main_status start $msg [mc "files"]] 78 + set fd [git_write [list update-index -z --index-info]] 79 fconfigure $fd \ 80 -blocking 0 \ 81 -buffering full \ ··· 144 if {$batch > 25} {set batch 25} 145 146 set status_bar_operation [$::main_status start $msg [mc "files"]] 147 + set fd [git_write [list update-index --add --remove -z --stdin]] 148 fconfigure $fd \ 149 -blocking 0 \ 150 -buffering full \ ··· 218 if {$batch > 25} {set batch 25} 219 220 set status_bar_operation [$::main_status start $msg [mc "files"]] 221 + set fd [git_write [list checkout-index \ 222 --index \ 223 --quiet \ 224 --force \ 225 -z \ 226 --stdin \ 227 + ]] 228 fconfigure $fd \ 229 -blocking 0 \ 230 -buffering full \
+3 -3
git-gui/lib/merge.tcl
··· 93 set spec [$w_rev get_tracking_branch] 94 set cmit [$w_rev get_commit] 95 96 - set fh [open [gitdir FETCH_HEAD] w] 97 fconfigure $fh -translation lf 98 if {$spec eq {}} { 99 set remote . ··· 118 set cmd [list git] 119 lappend cmd merge 120 lappend cmd --strategy=recursive 121 - lappend cmd [git fmt-merge-msg <[gitdir FETCH_HEAD]] 122 lappend cmd HEAD 123 lappend cmd $name 124 } ··· 239 } 240 241 if {[ask_popup $op_question] eq {yes}} { 242 - set fd [git_read --stderr read-tree --reset -u -v HEAD] 243 fconfigure $fd -blocking 0 -translation binary 244 set status_bar_operation [$::main_status \ 245 start \
··· 93 set spec [$w_rev get_tracking_branch] 94 set cmit [$w_rev get_commit] 95 96 + set fh [safe_open_file [gitdir FETCH_HEAD] w] 97 fconfigure $fh -translation lf 98 if {$spec eq {}} { 99 set remote . ··· 118 set cmd [list git] 119 lappend cmd merge 120 lappend cmd --strategy=recursive 121 + lappend cmd [git_redir [list fmt-merge-msg] [list <[gitdir FETCH_HEAD]]] 122 lappend cmd HEAD 123 lappend cmd $name 124 } ··· 239 } 240 241 if {[ask_popup $op_question] eq {yes}} { 242 + set fd [git_read [list read-tree --reset -u -v HEAD] [list 2>@1]] 243 fconfigure $fd -blocking 0 -translation binary 244 set status_bar_operation [$::main_status \ 245 start \
+4 -4
git-gui/lib/mergetool.tcl
··· 88 set merge_stages(3) {} 89 set merge_stages_buf {} 90 91 - set merge_stages_fd [eval git_read ls-files -u -z -- {$path}] 92 93 fconfigure $merge_stages_fd -blocking 0 -translation binary -encoding binary 94 fileevent $merge_stages_fd readable [list read_merge_stages $merge_stages_fd $cont] ··· 293 foreach fname $stages { 294 if {$merge_stages($i) eq {}} { 295 file delete $fname 296 - catch { close [open $fname w] } 297 } else { 298 # A hack to support autocrlf properly 299 git checkout-index -f --stage=$i -- $target ··· 343 344 # Force redirection to avoid interpreting output on stderr 345 # as an error, and launch the tool 346 - lappend cmdline {2>@1} 347 348 - if {[catch { set mtool_fd [_open_stdout_stderr $cmdline] } err]} { 349 delete_temp_files $mtool_tmpfiles 350 error_popup [mc "Could not start the merge tool:\n\n%s" $err] 351 return
··· 88 set merge_stages(3) {} 89 set merge_stages_buf {} 90 91 + set merge_stages_fd [git_read [list ls-files -u -z -- $path]] 92 93 fconfigure $merge_stages_fd -blocking 0 -translation binary -encoding binary 94 fileevent $merge_stages_fd readable [list read_merge_stages $merge_stages_fd $cont] ··· 293 foreach fname $stages { 294 if {$merge_stages($i) eq {}} { 295 file delete $fname 296 + catch { close [safe_open_file $fname w] } 297 } else { 298 # A hack to support autocrlf properly 299 git checkout-index -f --stage=$i -- $target ··· 343 344 # Force redirection to avoid interpreting output on stderr 345 # as an error, and launch the tool 346 + set redir [list {2>@1}] 347 348 + if {[catch { set mtool_fd [safe_open_command $cmdline $redir] } err]} { 349 delete_temp_files $mtool_tmpfiles 350 error_popup [mc "Could not start the merge tool:\n\n%s" $err] 351 return
+4 -4
git-gui/lib/remote.tcl
··· 32 } 33 34 if {$pat ne {}} { 35 - set fd [eval git_read for-each-ref --format=%(refname) $cmd] 36 while {[gets $fd n] > 0} { 37 foreach spec $pat { 38 set dst [string range [lindex $spec 0] 0 end-2] ··· 75 76 foreach name $all_remotes { 77 catch { 78 - set fd [open [file join $rm_dir $name] r] 79 while {[gets $fd line] >= 0} { 80 if {[regexp {^URL:[ ]*(.+)$} $line line url]} { 81 set remote_url($name) $url ··· 145 } 146 } else { 147 catch { 148 - set fd [open [gitdir remotes $r] r] 149 while {[gets $fd n] >= 0} { 150 if {[regexp {^Pull:[ \t]*([^:]+):} $n]} { 151 set enable 1 ··· 182 } 183 } else { 184 catch { 185 - set fd [open [gitdir remotes $r] r] 186 while {[gets $fd n] >= 0} { 187 if {[regexp {^Push:[ \t]*([^:]+):} $n]} { 188 set enable 1
··· 32 } 33 34 if {$pat ne {}} { 35 + set fd [git_read [concat for-each-ref --format=%(refname) $cmd]] 36 while {[gets $fd n] > 0} { 37 foreach spec $pat { 38 set dst [string range [lindex $spec 0] 0 end-2] ··· 75 76 foreach name $all_remotes { 77 catch { 78 + set fd [safe_open_file [file join $rm_dir $name] r] 79 while {[gets $fd line] >= 0} { 80 if {[regexp {^URL:[ ]*(.+)$} $line line url]} { 81 set remote_url($name) $url ··· 145 } 146 } else { 147 catch { 148 + set fd [safe_open_file [gitdir remotes $r] r] 149 while {[gets $fd n] >= 0} { 150 if {[regexp {^Pull:[ \t]*([^:]+):} $n]} { 151 set enable 1 ··· 182 } 183 } else { 184 catch { 185 + set fd [safe_open_file [gitdir remotes $r] r] 186 while {[gets $fd n] >= 0} { 187 if {[regexp {^Push:[ \t]*([^:]+):} $n]} { 188 set enable 1
+1 -1
git-gui/lib/remote_branch_delete.tcl
··· 308 set full_list [list] 309 set head_cache($cache) [list] 310 set full_cache($cache) [list] 311 - set active_ls [git_read ls-remote $uri] 312 fconfigure $active_ls \ 313 -blocking 0 \ 314 -translation lf \
··· 308 set full_list [list] 309 set head_cache($cache) [list] 310 set full_cache($cache) [list] 311 + set active_ls [git_read [list ls-remote $uri]] 312 fconfigure $active_ls \ 313 -blocking 0 \ 314 -translation lf \
+7 -7
git-gui/lib/shortcut.tcl
··· 12 set fn ${fn}.lnk 13 } 14 # Use git-gui.exe if available (ie: git-for-windows) 15 - set cmdLine [auto_execok git-gui.exe] 16 if {$cmdLine eq {}} { 17 set cmdLine [list [info nameofexecutable] \ 18 [file normalize $::argv0]] ··· 30 global argv0 _gitworktree oguilib 31 32 if {[catch { 33 - set desktop [exec cygpath \ 34 - --desktop] 35 }]} { 36 set desktop . 37 } ··· 50 "CHERE_INVOKING=1 \ 51 source /etc/profile; \ 52 git gui"} 53 - exec /bin/mkshortcut.exe \ 54 --arguments $shargs \ 55 --desc "git-gui on $repodir" \ 56 --icon $oguilib/git-gui.ico \ 57 --name $fn \ 58 --show min \ 59 --workingdir $repodir \ 60 - /bin/sh.exe 61 } err]} { 62 error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] 63 } ··· 83 84 file mkdir $MacOS 85 86 - set fd [open [file join $Contents Info.plist] w] 87 puts $fd {<?xml version="1.0" encoding="UTF-8"?> 88 <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 89 <plist version="1.0"> ··· 108 </plist>} 109 close $fd 110 111 - set fd [open $exe w] 112 puts $fd "#!/bin/sh" 113 foreach name [lsort [array names env]] { 114 set value $env($name)
··· 12 set fn ${fn}.lnk 13 } 14 # Use git-gui.exe if available (ie: git-for-windows) 15 + set cmdLine [list [_which git-gui]] 16 if {$cmdLine eq {}} { 17 set cmdLine [list [info nameofexecutable] \ 18 [file normalize $::argv0]] ··· 30 global argv0 _gitworktree oguilib 31 32 if {[catch { 33 + set desktop [safe_exec [list cygpath \ 34 + --desktop]] 35 }]} { 36 set desktop . 37 } ··· 50 "CHERE_INVOKING=1 \ 51 source /etc/profile; \ 52 git gui"} 53 + safe_exec [list /bin/mkshortcut.exe \ 54 --arguments $shargs \ 55 --desc "git-gui on $repodir" \ 56 --icon $oguilib/git-gui.ico \ 57 --name $fn \ 58 --show min \ 59 --workingdir $repodir \ 60 + /bin/sh.exe] 61 } err]} { 62 error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] 63 } ··· 83 84 file mkdir $MacOS 85 86 + set fd [safe_open_file [file join $Contents Info.plist] w] 87 puts $fd {<?xml version="1.0" encoding="UTF-8"?> 88 <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 89 <plist version="1.0"> ··· 108 </plist>} 109 close $fd 110 111 + set fd [safe_open_file $exe w] 112 puts $fd "#!/bin/sh" 113 foreach name [lsort [array names env]] { 114 set value $env($name)
+4 -3
git-gui/lib/sshkey.tcl
··· 7 ~/.ssh/id_rsa.pub ~/.ssh/identity.pub 8 } { 9 if {[file exists $name]} { 10 - set fh [open $name r] 11 set cont [read $fh] 12 close $fh 13 return [list $name $cont] ··· 83 set sshkey_title [mc "Generating..."] 84 $w.header.gen configure -state disabled 85 86 - set cmdline [list sh -c {echo | ssh-keygen -q -t rsa -f ~/.ssh/id_rsa 2>&1}] 87 88 - if {[catch { set sshkey_fd [_open_stdout_stderr $cmdline] } err]} { 89 error_popup [mc "Could not start ssh-keygen:\n\n%s" $err] 90 return 91 }
··· 7 ~/.ssh/id_rsa.pub ~/.ssh/identity.pub 8 } { 9 if {[file exists $name]} { 10 + set fh [safe_open_file $name r] 11 set cont [read $fh] 12 close $fh 13 return [list $name $cont] ··· 83 set sshkey_title [mc "Generating..."] 84 $w.header.gen configure -state disabled 85 86 + set cmdline [list [shellpath] -c \ 87 + {echo | ssh-keygen -q -t rsa -f ~/.ssh/id_rsa 2>&1}] 88 89 + if {[catch { set sshkey_fd [safe_open_command $cmdline] } err]} { 90 error_popup [mc "Could not start ssh-keygen:\n\n%s" $err] 91 return 92 }
+3 -4
git-gui/lib/tools.tcl
··· 110 111 set cmdline $repo_config(guitool.$fullname.cmd) 112 if {[is_config_true "guitool.$fullname.noconsole"]} { 113 - tools_run_silent [list sh -c $cmdline] \ 114 [list tools_complete $fullname {}] 115 } else { 116 regsub {/} $fullname { / } title 117 set w [console::new \ 118 [mc "Tool: %s" $title] \ 119 [mc "Running: %s" $cmdline]] 120 - console::exec $w [list sh -c $cmdline] \ 121 [list tools_complete $fullname $w] 122 } 123 ··· 130 } 131 132 proc tools_run_silent {cmd after} { 133 - lappend cmd 2>@1 134 - set fd [_open_stdout_stderr $cmd] 135 136 fconfigure $fd -blocking 0 -translation binary 137 fileevent $fd readable [list tools_consume_input $fd $after]
··· 110 111 set cmdline $repo_config(guitool.$fullname.cmd) 112 if {[is_config_true "guitool.$fullname.noconsole"]} { 113 + tools_run_silent [list [shellpath] -c $cmdline] \ 114 [list tools_complete $fullname {}] 115 } else { 116 regsub {/} $fullname { / } title 117 set w [console::new \ 118 [mc "Tool: %s" $title] \ 119 [mc "Running: %s" $cmdline]] 120 + console::exec $w [list [shellpath] -c $cmdline] \ 121 [list tools_complete $fullname $w] 122 } 123 ··· 130 } 131 132 proc tools_run_silent {cmd after} { 133 + set fd [safe_open_command $cmd [list 2>@1]] 134 135 fconfigure $fd -blocking 0 -translation binary 136 fileevent $fd readable [list tools_consume_input $fd $after]
+5 -4
git-gui/lib/win32.tcl
··· 2 # Copyright (C) 2007 Shawn Pearce 3 4 proc win32_read_lnk {lnk_path} { 5 - return [exec cscript.exe \ 6 /E:jscript \ 7 /nologo \ 8 [file join $::oguilib win32_shortcut.js] \ 9 - $lnk_path] 10 } 11 12 proc win32_create_lnk {lnk_path lnk_exec lnk_dir} { ··· 15 set lnk_args [lrange $lnk_exec 1 end] 16 set lnk_exec [lindex $lnk_exec 0] 17 18 - eval [list exec wscript.exe \ 19 /E:jscript \ 20 /nologo \ 21 [file nativename [file join $oguilib win32_shortcut.js]] \ 22 $lnk_path \ 23 [file nativename [file join $oguilib git-gui.ico]] \ 24 $lnk_dir \ 25 - $lnk_exec] $lnk_args 26 }
··· 2 # Copyright (C) 2007 Shawn Pearce 3 4 proc win32_read_lnk {lnk_path} { 5 + return [safe_exec [list cscript.exe \ 6 /E:jscript \ 7 /nologo \ 8 [file join $::oguilib win32_shortcut.js] \ 9 + $lnk_path]] 10 } 11 12 proc win32_create_lnk {lnk_path lnk_exec lnk_dir} { ··· 15 set lnk_args [lrange $lnk_exec 1 end] 16 set lnk_exec [lindex $lnk_exec 0] 17 18 + set cmd [list wscript.exe \ 19 /E:jscript \ 20 /nologo \ 21 [file nativename [file join $oguilib win32_shortcut.js]] \ 22 $lnk_path \ 23 [file nativename [file join $oguilib git-gui.ico]] \ 24 $lnk_dir \ 25 + $lnk_exec] 26 + safe_exec [concat $cmd $lnk_args] 27 }
+172 -106
gitk-git/gitk
··· 9 10 package require Tk 11 12 proc hasworktree {} { 13 return [expr {[exec git rev-parse --is-bare-repository] == "false" && 14 [exec git rev-parse --is-inside-git-dir] == "false"}] ··· 134 set mlist {} 135 set nr_unmerged 0 136 if {[catch { 137 - set fd [open "| git ls-files -u" r] 138 } err]} { 139 show_error {} . "[mc "Couldn't get list of unmerged files:"] $err" 140 exit 1 ··· 296 } elseif {[lsearch -exact $revs --all] >= 0} { 297 lappend revs HEAD 298 } 299 - if {[catch {set ids [eval exec git rev-parse $revs]} err]} { 300 # we get stdout followed by stderr in $err 301 # for an unknown rev, git rev-parse echoes it and then errors out 302 set errlines [split $err "\n"] ··· 353 return $ret 354 } 355 356 - # Escapes a list of filter paths to be passed to git log via stdin. Note that 357 - # paths must not be quoted. 358 - proc escape_filter_paths {paths} { 359 - set escaped [list] 360 - foreach path $paths { 361 - lappend escaped [string map {\\ \\\\ "\ " "\\\ "} $path] 362 - } 363 - return $escaped 364 - } 365 - 366 # Start off a git log process and arrange to read its output 367 proc start_rev_list {view} { 368 global startmsecs commitidx viewcomplete curview ··· 384 set args $viewargs($view) 385 if {$viewargscmd($view) ne {}} { 386 if {[catch { 387 - set str [exec sh -c $viewargscmd($view)] 388 } err]} { 389 error_popup "[mc "Error executing --argscmd command:"] $err" 390 return 0 ··· 422 } 423 424 if {[catch { 425 - set fd [open [concat | git log --no-color -z --pretty=raw $show_notes \ 426 - --parents --boundary $args --stdin \ 427 - "<<[join [concat $revs "--" \ 428 - [escape_filter_paths $files]] "\\n"]"] r] 429 } err]} { 430 error_popup "[mc "Error executing git log:"] $err" 431 return 0 ··· 459 set pid [pid $fd] 460 461 if {$::tcl_platform(platform) eq {windows}} { 462 - exec taskkill /pid $pid 463 } else { 464 - exec kill $pid 465 } 466 } 467 catch {close $fd} ··· 576 set args $vorigargs($view) 577 } 578 if {[catch { 579 - set fd [open [concat | git log --no-color -z --pretty=raw $show_notes \ 580 - --parents --boundary $args --stdin \ 581 - "<<[join [concat $revs "--" \ 582 - [escape_filter_paths \ 583 - $vfilelimit($view)]] "\\n"]"] r] 584 } err]} { 585 error_popup "[mc "Error executing git log:"] $err" 586 return ··· 1547 # and if we already know about it, using the rewritten 1548 # parent as a substitute parent for $id's children. 1549 if {![catch { 1550 - set rwid [exec git rev-list --first-parent --max-count=1 \ 1551 - $id -- $vfilelimit($view)] 1552 }]} { 1553 if {$rwid ne {} && [info exists varcid($view,$rwid)]} { 1554 # use $rwid in place of $id ··· 1668 global tclencoding 1669 1670 # Invoke git-log to handle automatic encoding conversion 1671 - set fd [open [concat | git log --no-color --pretty=raw -1 $id] r] 1672 # Read the results using i18n.logoutputencoding 1673 fconfigure $fd -translation lf -eofchar {} 1674 if {$tclencoding != {}} { ··· 1804 foreach v {tagids idtags headids idheads otherrefids idotherrefs} { 1805 unset -nocomplain $v 1806 } 1807 - set refd [open [list | git show-ref -d] r] 1808 if {$tclencoding != {}} { 1809 fconfigure $refd -encoding $tclencoding 1810 } ··· 1852 set selectheadid {} 1853 if {$selecthead ne {}} { 1854 catch { 1855 - set selectheadid [exec git rev-parse --verify $selecthead] 1856 } 1857 } 1858 } ··· 2112 {mc "Reread re&ferences" command rereadrefs} 2113 {mc "&List references" command showrefs -accelerator F2} 2114 {xx "" separator} 2115 - {mc "Start git &gui" command {exec git gui &}} 2116 {xx "" separator} 2117 {mc "&Quit" command doquit -accelerator Meta1-Q} 2118 }} ··· 2894 set remove_tmp 0 2895 if {[catch { 2896 set try_count 0 2897 - while {[catch {set f [open $config_file_tmp {WRONLY CREAT EXCL}]}]} { 2898 if {[incr try_count] > 50} { 2899 error "Unable to write config file: $config_file_tmp exists" 2900 } ··· 3610 set tmpdir $gitdir 3611 } 3612 set gitktmpformat [file join $tmpdir ".gitk-tmp.XXXXXX"] 3613 - if {[catch {set gitktmpdir [exec mktemp -d $gitktmpformat]}]} { 3614 set gitktmpdir [file join $gitdir [format ".gitk-tmp.%s" [pid]]] 3615 } 3616 if {[catch {file mkdir $gitktmpdir} err]} { ··· 3632 proc save_file_from_commit {filename output what} { 3633 global nullfile 3634 3635 - if {[catch {exec git show $filename -- > $output} err]} { 3636 if {[string match "fatal: bad revision *" $err]} { 3637 return $nullfile 3638 } ··· 3697 3698 if {$difffromfile ne {} && $difftofile ne {}} { 3699 set cmd [list [shellsplit $extdifftool] $difffromfile $difftofile] 3700 - if {[catch {set fl [open |$cmd r]} err]} { 3701 file delete -force $diffdir 3702 error_popup "$extdifftool: [mc "command failed:"] $err" 3703 } else { ··· 3801 # Find the SHA1 ID of the blob for file $fname in the index 3802 # at stage 0 or 2 3803 proc index_sha1 {fname} { 3804 - set f [open [list | git ls-files -s $fname] r] 3805 while {[gets $f line] >= 0} { 3806 set info [lindex [split $line "\t"] 0] 3807 set stage [lindex $info 2] ··· 3861 # being given an absolute path... 3862 set f [make_relative $f] 3863 lappend cmdline $base_commit $f 3864 - if {[catch {eval exec $cmdline &} err]} { 3865 error_popup "[mc "git gui blame: command failed:"] $err" 3866 } 3867 } ··· 3889 # must be a merge in progress... 3890 if {[catch { 3891 # get the last line from .git/MERGE_HEAD 3892 - set f [open [file join $gitdir MERGE_HEAD] r] 3893 set id [lindex [split [read $f] "\n"] end-1] 3894 close $f 3895 } err]} { ··· 3912 } 3913 set line [lindex $h 1] 3914 } 3915 - set blameargs {} 3916 - if {$from_index ne {}} { 3917 - lappend blameargs | git cat-file blob $from_index 3918 - } 3919 - lappend blameargs | git blame -p -L$line,+1 3920 if {$from_index ne {}} { 3921 - lappend blameargs --contents - 3922 } else { 3923 - lappend blameargs $id 3924 } 3925 - lappend blameargs -- [file join $cdup $flist_menu_file] 3926 if {[catch { 3927 - set f [open $blameargs r] 3928 } err]} { 3929 error_popup [mc "Couldn't start git blame: %s" $err] 3930 return ··· 4849 # must be "containing:", i.e. we're searching commit info 4850 return 4851 } 4852 - set cmd [concat | git diff-tree -r -s --stdin $gdtargs] 4853 - set filehighlight [open $cmd r+] 4854 fconfigure $filehighlight -blocking 0 4855 filerun $filehighlight readfhighlight 4856 set fhl_list {} ··· 5279 global viewmainheadid vfilelimit viewinstances mainheadid 5280 5281 catch { 5282 - set rfd [open [concat | git rev-list -1 $mainheadid \ 5283 - -- $vfilelimit($view)] r] 5284 set j [reg_instance $rfd] 5285 lappend viewinstances($view) $j 5286 fconfigure $rfd -blocking 0 ··· 5345 if {!$showlocalchanges || !$hasworktree} return 5346 incr lserial 5347 if {[package vcompare $git_version "1.7.2"] >= 0} { 5348 - set cmd "|git diff-index --cached --ignore-submodules=dirty HEAD" 5349 } else { 5350 - set cmd "|git diff-index --cached HEAD" 5351 } 5352 if {$vfilelimit($curview) ne {}} { 5353 set cmd [concat $cmd -- $vfilelimit($curview)] 5354 } 5355 - set fd [open $cmd r] 5356 fconfigure $fd -blocking 0 5357 set i [reg_instance $fd] 5358 filerun $fd [list readdiffindex $fd $lserial $i] ··· 5377 } 5378 5379 # now see if there are any local changes not checked in to the index 5380 - set cmd "|git diff-files" 5381 if {$vfilelimit($curview) ne {}} { 5382 set cmd [concat $cmd -- $vfilelimit($curview)] 5383 } 5384 - set fd [open $cmd r] 5385 fconfigure $fd -blocking 0 5386 set i [reg_instance $fd] 5387 filerun $fd [list readdifffiles $fd $serial $i] ··· 7170 global web_browser 7171 7172 if {$web_browser eq {}} return 7173 - # Use eval here in case $web_browser is a command plus some arguments 7174 - if {[catch {eval exec $web_browser [list $url] &} err]} { 7175 error_popup "[mc "Error starting web browser:"] $err" 7176 } 7177 } ··· 7673 if {![info exists treefilelist($id)]} { 7674 if {![info exists treepending]} { 7675 if {$id eq $nullid} { 7676 - set cmd [list | git ls-files] 7677 } elseif {$id eq $nullid2} { 7678 - set cmd [list | git ls-files --stage -t] 7679 } else { 7680 - set cmd [list | git ls-tree -r $id] 7681 } 7682 - if {[catch {set gtf [open $cmd r]}]} { 7683 return 7684 } 7685 set treepending $id ··· 7743 return 7744 } 7745 if {$diffids eq $nullid} { 7746 - if {[catch {set bf [open $f r]} err]} { 7747 puts "oops, can't read $f: $err" 7748 return 7749 } 7750 } else { 7751 set blob [lindex $treeidlist($diffids) $i] 7752 - if {[catch {set bf [open [concat | git cat-file blob $blob] r]} err]} { 7753 puts "oops, error reading blob $blob: $err" 7754 return 7755 } ··· 7899 if {$i >= 0} { 7900 if {[llength $ids] > 1 && $j < 0} { 7901 # comparing working directory with some specific revision 7902 - set cmd [concat | git diff-index $flags] 7903 if {$i == 0} { 7904 lappend cmd -R [lindex $ids 1] 7905 } else { ··· 7907 } 7908 } else { 7909 # comparing working directory with index 7910 - set cmd [concat | git diff-files $flags] 7911 if {$j == 1} { 7912 lappend cmd -R 7913 } ··· 7916 if {[package vcompare $git_version "1.7.2"] >= 0} { 7917 set flags "$flags --ignore-submodules=dirty" 7918 } 7919 - set cmd [concat | git diff-index --cached $flags] 7920 if {[llength $ids] > 1} { 7921 # comparing index with specific revision 7922 if {$j == 0} { ··· 7932 if {$log_showroot} { 7933 lappend flags --root 7934 } 7935 - set cmd [concat | git diff-tree -r $flags $ids] 7936 } 7937 return $cmd 7938 } ··· 7944 if {$limitdiffs && $vfilelimit($curview) ne {}} { 7945 set cmd [concat $cmd -- $vfilelimit($curview)] 7946 } 7947 - if {[catch {set gdtf [open $cmd r]}]} return 7948 7949 set treepending $ids 7950 set treediff {} ··· 8064 if {$limitdiffs && $vfilelimit($curview) ne {}} { 8065 set cmd [concat $cmd -- $vfilelimit($curview)] 8066 } 8067 - if {[catch {set bdf [open $cmd r]} err]} { 8068 error_popup [mc "Error getting diffs: %s" $err] 8069 return 8070 } ··· 8781 set id [lindex $matches 0] 8782 } 8783 } else { 8784 - if {[catch {set id [exec git rev-parse --verify $sha1string]}]} { 8785 error_popup [mc "Revision %s is not known" $sha1string] 8786 return 8787 } ··· 9087 9088 if {![info exists patchids($id)]} { 9089 set cmd [diffcmd [list $id] {-p --root}] 9090 - # trim off the initial "|" 9091 - set cmd [lrange $cmd 1 end] 9092 if {[catch { 9093 - set x [eval exec $cmd | git patch-id] 9094 set patchids($id) [lindex $x 0] 9095 }]} { 9096 set patchids($id) "error" ··· 9186 set fna [file join $tmpdir "commit-[string range $a 0 7]"] 9187 set fnb [file join $tmpdir "commit-[string range $b 0 7]"] 9188 if {[catch { 9189 - exec git diff-tree -p --pretty $a >$fna 9190 - exec git diff-tree -p --pretty $b >$fnb 9191 } err]} { 9192 error_popup [mc "Error writing commit to file: %s" $err] 9193 return 9194 } 9195 if {[catch { 9196 - set fd [open "| diff -U$diffcontext $fna $fnb" r] 9197 } err]} { 9198 error_popup [mc "Error diffing commits: %s" $err] 9199 return ··· 9333 set newid [$patchtop.tosha1 get] 9334 set fname [$patchtop.fname get] 9335 set cmd [diffcmd [list $oldid $newid] -p] 9336 - # trim off the initial "|" 9337 - set cmd [lrange $cmd 1 end] 9338 - lappend cmd >$fname & 9339 - if {[catch {eval exec $cmd} err]} { 9340 error_popup "[mc "Error creating patch:"] $err" $patchtop 9341 } 9342 catch {destroy $patchtop} ··· 9405 } 9406 if {[catch { 9407 if {$msg != {}} { 9408 - exec git tag -a -m $msg $tag $id 9409 } else { 9410 - exec git tag $tag $id 9411 } 9412 } err]} { 9413 error_popup "[mc "Error creating tag:"] $err" $mktagtop ··· 9475 if {$autosellen < 40} { 9476 lappend cmd --abbrev=$autosellen 9477 } 9478 - set reference [eval exec $cmd $rowmenuid] 9479 9480 clipboard clear 9481 clipboard append $reference ··· 9525 set id [$wrcomtop.sha1 get] 9526 set cmd "echo $id | [$wrcomtop.cmd get]" 9527 set fname [$wrcomtop.fname get] 9528 - if {[catch {exec sh -c $cmd >$fname &} err]} { 9529 error_popup "[mc "Error writing commit:"] $err" $wrcomtop 9530 } 9531 catch {destroy $wrcomtop} ··· 9629 nowbusy newbranch 9630 update 9631 if {[catch { 9632 - eval exec git branch $cmdargs 9633 } err]} { 9634 notbusy newbranch 9635 error_popup $err ··· 9670 nowbusy renamebranch 9671 update 9672 if {[catch { 9673 - eval exec git branch $cmdargs 9674 } err]} { 9675 notbusy renamebranch 9676 error_popup $err ··· 9711 } 9712 } 9713 9714 - eval exec git citool $tool_args & 9715 9716 array unset env GIT_AUTHOR_* 9717 array set env $save_env ··· 9734 update 9735 # Unfortunately git-cherry-pick writes stuff to stderr even when 9736 # no error occurs, and exec takes that as an indication of error... 9737 - if {[catch {exec sh -c "git cherry-pick -r $rowmenuid 2>&1"} err]} { 9738 notbusy cherrypick 9739 if {[regexp -line \ 9740 {Entry '(.*)' (would be overwritten by merge|not uptodate)} \ ··· 9796 nowbusy revert [mc "Reverting"] 9797 update 9798 9799 - if [catch {exec git revert --no-edit $rowmenuid} err] { 9800 notbusy revert 9801 if [regexp {files would be overwritten by merge:(\n(( |\t)+[^\n]+\n)+)}\ 9802 $err match files] { ··· 9872 bind $w <Visibility> "grab $w; focus $w" 9873 tkwait window $w 9874 if {!$confirm_ok} return 9875 - if {[catch {set fd [open \ 9876 - [list | git reset --$resettype $rowmenuid 2>@1] r]} err]} { 9877 error_popup $err 9878 } else { 9879 dohidelocalchanges ··· 9944 9945 # check the tree is clean first?? 9946 set newhead $headmenuhead 9947 - set command [list | git checkout] 9948 if {[string match "remotes/*" $newhead]} { 9949 set remote $newhead 9950 set newhead [string range $newhead [expr [string last / $newhead] + 1] end] ··· 9958 } else { 9959 lappend command $newhead 9960 } 9961 - lappend command 2>@1 9962 nowbusy checkout [mc "Checking out"] 9963 update 9964 dohidelocalchanges 9965 if {[catch { 9966 - set fd [open $command r] 9967 } err]} { 9968 notbusy checkout 9969 error_popup $err ··· 10029 } 10030 nowbusy rmbranch 10031 update 10032 - if {[catch {exec git branch -D $head} err]} { 10033 notbusy rmbranch 10034 error_popup $err 10035 return ··· 10220 set cachedarcs 0 10221 set allccache [file join $gitdir "gitk.cache"] 10222 if {![catch { 10223 - set f [open $allccache r] 10224 set allcwait 1 10225 getcache $f 10226 }]} return ··· 10229 if {$allcwait} { 10230 return 10231 } 10232 - set cmd [list | git rev-list --parents] 10233 set allcupdate [expr {$seeds ne {}}] 10234 if {!$allcupdate} { 10235 set ids "--all" ··· 10257 if {$ids ne {}} { 10258 if {$ids eq "--all"} { 10259 set cmd [concat $cmd "--all"] 10260 } else { 10261 - set cmd [concat $cmd --stdin "<<[join $ids "\\n"]"] 10262 } 10263 - set fd [open $cmd r] 10264 fconfigure $fd -blocking 0 10265 incr allcommits 10266 nowbusy allcommits ··· 10650 set cachearc 0 10651 set cachedarcs $nextarc 10652 catch { 10653 - set f [open $allccache w] 10654 puts $f [list 1 $cachedarcs] 10655 run writecache $f 10656 } ··· 11353 11354 if {![info exists cached_tagcontent($tag)]} { 11355 catch { 11356 - set cached_tagcontent($tag) [exec git cat-file -p $tag] 11357 } 11358 } 11359 $ctext insert end "[mc "Tag"]: $tag\n" bold ··· 12239 set r $path_attr_cache($attr,$path) 12240 } else { 12241 set r "unspecified" 12242 - if {![catch {set line [exec git check-attr $attr -- $path]}]} { 12243 regexp "(.*): $attr: (.*)" $line m f r 12244 } 12245 set path_attr_cache($attr,$path) $r ··· 12266 while {$newlist ne {}} { 12267 set head [lrange $newlist 0 [expr {$lim - 1}]] 12268 set newlist [lrange $newlist $lim end] 12269 - if {![catch {set rlist [eval exec git check-attr $attr -- $head]}]} { 12270 foreach row [split $rlist "\n"] { 12271 if {[regexp "(.*): $attr: (.*)" $row m path value]} { 12272 if {[string index $path 0] eq "\""} { ··· 12319 12320 # on OSX bring the current Wish process window to front 12321 if {[tk windowingsystem] eq "aqua"} { 12322 - exec osascript -e [format { 12323 tell application "System Events" 12324 set frontmost of processes whose unix id is %d to true 12325 end tell 12326 - } [pid] ] 12327 } 12328 12329 # Unset GIT_TRACE var if set ··· 12568 if {$i >= [llength $argv] && $revtreeargs ne {}} { 12569 # no -- on command line, but some arguments (other than --argscmd) 12570 if {[catch { 12571 - set f [eval exec git rev-parse --no-revs --no-flags $revtreeargs] 12572 set cmdline_files [split $f "\n"] 12573 set n [llength $cmdline_files] 12574 set revtreeargs [lrange $revtreeargs 0 end-$n]
··· 9 10 package require Tk 11 12 + 13 + # Wrap exec/open to sanitize arguments 14 + 15 + # unsafe arguments begin with redirections or the pipe or background operators 16 + proc is_arg_unsafe {arg} { 17 + regexp {^([<|>&]|2>)} $arg 18 + } 19 + 20 + proc make_arg_safe {arg} { 21 + if {[is_arg_unsafe $arg]} { 22 + set arg [file join . $arg] 23 + } 24 + return $arg 25 + } 26 + 27 + proc make_arglist_safe {arglist} { 28 + set res {} 29 + foreach arg $arglist { 30 + lappend res [make_arg_safe $arg] 31 + } 32 + return $res 33 + } 34 + 35 + # executes one command 36 + # no redirections or pipelines are possible 37 + # cmd is a list that specifies the command and its arguments 38 + # calls `exec` and returns its value 39 + proc safe_exec {cmd} { 40 + eval exec [make_arglist_safe $cmd] 41 + } 42 + 43 + # executes one command with redirections 44 + # no pipelines are possible 45 + # cmd is a list that specifies the command and its arguments 46 + # redir is a list that specifies redirections (output, background, constant(!) commands) 47 + # calls `exec` and returns its value 48 + proc safe_exec_redirect {cmd redir} { 49 + eval exec [make_arglist_safe $cmd] $redir 50 + } 51 + 52 + proc safe_open_file {filename flags} { 53 + # a file name starting with "|" would attempt to run a process 54 + # but such a file name must be treated as a relative path 55 + # hide the "|" behind "./" 56 + if {[string index $filename 0] eq "|"} { 57 + set filename [file join . $filename] 58 + } 59 + open $filename $flags 60 + } 61 + 62 + # opens a command pipeline for reading 63 + # cmd is a list that specifies the command and its arguments 64 + # calls `open` and returns the file id 65 + proc safe_open_command {cmd} { 66 + open |[make_arglist_safe $cmd] r 67 + } 68 + 69 + # opens a command pipeline for reading and writing 70 + # cmd is a list that specifies the command and its arguments 71 + # calls `open` and returns the file id 72 + proc safe_open_command_rw {cmd} { 73 + open |[make_arglist_safe $cmd] r+ 74 + } 75 + 76 + # opens a command pipeline for reading with redirections 77 + # cmd is a list that specifies the command and its arguments 78 + # redir is a list that specifies redirections 79 + # calls `open` and returns the file id 80 + proc safe_open_command_redirect {cmd redir} { 81 + set cmd [make_arglist_safe $cmd] 82 + open |[concat $cmd $redir] r 83 + } 84 + 85 + # opens a pipeline with several commands for reading 86 + # cmds is a list of lists, each of which specifies a command and its arguments 87 + # calls `open` and returns the file id 88 + proc safe_open_pipeline {cmds} { 89 + set cmd {} 90 + foreach subcmd $cmds { 91 + set cmd [concat $cmd | [make_arglist_safe $subcmd]] 92 + } 93 + open $cmd r 94 + } 95 + 96 + # End exec/open wrappers 97 + 98 proc hasworktree {} { 99 return [expr {[exec git rev-parse --is-bare-repository] == "false" && 100 [exec git rev-parse --is-inside-git-dir] == "false"}] ··· 220 set mlist {} 221 set nr_unmerged 0 222 if {[catch { 223 + set fd [safe_open_command {git ls-files -u}] 224 } err]} { 225 show_error {} . "[mc "Couldn't get list of unmerged files:"] $err" 226 exit 1 ··· 382 } elseif {[lsearch -exact $revs --all] >= 0} { 383 lappend revs HEAD 384 } 385 + if {[catch {set ids [safe_exec [concat git rev-parse $revs]]} err]} { 386 # we get stdout followed by stderr in $err 387 # for an unknown rev, git rev-parse echoes it and then errors out 388 set errlines [split $err "\n"] ··· 439 return $ret 440 } 441 442 # Start off a git log process and arrange to read its output 443 proc start_rev_list {view} { 444 global startmsecs commitidx viewcomplete curview ··· 460 set args $viewargs($view) 461 if {$viewargscmd($view) ne {}} { 462 if {[catch { 463 + set str [safe_exec [list sh -c $viewargscmd($view)]] 464 } err]} { 465 error_popup "[mc "Error executing --argscmd command:"] $err" 466 return 0 ··· 498 } 499 500 if {[catch { 501 + set fd [safe_open_command_redirect [concat git log --no-color -z --pretty=raw $show_notes \ 502 + --parents --boundary $args --stdin] \ 503 + [list "<<[join [concat $revs "--" $files] "\n"]"]] 504 } err]} { 505 error_popup "[mc "Error executing git log:"] $err" 506 return 0 ··· 534 set pid [pid $fd] 535 536 if {$::tcl_platform(platform) eq {windows}} { 537 + safe_exec [list taskkill /pid $pid] 538 } else { 539 + safe_exec [list kill $pid] 540 } 541 } 542 catch {close $fd} ··· 651 set args $vorigargs($view) 652 } 653 if {[catch { 654 + set fd [safe_open_command_redirect [concat git log --no-color -z --pretty=raw $show_notes \ 655 + --parents --boundary $args --stdin] \ 656 + [list "<<[join [concat $revs "--" $vfilelimit($view)] "\n"]"]] 657 } err]} { 658 error_popup "[mc "Error executing git log:"] $err" 659 return ··· 1620 # and if we already know about it, using the rewritten 1621 # parent as a substitute parent for $id's children. 1622 if {![catch { 1623 + set rwid [safe_exec [list git rev-list --first-parent --max-count=1 \ 1624 + $id -- $vfilelimit($view)]] 1625 }]} { 1626 if {$rwid ne {} && [info exists varcid($view,$rwid)]} { 1627 # use $rwid in place of $id ··· 1741 global tclencoding 1742 1743 # Invoke git-log to handle automatic encoding conversion 1744 + set fd [safe_open_command [concat git log --no-color --pretty=raw -1 $id]] 1745 # Read the results using i18n.logoutputencoding 1746 fconfigure $fd -translation lf -eofchar {} 1747 if {$tclencoding != {}} { ··· 1877 foreach v {tagids idtags headids idheads otherrefids idotherrefs} { 1878 unset -nocomplain $v 1879 } 1880 + set refd [safe_open_command [list git show-ref -d]] 1881 if {$tclencoding != {}} { 1882 fconfigure $refd -encoding $tclencoding 1883 } ··· 1925 set selectheadid {} 1926 if {$selecthead ne {}} { 1927 catch { 1928 + set selectheadid [safe_exec [list git rev-parse --verify $selecthead]] 1929 } 1930 } 1931 } ··· 2185 {mc "Reread re&ferences" command rereadrefs} 2186 {mc "&List references" command showrefs -accelerator F2} 2187 {xx "" separator} 2188 + {mc "Start git &gui" command {safe_exec_redirect [list git gui] [list &]}} 2189 {xx "" separator} 2190 {mc "&Quit" command doquit -accelerator Meta1-Q} 2191 }} ··· 2967 set remove_tmp 0 2968 if {[catch { 2969 set try_count 0 2970 + while {[catch {set f [safe_open_file $config_file_tmp {WRONLY CREAT EXCL}]}]} { 2971 if {[incr try_count] > 50} { 2972 error "Unable to write config file: $config_file_tmp exists" 2973 } ··· 3683 set tmpdir $gitdir 3684 } 3685 set gitktmpformat [file join $tmpdir ".gitk-tmp.XXXXXX"] 3686 + if {[catch {set gitktmpdir [safe_exec [list mktemp -d $gitktmpformat]]}]} { 3687 set gitktmpdir [file join $gitdir [format ".gitk-tmp.%s" [pid]]] 3688 } 3689 if {[catch {file mkdir $gitktmpdir} err]} { ··· 3705 proc save_file_from_commit {filename output what} { 3706 global nullfile 3707 3708 + if {[catch {safe_exec_redirect [list git show $filename --] [list > $output]} err]} { 3709 if {[string match "fatal: bad revision *" $err]} { 3710 return $nullfile 3711 } ··· 3770 3771 if {$difffromfile ne {} && $difftofile ne {}} { 3772 set cmd [list [shellsplit $extdifftool] $difffromfile $difftofile] 3773 + if {[catch {set fl [safe_open_command $cmd]} err]} { 3774 file delete -force $diffdir 3775 error_popup "$extdifftool: [mc "command failed:"] $err" 3776 } else { ··· 3874 # Find the SHA1 ID of the blob for file $fname in the index 3875 # at stage 0 or 2 3876 proc index_sha1 {fname} { 3877 + set f [safe_open_command [list git ls-files -s $fname]] 3878 while {[gets $f line] >= 0} { 3879 set info [lindex [split $line "\t"] 0] 3880 set stage [lindex $info 2] ··· 3934 # being given an absolute path... 3935 set f [make_relative $f] 3936 lappend cmdline $base_commit $f 3937 + if {[catch {safe_exec_redirect $cmdline [list &]} err]} { 3938 error_popup "[mc "git gui blame: command failed:"] $err" 3939 } 3940 } ··· 3962 # must be a merge in progress... 3963 if {[catch { 3964 # get the last line from .git/MERGE_HEAD 3965 + set f [safe_open_file [file join $gitdir MERGE_HEAD] r] 3966 set id [lindex [split [read $f] "\n"] end-1] 3967 close $f 3968 } err]} { ··· 3985 } 3986 set line [lindex $h 1] 3987 } 3988 + set blamefile [file join $cdup $flist_menu_file] 3989 if {$from_index ne {}} { 3990 + set blameargs [list \ 3991 + [list git cat-file blob $from_index] \ 3992 + [list git blame -p -L$line,+1 --contents - -- $blamefile]] 3993 } else { 3994 + set blameargs [list \ 3995 + [list git blame -p -L$line,+1 $id -- $blamefile]] 3996 } 3997 if {[catch { 3998 + set f [safe_open_pipeline $blameargs] 3999 } err]} { 4000 error_popup [mc "Couldn't start git blame: %s" $err] 4001 return ··· 4920 # must be "containing:", i.e. we're searching commit info 4921 return 4922 } 4923 + set cmd [concat git diff-tree -r -s --stdin $gdtargs] 4924 + set filehighlight [safe_open_command_rw $cmd] 4925 fconfigure $filehighlight -blocking 0 4926 filerun $filehighlight readfhighlight 4927 set fhl_list {} ··· 5350 global viewmainheadid vfilelimit viewinstances mainheadid 5351 5352 catch { 5353 + set rfd [safe_open_command [concat git rev-list -1 $mainheadid \ 5354 + -- $vfilelimit($view)]] 5355 set j [reg_instance $rfd] 5356 lappend viewinstances($view) $j 5357 fconfigure $rfd -blocking 0 ··· 5416 if {!$showlocalchanges || !$hasworktree} return 5417 incr lserial 5418 if {[package vcompare $git_version "1.7.2"] >= 0} { 5419 + set cmd "git diff-index --cached --ignore-submodules=dirty HEAD" 5420 } else { 5421 + set cmd "git diff-index --cached HEAD" 5422 } 5423 if {$vfilelimit($curview) ne {}} { 5424 set cmd [concat $cmd -- $vfilelimit($curview)] 5425 } 5426 + set fd [safe_open_command $cmd] 5427 fconfigure $fd -blocking 0 5428 set i [reg_instance $fd] 5429 filerun $fd [list readdiffindex $fd $lserial $i] ··· 5448 } 5449 5450 # now see if there are any local changes not checked in to the index 5451 + set cmd "git diff-files" 5452 if {$vfilelimit($curview) ne {}} { 5453 set cmd [concat $cmd -- $vfilelimit($curview)] 5454 } 5455 + set fd [safe_open_command $cmd] 5456 fconfigure $fd -blocking 0 5457 set i [reg_instance $fd] 5458 filerun $fd [list readdifffiles $fd $serial $i] ··· 7241 global web_browser 7242 7243 if {$web_browser eq {}} return 7244 + # Use concat here in case $web_browser is a command plus some arguments 7245 + if {[catch {safe_exec_redirect [concat $web_browser [list $url]] [list &]} err]} { 7246 error_popup "[mc "Error starting web browser:"] $err" 7247 } 7248 } ··· 7744 if {![info exists treefilelist($id)]} { 7745 if {![info exists treepending]} { 7746 if {$id eq $nullid} { 7747 + set cmd [list git ls-files] 7748 } elseif {$id eq $nullid2} { 7749 + set cmd [list git ls-files --stage -t] 7750 } else { 7751 + set cmd [list git ls-tree -r $id] 7752 } 7753 + if {[catch {set gtf [safe_open_command $cmd]}]} { 7754 return 7755 } 7756 set treepending $id ··· 7814 return 7815 } 7816 if {$diffids eq $nullid} { 7817 + if {[catch {set bf [safe_open_file $f r]} err]} { 7818 puts "oops, can't read $f: $err" 7819 return 7820 } 7821 } else { 7822 set blob [lindex $treeidlist($diffids) $i] 7823 + if {[catch {set bf [safe_open_command [concat git cat-file blob $blob]]} err]} { 7824 puts "oops, error reading blob $blob: $err" 7825 return 7826 } ··· 7970 if {$i >= 0} { 7971 if {[llength $ids] > 1 && $j < 0} { 7972 # comparing working directory with some specific revision 7973 + set cmd [concat git diff-index $flags] 7974 if {$i == 0} { 7975 lappend cmd -R [lindex $ids 1] 7976 } else { ··· 7978 } 7979 } else { 7980 # comparing working directory with index 7981 + set cmd [concat git diff-files $flags] 7982 if {$j == 1} { 7983 lappend cmd -R 7984 } ··· 7987 if {[package vcompare $git_version "1.7.2"] >= 0} { 7988 set flags "$flags --ignore-submodules=dirty" 7989 } 7990 + set cmd [concat git diff-index --cached $flags] 7991 if {[llength $ids] > 1} { 7992 # comparing index with specific revision 7993 if {$j == 0} { ··· 8003 if {$log_showroot} { 8004 lappend flags --root 8005 } 8006 + set cmd [concat git diff-tree -r $flags $ids] 8007 } 8008 return $cmd 8009 } ··· 8015 if {$limitdiffs && $vfilelimit($curview) ne {}} { 8016 set cmd [concat $cmd -- $vfilelimit($curview)] 8017 } 8018 + if {[catch {set gdtf [safe_open_command $cmd]}]} return 8019 8020 set treepending $ids 8021 set treediff {} ··· 8135 if {$limitdiffs && $vfilelimit($curview) ne {}} { 8136 set cmd [concat $cmd -- $vfilelimit($curview)] 8137 } 8138 + if {[catch {set bdf [safe_open_command $cmd]} err]} { 8139 error_popup [mc "Error getting diffs: %s" $err] 8140 return 8141 } ··· 8852 set id [lindex $matches 0] 8853 } 8854 } else { 8855 + if {[catch {set id [safe_exec [list git rev-parse --verify $sha1string]]}]} { 8856 error_popup [mc "Revision %s is not known" $sha1string] 8857 return 8858 } ··· 9158 9159 if {![info exists patchids($id)]} { 9160 set cmd [diffcmd [list $id] {-p --root}] 9161 if {[catch { 9162 + set x [safe_exec_redirect $cmd [list | git patch-id]] 9163 set patchids($id) [lindex $x 0] 9164 }]} { 9165 set patchids($id) "error" ··· 9255 set fna [file join $tmpdir "commit-[string range $a 0 7]"] 9256 set fnb [file join $tmpdir "commit-[string range $b 0 7]"] 9257 if {[catch { 9258 + safe_exec_redirect [list git diff-tree -p --pretty $a] [list >$fna] 9259 + safe_exec_redirect [list git diff-tree -p --pretty $b] [list >$fnb] 9260 } err]} { 9261 error_popup [mc "Error writing commit to file: %s" $err] 9262 return 9263 } 9264 if {[catch { 9265 + set fd [safe_open_command "diff -U$diffcontext $fna $fnb"] 9266 } err]} { 9267 error_popup [mc "Error diffing commits: %s" $err] 9268 return ··· 9402 set newid [$patchtop.tosha1 get] 9403 set fname [$patchtop.fname get] 9404 set cmd [diffcmd [list $oldid $newid] -p] 9405 + if {[catch {safe_exec_redirect $cmd [list >$fname &]} err]} { 9406 error_popup "[mc "Error creating patch:"] $err" $patchtop 9407 } 9408 catch {destroy $patchtop} ··· 9471 } 9472 if {[catch { 9473 if {$msg != {}} { 9474 + safe_exec [list git tag -a -m $msg $tag $id] 9475 } else { 9476 + safe_exec [list git tag $tag $id] 9477 } 9478 } err]} { 9479 error_popup "[mc "Error creating tag:"] $err" $mktagtop ··· 9541 if {$autosellen < 40} { 9542 lappend cmd --abbrev=$autosellen 9543 } 9544 + set reference [safe_exec [concat $cmd $rowmenuid]] 9545 9546 clipboard clear 9547 clipboard append $reference ··· 9591 set id [$wrcomtop.sha1 get] 9592 set cmd "echo $id | [$wrcomtop.cmd get]" 9593 set fname [$wrcomtop.fname get] 9594 + if {[catch {safe_exec_redirect [list sh -c $cmd] [list >$fname &]} err]} { 9595 error_popup "[mc "Error writing commit:"] $err" $wrcomtop 9596 } 9597 catch {destroy $wrcomtop} ··· 9695 nowbusy newbranch 9696 update 9697 if {[catch { 9698 + safe_exec [concat git branch $cmdargs] 9699 } err]} { 9700 notbusy newbranch 9701 error_popup $err ··· 9736 nowbusy renamebranch 9737 update 9738 if {[catch { 9739 + safe_exec [concat git branch $cmdargs] 9740 } err]} { 9741 notbusy renamebranch 9742 error_popup $err ··· 9777 } 9778 } 9779 9780 + safe_exec_redirect [concat git citool $tool_args] [list &] 9781 9782 array unset env GIT_AUTHOR_* 9783 array set env $save_env ··· 9800 update 9801 # Unfortunately git-cherry-pick writes stuff to stderr even when 9802 # no error occurs, and exec takes that as an indication of error... 9803 + if {[catch {safe_exec [list sh -c "git cherry-pick -r $rowmenuid 2>&1"]} err]} { 9804 notbusy cherrypick 9805 if {[regexp -line \ 9806 {Entry '(.*)' (would be overwritten by merge|not uptodate)} \ ··· 9862 nowbusy revert [mc "Reverting"] 9863 update 9864 9865 + if [catch {safe_exec [list git revert --no-edit $rowmenuid]} err] { 9866 notbusy revert 9867 if [regexp {files would be overwritten by merge:(\n(( |\t)+[^\n]+\n)+)}\ 9868 $err match files] { ··· 9938 bind $w <Visibility> "grab $w; focus $w" 9939 tkwait window $w 9940 if {!$confirm_ok} return 9941 + if {[catch {set fd [safe_open_command_redirect \ 9942 + [list git reset --$resettype $rowmenuid] [list 2>@1]]} err]} { 9943 error_popup $err 9944 } else { 9945 dohidelocalchanges ··· 10010 10011 # check the tree is clean first?? 10012 set newhead $headmenuhead 10013 + set command [list git checkout] 10014 if {[string match "remotes/*" $newhead]} { 10015 set remote $newhead 10016 set newhead [string range $newhead [expr [string last / $newhead] + 1] end] ··· 10024 } else { 10025 lappend command $newhead 10026 } 10027 nowbusy checkout [mc "Checking out"] 10028 update 10029 dohidelocalchanges 10030 if {[catch { 10031 + set fd [safe_open_command_redirect $command [list 2>@1]] 10032 } err]} { 10033 notbusy checkout 10034 error_popup $err ··· 10094 } 10095 nowbusy rmbranch 10096 update 10097 + if {[catch {safe_exec [list git branch -D $head]} err]} { 10098 notbusy rmbranch 10099 error_popup $err 10100 return ··· 10285 set cachedarcs 0 10286 set allccache [file join $gitdir "gitk.cache"] 10287 if {![catch { 10288 + set f [safe_open_file $allccache r] 10289 set allcwait 1 10290 getcache $f 10291 }]} return ··· 10294 if {$allcwait} { 10295 return 10296 } 10297 + set cmd [list git rev-list --parents] 10298 set allcupdate [expr {$seeds ne {}}] 10299 if {!$allcupdate} { 10300 set ids "--all" ··· 10322 if {$ids ne {}} { 10323 if {$ids eq "--all"} { 10324 set cmd [concat $cmd "--all"] 10325 + set fd [safe_open_command $cmd] 10326 } else { 10327 + set cmd [concat $cmd --stdin] 10328 + set fd [safe_open_command_redirect $cmd [list "<<[join $ids "\n"]"]] 10329 } 10330 fconfigure $fd -blocking 0 10331 incr allcommits 10332 nowbusy allcommits ··· 10716 set cachearc 0 10717 set cachedarcs $nextarc 10718 catch { 10719 + set f [safe_open_file $allccache w] 10720 puts $f [list 1 $cachedarcs] 10721 run writecache $f 10722 } ··· 11419 11420 if {![info exists cached_tagcontent($tag)]} { 11421 catch { 11422 + set cached_tagcontent($tag) [safe_exec [list git cat-file -p $tag]] 11423 } 11424 } 11425 $ctext insert end "[mc "Tag"]: $tag\n" bold ··· 12305 set r $path_attr_cache($attr,$path) 12306 } else { 12307 set r "unspecified" 12308 + if {![catch {set line [safe_exec [list git check-attr $attr -- $path]]}]} { 12309 regexp "(.*): $attr: (.*)" $line m f r 12310 } 12311 set path_attr_cache($attr,$path) $r ··· 12332 while {$newlist ne {}} { 12333 set head [lrange $newlist 0 [expr {$lim - 1}]] 12334 set newlist [lrange $newlist $lim end] 12335 + if {![catch {set rlist [safe_exec [concat git check-attr $attr -- $head]]}]} { 12336 foreach row [split $rlist "\n"] { 12337 if {[regexp "(.*): $attr: (.*)" $row m path value]} { 12338 if {[string index $path 0] eq "\""} { ··· 12385 12386 # on OSX bring the current Wish process window to front 12387 if {[tk windowingsystem] eq "aqua"} { 12388 + safe_exec [list osascript -e [format { 12389 tell application "System Events" 12390 set frontmost of processes whose unix id is %d to true 12391 end tell 12392 + } [pid] ]] 12393 } 12394 12395 # Unset GIT_TRACE var if set ··· 12634 if {$i >= [llength $argv] && $revtreeargs ne {}} { 12635 # no -- on command line, but some arguments (other than --argscmd) 12636 if {[catch { 12637 + set f [safe_exec [concat git rev-parse --no-revs --no-flags $revtreeargs]] 12638 set cmdline_files [split $f "\n"] 12639 set n [llength $cmdline_files] 12640 set revtreeargs [lrange $revtreeargs 0 end-$n]
+11
t/t1300-config.sh
··· 2852 2853 done 2854 2855 test_done
··· 2852 2853 done 2854 2855 + test_expect_success 'writing value with trailing CR not stripped on read' ' 2856 + test_when_finished "rm -rf cr-test" && 2857 + 2858 + printf "bar\r\n" >expect && 2859 + git init cr-test && 2860 + git -C cr-test config set core.foo $(printf "bar\r") && 2861 + git -C cr-test config get core.foo >actual && 2862 + 2863 + test_cmp expect actual 2864 + ' 2865 + 2866 test_done
+23
t/t5558-clone-bundle-uri.sh
··· 1249 trace-mult.txt >bundle-fetches && 1250 test_line_count = 1 bundle-fetches 1251 ' 1252 # Do not add tests here unless they use the HTTP server, as they will 1253 # not run unless the HTTP dependencies exist. 1254
··· 1249 trace-mult.txt >bundle-fetches && 1250 test_line_count = 1 bundle-fetches 1251 ' 1252 + 1253 + test_expect_success 'bundles with space in URI are rejected' ' 1254 + test_when_finished "rm -rf busted repo" && 1255 + mkdir -p "$HOME/busted/ /$HOME/repo/.git/objects/bundles" && 1256 + git clone --bundle-uri="$HTTPD_URL/bogus $HOME/busted/" "$HTTPD_URL/smart/fetch.git" repo 2>err && 1257 + test_grep "error: bundle-uri: URI is malformed: " err && 1258 + find busted -type f >files && 1259 + test_must_be_empty files 1260 + ' 1261 + 1262 + test_expect_success 'bundles with newline in URI are rejected' ' 1263 + test_when_finished "rm -rf busted repo" && 1264 + git clone --bundle-uri="$HTTPD_URL/bogus\nget $HTTPD_URL/bogus $HOME/busted" "$HTTPD_URL/smart/fetch.git" repo 2>err && 1265 + test_grep "error: bundle-uri: URI is malformed: " err && 1266 + test_path_is_missing "$HOME/busted" 1267 + ' 1268 + 1269 + test_expect_success 'bundles with newline in target path are rejected' ' 1270 + git clone --bundle-uri="$HTTPD_URL/bogus" "$HTTPD_URL/smart/fetch.git" "$(printf "escape\nget $HTTPD_URL/bogus .")" 2>err && 1271 + test_grep "error: bundle-uri: filename is malformed: " err && 1272 + test_path_is_missing escape 1273 + ' 1274 + 1275 # Do not add tests here unless they use the HTTP server, as they will 1276 # not run unless the HTTP dependencies exist. 1277
+33
t/t7450-bad-git-dotfiles.sh
··· 373 test_path_is_missing nested_checkout/thing2/.git 374 ' 375 376 test_done
··· 373 test_path_is_missing nested_checkout/thing2/.git 374 ' 375 376 + test_expect_success SYMLINKS,!WINDOWS,!MINGW 'submodule must not checkout into different directory' ' 377 + test_when_finished "rm -rf sub repo bad-clone" && 378 + 379 + git init sub && 380 + write_script sub/post-checkout <<-\EOF && 381 + touch "$PWD/foo" 382 + EOF 383 + git -C sub add post-checkout && 384 + git -C sub commit -m hook && 385 + 386 + git init repo && 387 + git -C repo -c protocol.file.allow=always submodule add "$PWD/sub" sub && 388 + git -C repo mv sub $(printf "sub\r") && 389 + 390 + # Ensure config values containing CR are wrapped in quotes. 391 + git config unset -f repo/.gitmodules submodule.sub.path && 392 + printf "\tpath = \"sub\r\"\n" >>repo/.gitmodules && 393 + 394 + git config unset -f repo/.git/modules/sub/config core.worktree && 395 + { 396 + printf "[core]\n" && 397 + printf "\tworktree = \"../../../sub\r\"\n" 398 + } >>repo/.git/modules/sub/config && 399 + 400 + ln -s .git/modules/sub/hooks repo/sub && 401 + git -C repo add -A && 402 + git -C repo commit -m submodule && 403 + 404 + git -c protocol.file.allow=always clone --recurse-submodules repo bad-clone && 405 + ! test -f "$PWD/foo" && 406 + test -f $(printf "bad-clone/sub\r/post-checkout") 407 + ' 408 + 409 test_done