gitk: prevent overly long command lines

To avoid running into command line limitations, some of Git's commands support the `--stdin` option. Let's use exactly this option in the three rev-list/log invocations in gitk that would otherwise possibly run the danger of trying to invoke a too-long command line. While it is easy to redirect either stdin or stdout in Tcl/Tk scripts, what we need here is both. We need to capture the output, yet we also need to pipe in the revs/files arguments via stdin (because stdin does not have any limit, unlike the command line). To help this, we use the neat Tcl feature where you can capture stdout and at the same time feed a fixed string as stdin to the spawned process. One non-obvious aspect about this change is that the `--stdin` option allows to specify revs, the double-dash, and files, but *no* other options such as `--not`. This is addressed by prefixing the "negative" revs with `^` explicitly rather than relying on the `--not` option (thanks for coming up with that idea, Max!). This fixes https://github.com/git-for-windows/git/issues/1987 Analysis-and-initial-patch-by: Max Kirillov <max@max630.net> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Johannes Schindelin committed Jan 24, 2023 at 11:23 UTC bb5cb23daf751790950ff9f761f8884e21c88d00
1 file changed +19 -5
gitk
+19 -5
@@ -405,14 +405,16 @@ proc start_rev_list {view} {
405 if {$revs eq {}} {
406 return 0
407 }
408 - set args [concat $vflags($view) $revs]
408 + set args $vflags($view)
409 } else {
410 + set revs {}
411 set args $vorigargs($view)
412 }
413
414 if {[catch {
415 set fd [open [concat | git log --no-color -z --pretty=raw $show_notes \
415 - --parents --boundary $args "--" $files] r]
416 + --parents --boundary $args --stdin \
417 + "<<[join [concat $revs "--" $files] "\\n"]"] r]
418 } err]} {
419 error_popup "[mc "Error executing git log:"] $err"
420 return 0
@@ -554,13 +556,19 @@ proc updatecommits {} {
556 set revs $newrevs
557 set vposids($view) [lsort -unique [concat $oldpos $vposids($view)]]
558 }
557 - set args [concat $vflags($view) $revs --not $oldpos]
559 + set args $vflags($view)
560 + foreach r $oldpos {
561 + lappend revs "^$r"
562 + }
563 } else {
564 + set revs {}
565 set args $vorigargs($view)
566 }
567 if {[catch {
568 set fd [open [concat | git log --no-color -z --pretty=raw $show_notes \
563 - --parents --boundary $args "--" $vfilelimit($view)] r]
569 + --parents --boundary $args --stdin \
570 + "<<[join [concat $revs "--" \
571 + $vfilelimit($view)] "\\n"]"] r]
572 } err]} {
573 error_popup "[mc "Error executing git log:"] $err"
574 return
@@ -10231,10 +10239,16 @@ proc getallcommits {} {
10239 foreach id $seeds {
10240 lappend ids "^$id"
10241 }
10242 + lappend ids "--"
10243 }
10244 }
10245 if {$ids ne {}} {
10237 - set fd [open [concat $cmd $ids] r]
10246 + if {$ids eq "--all"} {
10247 + set cmd [concat $cmd "--all"]
10248 + } else {
10249 + set cmd [concat $cmd --stdin "<<[join $ids "\\n"]"]
10250 + }
10251 + set fd [open $cmd r]
10252 fconfigure $fd -blocking 0
10253 incr allcommits
10254 nowbusy allcommits