git-gui: Add support of SHA256 repo

This patch adds the basic support of SHA256 Git repositories. Most of changes are idiomatic replacement of the hard-coded hash ID length, but there are subtle things: * The hash length is determined on startup, and stored in $hashlength global variable (either 40 or 64). * The hard-coded "40" are replaced with $hashlength; for regexp patterns, the ugly string map is used. * Some code have the fixed numbers like 39 and 45, and those are replaced with the $hashlength and the offset correction. * $nullid and $nullid2 are generated for the hash length. A caveat is that repository picker dialog is performed before evaluating the repo type, hence $hashlength isn't set there yet. So the code dealing with the hard-coded "40" are handled differently; namely, the regexp range is expanded, and the null id is generated from the HEAD id length locally. Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Johannes Sixt <j6t@kdbg.org>

Takashi Iwai committed Jul 16, 2025 at 09:32 UTC dab92fe42fad87a2f7067589a32ee08e70d5354b
5 files changed +31 -12
git-gui.sh
+14 -3
@@ -1298,6 +1298,17 @@ if {[catch {
1298 set picked 1
1299 }
1300
1301 +# Use object format as hash algorithm (either "sha1" or "sha256")
1302 +set hashalgorithm [git rev-parse --show-object-format]
1303 +if {$hashalgorithm eq "sha1"} {
1304 + set hashlength 40
1305 +} elseif {$hashalgorithm eq "sha256"} {
1306 + set hashlength 64
1307 +} else {
1308 + puts stderr "Unknown hash algorithm: $hashalgorithm"
1309 + exit 1
1310 +}
1311 +
1312 # we expand the _gitdir when it's just a single dot (i.e. when we're being
1313 # run from the .git dir itself) lest the routines to find the worktree
1314 # get confused
@@ -1391,8 +1402,8 @@ set is_conflict_diff 0
1402 set last_revert {}
1403 set last_revert_enc {}
1404
1394 -set nullid "0000000000000000000000000000000000000000"
1395 -set nullid2 "0000000000000000000000000000000000000001"
1405 +set nullid [string repeat 0 $hashlength]
1406 +set nullid2 "[string repeat 0 [expr $hashlength - 1]]1"
1407
1408 ######################################################################
1409 ##
@@ -3202,7 +3213,7 @@ blame {
3213 if {$head eq {}} {
3214 load_current_branch
3215 } else {
3205 - if {[regexp {^[0-9a-f]{1,39}$} $head]} {
3216 + if {[regexp [string map "@@ [expr $hashlength - 1]" {^[0-9a-f]{1,@@}$}] $head]} {
3217 if {[catch {
3218 set head [git rev-parse --verify $head]
3219 } err]} {
lib/blame.tcl
+8 -4
@@ -426,6 +426,7 @@ method _kill {} {
426
427 method _load {jump} {
428 variable group_colors
429 + global hashlength
430
431 _hide_tooltip $this
432
@@ -436,7 +437,7 @@ method _load {jump} {
437 $i conf -state normal
438 $i delete 0.0 end
439 foreach g [$i tag names] {
439 - if {[regexp {^g[0-9a-f]{40}$} $g]} {
440 + if {[regexp [string map "@@ $hashlength" {^g[0-9a-f]{@@}$}] $g]} {
441 $i tag delete $g
442 }
443 }
@@ -500,6 +501,8 @@ method _load {jump} {
501 }
502
503 method _history_menu {} {
504 + global hashlength
505 +
506 set m $w.backmenu
507 if {[winfo exists $m]} {
508 $m delete 0 end
@@ -513,7 +516,7 @@ method _history_menu {} {
516 set c [lindex $e 0]
517 set f [lindex $e 1]
518
516 - if {[regexp {^[0-9a-f]{40}$} $c]} {
519 + if {[regexp [string map "@@ $hashlength" {^[0-9a-f]{@@}$}] $c]} {
520 set t [string range $c 0 8]...
521 } elseif {$c eq {}} {
522 set t {Working Directory}
@@ -627,6 +630,7 @@ method _exec_blame {cur_w cur_d options cur_s} {
630 method _read_blame {fd cur_w cur_d} {
631 upvar #0 $cur_d line_data
632 variable group_colors
633 + global hashlength nullid
634
635 if {$fd ne $current_fd} {
636 catch {close $fd}
@@ -635,7 +639,7 @@ method _read_blame {fd cur_w cur_d} {
639
640 $cur_w conf -state normal
641 while {[gets $fd line] >= 0} {
638 - if {[regexp {^([a-z0-9]{40}) (\d+) (\d+) (\d+)$} $line line \
642 + if {[regexp [string map "@@ $hashlength" {^([a-z0-9]{@@}) (\d+) (\d+) (\d+)$}] $line line \
643 cmit original_line final_line line_count]} {
644 set r_commit $cmit
645 set r_orig_line $original_line
@@ -648,7 +652,7 @@ method _read_blame {fd cur_w cur_d} {
652 set oln $r_orig_line
653 set cmit $r_commit
654
651 - if {[regexp {^0{40}$} $cmit]} {
655 + if {$cmit eq $nullid} {
656 set commit_abbr work
657 set commit_type curr_commit
658 } elseif {$cmit eq $commit} {
lib/choose_repository.tcl
+4 -3
@@ -879,7 +879,7 @@ method _do_clone_full_end {ok} {
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]} {
882 + if {[regexp "^(.{40,64})\t\t" $line line HEAD]} {
883 break
884 }
885 }
@@ -987,8 +987,9 @@ method _readtree_wait {fd} {
987
988 # -- Run the post-checkout hook.
989 #
990 - set fd_ph [githook_read post-checkout [string repeat 0 40] \
991 - [git rev-parse HEAD] 1]
990 + set head_id [git rev-parse HEAD]
991 + set fd_ph [githook_read post-checkout \
992 + [string repeat 0 [string length $head_id]] $head_id 1]
993 if {$fd_ph ne {}} {
994 global pch_error
995 set pch_error {}
lib/commit.tcl
+2 -1
@@ -346,6 +346,7 @@ proc commit_committree {fd_wt curHEAD msg_p} {
346 global file_states selected_paths rescan_active
347 global repo_config
348 global env
349 + global hashlength
350
351 gets $fd_wt tree_id
352 if {[catch {close $fd_wt} err]} {
@@ -365,7 +366,7 @@ proc commit_committree {fd_wt curHEAD msg_p} {
366 close $fd_ot
367
368 if {[string equal -length 5 {tree } $old_tree]
368 - && [string length $old_tree] == 45} {
369 + && [string length $old_tree] == [expr {$hashlength + 5}]} {
370 set old_tree [string range $old_tree 5 end]
371 } else {
372 error [mc "Commit %s appears to be corrupt" $PARENT]
lib/remote_branch_delete.tcl
+3 -1
@@ -323,6 +323,8 @@ method _load {cache uri} {
323 }
324
325 method _read {cache fd} {
326 + global hashlength
327 +
328 if {$fd ne $active_ls} {
329 catch {close $fd}
330 return
@@ -330,7 +332,7 @@ method _read {cache fd} {
332
333 while {[gets $fd line] >= 0} {
334 if {[string match {*^{}} $line]} continue
333 - if {[regexp {^([0-9a-f]{40}) (.*)$} $line _junk obj ref]} {
335 + if {[regexp [string map "@@ $hashlength" {^([0-9a-f]{@@}) (.*)$}] $line _junk obj ref]} {
336 if {[regsub ^refs/heads/ $ref {} abr]} {
337 lappend head_list $abr
338 lappend head_cache($cache) $abr