{"thread":{"id":"63737","subject":"[PATCH v2] git-gui: Add support of SHA256 repo","startedAt":"2025-07-03T12:04:37Z","lastAt":"2025-07-16T07:24:08Z","messageCount":5,"participants":["Takashi Iwai","Johannes Sixt"],"isPatch":true,"patchVersion":2,"patchTotal":null},"messages":[{"id":"521267","messageId":"20250703120430.17240-1-tiwai@suse.de","threadId":"63737","inReplyTo":null,"subject":"[PATCH v2] git-gui: Add support of SHA256 repo","fromName":"Takashi Iwai","fromEmail":"tiwai@suse.de","sentAt":"2025-07-03T12:04:28Z","receivedAt":"2025-07-03T12:04:37Z","isPatch":true,"sender":{"key":"tiwai@suse.de","avatar":"https://avatars.githubusercontent.com/u/306482?v=4"},"body":"This patch adds the basic support of SHA256 Git repositories.\nThe needed changes were mostly about adjusting the fixed ID length of\nSHA1 (40) to be variable depending on the repo type.\n\nSigned-off-by: Takashi Iwai <tiwai@suse.de>\n---\nv1->v2: Fix the handling in commit_committree, too\n\n git-gui/git-gui.sh                   | 13 ++++++++++++-\n git-gui/lib/blame.tcl                | 12 ++++++++----\n git-gui/lib/choose_repository.tcl    |  8 ++++++--\n git-gui/lib/commit.tcl               |  3 ++-\n git-gui/lib/remote_branch_delete.tcl |  4 +++-\n 5 files changed, 31 insertions(+), 9 deletions(-)\n\ndiff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh\nindex 28572c889c0e..206981190535 100755\n--- a/git-gui/git-gui.sh\n+++ b/git-gui/git-gui.sh\n@@ -1275,6 +1275,17 @@ if {[catch {\n \tset picked 1\n }\n \n+# Use object format as hash algorightm (either \"sha1\" or \"sha256\")\n+set hashalgorithm [exec git rev-parse --show-object-format]\n+if {$hashalgorithm eq \"sha1\"} {\n+\tset hashlength 40\n+} elseif {$hashalgorithm eq \"sha256\"} {\n+\tset hashlength 64\n+} else {\n+\tputs stderr \"Unknown hash algorithm: $hashalgorithm\"\n+\texit 1\n+}\n+\n # we expand the _gitdir when it's just a single dot (i.e. when we're being\n # run from the .git dir itself) lest the routines to find the worktree\n # get confused\n@@ -1822,7 +1833,7 @@ proc short_path {path} {\n }\n \n set next_icon_id 0\n-set null_sha1 [string repeat 0 40]\n+set null_sha1 [string repeat 0 $hashlength]\n \n proc merge_state {path new_state {head_info {}} {index_info {}}} {\n \tglobal file_states next_icon_id null_sha1\ndiff --git a/git-gui/lib/blame.tcl b/git-gui/lib/blame.tcl\nindex 8441e109be32..1f0b8ea28504 100644\n--- a/git-gui/lib/blame.tcl\n+++ b/git-gui/lib/blame.tcl\n@@ -426,6 +426,7 @@ method _kill {} {\n \n method _load {jump} {\n \tvariable group_colors\n+\tglobal hashlength\n \n \t_hide_tooltip $this\n \n@@ -436,7 +437,7 @@ method _load {jump} {\n \t\t\t$i conf -state normal\n \t\t\t$i delete 0.0 end\n \t\t\tforeach g [$i tag names] {\n-\t\t\t\tif {[regexp {^g[0-9a-f]{40}$} $g]} {\n+\t\t\t\tif {[regexp [string map \"@@ $hashlength\" {^g[0-9a-f]{@@}$}] $g]} {\n \t\t\t\t\t$i tag delete $g\n \t\t\t\t}\n \t\t\t}\n@@ -500,6 +501,8 @@ method _load {jump} {\n }\n \n method _history_menu {} {\n+\tglobal hashlength\n+\n \tset m $w.backmenu\n \tif {[winfo exists $m]} {\n \t\t$m delete 0 end\n@@ -513,7 +516,7 @@ method _history_menu {} {\n \t\tset c [lindex $e 0]\n \t\tset f [lindex $e 1]\n \n-\t\tif {[regexp {^[0-9a-f]{40}$} $c]} {\n+\t\tif {[regexp [string map \"@@ $hashlength\" {^[0-9a-f]{@@}$}] $c]} {\n \t\t\tset t [string range $c 0 8]...\n \t\t} elseif {$c eq {}} {\n \t\t\tset t {Working Directory}\n@@ -627,6 +630,7 @@ method _exec_blame {cur_w cur_d options cur_s} {\n method _read_blame {fd cur_w cur_d} {\n \tupvar #0 $cur_d line_data\n \tvariable group_colors\n+\tglobal hashlength\n \n \tif {$fd ne $current_fd} {\n \t\tcatch {close $fd}\n@@ -635,7 +639,7 @@ method _read_blame {fd cur_w cur_d} {\n \n \t$cur_w conf -state normal\n \twhile {[gets $fd line] >= 0} {\n-\t\tif {[regexp {^([a-z0-9]{40}) (\\d+) (\\d+) (\\d+)$} $line line \\\n+\t\tif {[regexp [string map \"@@ $hashlength\" {^([a-z0-9]{@@}) (\\d+) (\\d+) (\\d+)$}] $line line \\\n \t\t\tcmit original_line final_line line_count]} {\n \t\t\tset r_commit     $cmit\n \t\t\tset r_orig_line  $original_line\n@@ -648,7 +652,7 @@ method _read_blame {fd cur_w cur_d} {\n \t\t\tset oln  $r_orig_line\n \t\t\tset cmit $r_commit\n \n-\t\t\tif {[regexp {^0{40}$} $cmit]} {\n+\t\t\tif {[regexp [string map \"@@ $hashlength\" {^0{@@}$}] $cmit]} {\n \t\t\t\tset commit_abbr work\n \t\t\t\tset commit_type curr_commit\n \t\t\t} elseif {$cmit eq $commit} {\ndiff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl\nindex d23abedcb36f..6078b1c7e2c4 100644\n--- a/git-gui/lib/choose_repository.tcl\n+++ b/git-gui/lib/choose_repository.tcl\n@@ -870,6 +870,8 @@ method _do_clone_HEAD {ok} {\n }\n \n method _do_clone_full_end {ok} {\n+\tglobal hashlength\n+\n \t$o_cons done $ok\n \n \tif {$ok} {\n@@ -879,7 +881,7 @@ method _do_clone_full_end {ok} {\n \t\tif {[file exists [gitdir FETCH_HEAD]]} {\n \t\t\tset fd [open [gitdir FETCH_HEAD] r]\n \t\t\twhile {[gets $fd line] >= 0} {\n-\t\t\t\tif {[regexp \"^(.{40})\\t\\t\" $line line HEAD]} {\n+\t\t\t\tif {[regexp [string map \"@@ $hashlength\" \"^(.{@@})\\t\\t\"] $line line HEAD]} {\n \t\t\t\t\tbreak\n \t\t\t\t}\n \t\t\t}\n@@ -965,6 +967,8 @@ method _do_clone_checkout {HEAD} {\n }\n \n method _readtree_wait {fd} {\n+\tglobal hashlength\n+\n \tset buf [read $fd]\n \t$o_status_op update_meter $buf\n \tappend readtree_err $buf\n@@ -986,7 +990,7 @@ method _readtree_wait {fd} {\n \n \t# -- Run the post-checkout hook.\n \t#\n-\tset fd_ph [githook_read post-checkout [string repeat 0 40] \\\n+\tset fd_ph [githook_read post-checkout [string repeat 0 $hashlength] \\\n \t\t[git rev-parse HEAD] 1]\n \tif {$fd_ph ne {}} {\n \t\tglobal pch_error\ndiff --git a/git-gui/lib/commit.tcl b/git-gui/lib/commit.tcl\nindex a570f9cdc6a4..7a7394a5c89c 100644\n--- a/git-gui/lib/commit.tcl\n+++ b/git-gui/lib/commit.tcl\n@@ -348,6 +348,7 @@ proc commit_committree {fd_wt curHEAD msg_p} {\n \tglobal file_states selected_paths rescan_active\n \tglobal repo_config\n \tglobal env\n+\tglobal hashlength\n \n \tgets $fd_wt tree_id\n \tif {[catch {close $fd_wt} err]} {\n@@ -367,7 +368,7 @@ proc commit_committree {fd_wt curHEAD msg_p} {\n \t\tclose $fd_ot\n \n \t\tif {[string equal -length 5 {tree } $old_tree]\n-\t\t\t&& [string length $old_tree] == 45} {\n+\t\t\t&& [string length $old_tree] == [expr {$hashlength + 5}]} {\n \t\t\tset old_tree [string range $old_tree 5 end]\n \t\t} else {\n \t\t\terror [mc \"Commit %s appears to be corrupt\" $PARENT]\ndiff --git a/git-gui/lib/remote_branch_delete.tcl b/git-gui/lib/remote_branch_delete.tcl\nindex 5ba9fcadd17f..8ea672479306 100644\n--- a/git-gui/lib/remote_branch_delete.tcl\n+++ b/git-gui/lib/remote_branch_delete.tcl\n@@ -323,6 +323,8 @@ method _load {cache uri} {\n }\n \n method _read {cache fd} {\n+\tglobal hashlength\n+\n \tif {$fd ne $active_ls} {\n \t\tcatch {close $fd}\n \t\treturn\n@@ -330,7 +332,7 @@ method _read {cache fd} {\n \n \twhile {[gets $fd line] >= 0} {\n \t\tif {[string match {*^{}} $line]} continue\n-\t\tif {[regexp {^([0-9a-f]{40})\t(.*)$} $line _junk obj ref]} {\n+\t\tif {[regexp [string map \"@@ $hashlength\" {^([0-9a-f]{@@})\t(.*)$}] $line _junk obj ref]} {\n \t\t\tif {[regsub ^refs/heads/ $ref {} abr]} {\n \t\t\t\tlappend head_list $abr\n \t\t\t\tlappend head_cache($cache) $abr\n-- \n2.50.0\n\n"},{"id":"521904","messageId":"b78bad36-d4ae-4d91-a72a-c3446e10d34b@kdbg.org","threadId":"63737","inReplyTo":"20250703120430.17240-1-tiwai@suse.de","subject":"Re: [PATCH v2] git-gui: Add support of SHA256 repo","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2025-07-14T16:28:13Z","receivedAt":"2025-07-14T16:28:22Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 03.07.25 um 14:04 schrieb Takashi Iwai:\n> This patch adds the basic support of SHA256 Git repositories.\n> The needed changes were mostly about adjusting the fixed ID length of\n> SHA1 (40) to be variable depending on the repo type.\n\nThank you. Being precise in the commit message would be very\nappreciated. You say \"mostly\", which makes me wonder what the cases are\nthat fall not under \"mostly\". How about:\n\n   Determine the hash length on startup, then replace the hard-coded\n   \"40\" by the variable value. Also fix <foo> to do <bar> so as to\n   account for <baz>.\n\nOr make a bullet list if there is more to enumerate. Or make a\nmulti-patch series where each patch has its own topic if this is warranted.\n\nNow reading on...\n\n> \n> Signed-off-by: Takashi Iwai <tiwai@suse.de>\n> ---\n> v1->v2: Fix the handling in commit_committree, too\n> \n>  git-gui/git-gui.sh                   | 13 ++++++++++++-\n>  git-gui/lib/blame.tcl                | 12 ++++++++----\n>  git-gui/lib/choose_repository.tcl    |  8 ++++++--\n>  git-gui/lib/commit.tcl               |  3 ++-\n>  git-gui/lib/remote_branch_delete.tcl |  4 +++-\n>  5 files changed, 31 insertions(+), 9 deletions(-)\n> \n> diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh\n> index 28572c889c0e..206981190535 100755\n> --- a/git-gui/git-gui.sh\n> +++ b/git-gui/git-gui.sh\n> @@ -1275,6 +1275,17 @@ if {[catch {\n>  \tset picked 1\n>  }\n>  \n> +# Use object format as hash algorightm (either \"sha1\" or \"sha256\")\n> +set hashalgorithm [exec git rev-parse --show-object-format]\n\nMental note: This raises the minimal requirement to Git 2.25.0.\n\n> +if {$hashalgorithm eq \"sha1\"} {\n> +\tset hashlength 40\n> +} elseif {$hashalgorithm eq \"sha256\"} {\n> +\tset hashlength 64\n> +} else {\n> +\tputs stderr \"Unknown hash algorithm: $hashalgorithm\"\n> +\texit 1\n> +}\n> +\n>  # we expand the _gitdir when it's just a single dot (i.e. when we're being\n>  # run from the .git dir itself) lest the routines to find the worktree\n>  # get confused\n> @@ -1822,7 +1833,7 @@ proc short_path {path} {\n>  }\n>  \n>  set next_icon_id 0\n> -set null_sha1 [string repeat 0 40]\n> +set null_sha1 [string repeat 0 $hashlength]\n>  \n>  proc merge_state {path new_state {head_info {}} {index_info {}}} {\n>  \tglobal file_states next_icon_id null_sha1\n\nBTW, there is a case\n\n      if {[regexp {^[0-9a-f]{1,39}$} $head]}\n\naround line 3217 in git-gui.sh.\n\n> diff --git a/git-gui/lib/blame.tcl b/git-gui/lib/blame.tcl\n> index 8441e109be32..1f0b8ea28504 100644\n> --- a/git-gui/lib/blame.tcl\n> +++ b/git-gui/lib/blame.tcl\n> @@ -426,6 +426,7 @@ method _kill {} {\n>  \n>  method _load {jump} {\n>  \tvariable group_colors\n> +\tglobal hashlength\n>  \n>  \t_hide_tooltip $this\n>  \n> @@ -436,7 +437,7 @@ method _load {jump} {\n>  \t\t\t$i conf -state normal\n>  \t\t\t$i delete 0.0 end\n>  \t\t\tforeach g [$i tag names] {\n> -\t\t\t\tif {[regexp {^g[0-9a-f]{40}$} $g]} {\n> +\t\t\t\tif {[regexp [string map \"@@ $hashlength\" {^g[0-9a-f]{@@}$}] $g]} {\n\nGithub copilot insist that using 'string map' to replace parts of a\nregular expression is idiomatic. However, I could not find a single\nreference that it cited. Tsk, tsk, AI, what were you smoking today?\n\nThe alternatives that I tried could come up with were not any better, so\nthis is good.\n\n>  \t\t\t\t\t$i tag delete $g\n>  \t\t\t\t}\n>  \t\t\t}\n> @@ -500,6 +501,8 @@ method _load {jump} {\n>  }\n>  \n>  method _history_menu {} {\n> +\tglobal hashlength\n> +\n>  \tset m $w.backmenu\n>  \tif {[winfo exists $m]} {\n>  \t\t$m delete 0 end\n> @@ -513,7 +516,7 @@ method _history_menu {} {\n>  \t\tset c [lindex $e 0]\n>  \t\tset f [lindex $e 1]\n>  \n> -\t\tif {[regexp {^[0-9a-f]{40}$} $c]} {\n> +\t\tif {[regexp [string map \"@@ $hashlength\" {^[0-9a-f]{@@}$}] $c]} {\n>  \t\t\tset t [string range $c 0 8]...\n>  \t\t} elseif {$c eq {}} {\n>  \t\t\tset t {Working Directory}\n> @@ -627,6 +630,7 @@ method _exec_blame {cur_w cur_d options cur_s} {\n>  method _read_blame {fd cur_w cur_d} {\n>  \tupvar #0 $cur_d line_data\n>  \tvariable group_colors\n> +\tglobal hashlength\n>  \n>  \tif {$fd ne $current_fd} {\n>  \t\tcatch {close $fd}\n> @@ -635,7 +639,7 @@ method _read_blame {fd cur_w cur_d} {\n>  \n>  \t$cur_w conf -state normal\n>  \twhile {[gets $fd line] >= 0} {\n> -\t\tif {[regexp {^([a-z0-9]{40}) (\\d+) (\\d+) (\\d+)$} $line line \\\n> +\t\tif {[regexp [string map \"@@ $hashlength\" {^([a-z0-9]{@@}) (\\d+) (\\d+) (\\d+)$}] $line line \\\n>  \t\t\tcmit original_line final_line line_count]} {\n>  \t\t\tset r_commit     $cmit\n>  \t\t\tset r_orig_line  $original_line\n> @@ -648,7 +652,7 @@ method _read_blame {fd cur_w cur_d} {\n>  \t\t\tset oln  $r_orig_line\n>  \t\t\tset cmit $r_commit\n>  \n> -\t\t\tif {[regexp {^0{40}$} $cmit]} {\n> +\t\t\tif {[regexp [string map \"@@ $hashlength\" {^0{@@}$}] $cmit]} {\n\nThis is a roundabout way to say 'if {$cmit eq $nullid}'.\n\n>  \t\t\t\tset commit_abbr work\n>  \t\t\t\tset commit_type curr_commit\n>  \t\t\t} elseif {$cmit eq $commit} {\n> diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl\n> index d23abedcb36f..6078b1c7e2c4 100644\n> --- a/git-gui/lib/choose_repository.tcl\n> +++ b/git-gui/lib/choose_repository.tcl\n> @@ -870,6 +870,8 @@ method _do_clone_HEAD {ok} {\n>  }\n>  \n>  method _do_clone_full_end {ok} {\n> +\tglobal hashlength\n> +\n>  \t$o_cons done $ok\n>  \n>  \tif {$ok} {\n> @@ -879,7 +881,7 @@ method _do_clone_full_end {ok} {\n>  \t\tif {[file exists [gitdir FETCH_HEAD]]} {\n>  \t\t\tset fd [open [gitdir FETCH_HEAD] r]\n>  \t\t\twhile {[gets $fd line] >= 0} {\n> -\t\t\t\tif {[regexp \"^(.{40})\\t\\t\" $line line HEAD]} {\n> +\t\t\t\tif {[regexp [string map \"@@ $hashlength\" \"^(.{@@})\\t\\t\"] $line line HEAD]} {\n>  \t\t\t\t\tbreak\n>  \t\t\t\t}\n>  \t\t\t}\n\nThe repository picker dialog runs before $hashlength is set. Therefore,\nat the time that this function is executed, $hashlength is not available.\n\nThis procedure can depend on the file format, which is to have \\t\\t\nafter the hash regardless of its length.\n\n> @@ -965,6 +967,8 @@ method _do_clone_checkout {HEAD} {\n>  }\n>  \n>  method _readtree_wait {fd} {\n> +\tglobal hashlength\n> +\n>  \tset buf [read $fd]\n>  \t$o_status_op update_meter $buf\n>  \tappend readtree_err $buf\n> @@ -986,7 +990,7 @@ method _readtree_wait {fd} {\n>  \n>  \t# -- Run the post-checkout hook.\n>  \t#\n> -\tset fd_ph [githook_read post-checkout [string repeat 0 40] \\\n> +\tset fd_ph [githook_read post-checkout [string repeat 0 $hashlength] \\\n\nYet another case where $nullid can be used.\n\n>  \t\t[git rev-parse HEAD] 1]\n>  \tif {$fd_ph ne {}} {\n>  \t\tglobal pch_error\n> diff --git a/git-gui/lib/commit.tcl b/git-gui/lib/commit.tcl\n> index a570f9cdc6a4..7a7394a5c89c 100644\n> --- a/git-gui/lib/commit.tcl\n> +++ b/git-gui/lib/commit.tcl\n> @@ -348,6 +348,7 @@ proc commit_committree {fd_wt curHEAD msg_p} {\n>  \tglobal file_states selected_paths rescan_active\n>  \tglobal repo_config\n>  \tglobal env\n> +\tglobal hashlength\n>  \n>  \tgets $fd_wt tree_id\n>  \tif {[catch {close $fd_wt} err]} {\n> @@ -367,7 +368,7 @@ proc commit_committree {fd_wt curHEAD msg_p} {\n>  \t\tclose $fd_ot\n>  \n>  \t\tif {[string equal -length 5 {tree } $old_tree]\n> -\t\t\t&& [string length $old_tree] == 45} {\n> +\t\t\t&& [string length $old_tree] == [expr {$hashlength + 5}]} {\n\nGood find!\n\n>  \t\t\tset old_tree [string range $old_tree 5 end]\n>  \t\t} else {\n>  \t\t\terror [mc \"Commit %s appears to be corrupt\" $PARENT]\n> diff --git a/git-gui/lib/remote_branch_delete.tcl b/git-gui/lib/remote_branch_delete.tcl\n> index 5ba9fcadd17f..8ea672479306 100644\n> --- a/git-gui/lib/remote_branch_delete.tcl\n> +++ b/git-gui/lib/remote_branch_delete.tcl\n> @@ -323,6 +323,8 @@ method _load {cache uri} {\n>  }\n>  \n>  method _read {cache fd} {\n> +\tglobal hashlength\n> +\n>  \tif {$fd ne $active_ls} {\n>  \t\tcatch {close $fd}\n>  \t\treturn\n> @@ -330,7 +332,7 @@ method _read {cache fd} {\n>  \n>  \twhile {[gets $fd line] >= 0} {\n>  \t\tif {[string match {*^{}} $line]} continue\n> -\t\tif {[regexp {^([0-9a-f]{40})\t(.*)$} $line _junk obj ref]} {\n> +\t\tif {[regexp [string map \"@@ $hashlength\" {^([0-9a-f]{@@})\t(.*)$}] $line _junk obj ref]} {\n>  \t\t\tif {[regsub ^refs/heads/ $ref {} abr]} {\n>  \t\t\t\tlappend head_list $abr\n>  \t\t\t\tlappend head_cache($cache) $abr\n\n-- Hannes\n\n"},{"id":"521999","messageId":"87ecuha66p.wl-tiwai@suse.de","threadId":"63737","inReplyTo":"b78bad36-d4ae-4d91-a72a-c3446e10d34b@kdbg.org","subject":"Re: [PATCH v2] git-gui: Add support of SHA256 repo","fromName":"Takashi Iwai","fromEmail":"tiwai@suse.de","sentAt":"2025-07-15T14:18:22Z","receivedAt":"2025-07-15T14:18:24Z","isPatch":true,"sender":{"key":"tiwai@suse.de","avatar":"https://avatars.githubusercontent.com/u/306482?v=4"},"body":"On Mon, 14 Jul 2025 18:28:13 +0200,\nJohannes Sixt wrote:\n> \n> Am 03.07.25 um 14:04 schrieb Takashi Iwai:\n> > This patch adds the basic support of SHA256 Git repositories.\n> > The needed changes were mostly about adjusting the fixed ID length of\n> > SHA1 (40) to be variable depending on the repo type.\n> \n> Thank you. Being precise in the commit message would be very\n> appreciated. You say \"mostly\", which makes me wonder what the cases are\n> that fall not under \"mostly\". How about:\n> \n>    Determine the hash length on startup, then replace the hard-coded\n>    \"40\" by the variable value. Also fix <foo> to do <bar> so as to\n>    account for <baz>.\n> \n> Or make a bullet list if there is more to enumerate. Or make a\n> multi-patch series where each patch has its own topic if this is warranted.\n\nThanks for the review!\nSure, will add more descriptions in the next respin.\n\n> BTW, there is a case\n> \n>       if {[regexp {^[0-9a-f]{1,39}$} $head]}\n> \n> around line 3217 in git-gui.sh.\n\nObviously I didn't look for numbers less than 40 :)\nI'll replace it, too.\n\nBut I don't understand why it matches up to only 39, not 40 in the\ncode above.\nIt seems trying to get the proper hash id if it's no full length id?\nIf so, the check should be rather like\n\tif {![regexp {^[0-9a-f]{40}$} $head]}\n??  It makes the conversion a bit simpler.\n\n> > @@ -436,7 +437,7 @@ method _load {jump} {\n> >  \t\t\t$i conf -state normal\n> >  \t\t\t$i delete 0.0 end\n> >  \t\t\tforeach g [$i tag names] {\n> > -\t\t\t\tif {[regexp {^g[0-9a-f]{40}$} $g]} {\n> > +\t\t\t\tif {[regexp [string map \"@@ $hashlength\" {^g[0-9a-f]{@@}$}] $g]} {\n> \n> Github copilot insist that using 'string map' to replace parts of a\n> regular expression is idiomatic. However, I could not find a single\n> reference that it cited. Tsk, tsk, AI, what were you smoking today?\n> \n> The alternatives that I tried could come up with were not any better, so\n> this is good.\n\nTo be honest, my knowledge of Tcl/Tk is decades old (and only casually\nrevisiting right now), so let me know if there is a better\nexpression.\n\n> > @@ -648,7 +652,7 @@ method _read_blame {fd cur_w cur_d} {\n> >  \t\t\tset oln  $r_orig_line\n> >  \t\t\tset cmit $r_commit\n> >  \n> > -\t\t\tif {[regexp {^0{40}$} $cmit]} {\n> > +\t\t\tif {[regexp [string map \"@@ $hashlength\" {^0{@@}$}] $cmit]} {\n> \n> This is a roundabout way to say 'if {$cmit eq $nullid}'.\n\nOK, noted.\n\nWhile we're at it, I found that $null_sha1 is identical with $nullid.\nI'll prepare a cleanup patch as preliminary.\n\n> > @@ -879,7 +881,7 @@ method _do_clone_full_end {ok} {\n> >  \t\tif {[file exists [gitdir FETCH_HEAD]]} {\n> >  \t\t\tset fd [open [gitdir FETCH_HEAD] r]\n> >  \t\t\twhile {[gets $fd line] >= 0} {\n> > -\t\t\t\tif {[regexp \"^(.{40})\\t\\t\" $line line HEAD]} {\n> > +\t\t\t\tif {[regexp [string map \"@@ $hashlength\" \"^(.{@@})\\t\\t\"] $line line HEAD]} {\n> >  \t\t\t\t\tbreak\n> >  \t\t\t\t}\n> >  \t\t\t}\n> \n> The repository picker dialog runs before $hashlength is set. Therefore,\n> at the time that this function is executed, $hashlength is not available.\n> \n> This procedure can depend on the file format, which is to have \\t\\t\n> after the hash regardless of its length.\n\nOh that's bad.  I'll rewrite without the reference to $hashlength.\nI guess we can simply replace the above with a range check {40,64}.\n\n> > @@ -965,6 +967,8 @@ method _do_clone_checkout {HEAD} {\n> >  }\n> >  \n> >  method _readtree_wait {fd} {\n> > +\tglobal hashlength\n> > +\n> >  \tset buf [read $fd]\n> >  \t$o_status_op update_meter $buf\n> >  \tappend readtree_err $buf\n> > @@ -986,7 +990,7 @@ method _readtree_wait {fd} {\n> >  \n> >  \t# -- Run the post-checkout hook.\n> >  \t#\n> > -\tset fd_ph [githook_read post-checkout [string repeat 0 40] \\\n> > +\tset fd_ph [githook_read post-checkout [string repeat 0 $hashlength] \\\n> \n> Yet another case where $nullid can be used.\n\nBut it's also in repo picker code, so we don't have $nullid yet?\nI'll rewrite somehow without $hashlength reference here, too.\n(e.g. use the length of \"git-rev-parse HEAD\" output that is called\nbelow)\n\n> >  \t\t[git rev-parse HEAD] 1]\n\n\nthanks,\n\nTakashi\n"},{"id":"522036","messageId":"c543a644-8e58-4601-8a79-247cd5e124c5@kdbg.org","threadId":"63737","inReplyTo":"87ecuha66p.wl-tiwai@suse.de","subject":"Re: [PATCH v2] git-gui: Add support of SHA256 repo","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2025-07-15T19:19:38Z","receivedAt":"2025-07-15T19:19:46Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 15.07.25 um 16:18 schrieb Takashi Iwai:\n> On Mon, 14 Jul 2025 18:28:13 +0200,\n>> BTW, there is a case\n>>\n>>       if {[regexp {^[0-9a-f]{1,39}$} $head]}\n>>\n>> around line 3217 in git-gui.sh.\n> \n> Obviously I didn't look for numbers less than 40 :)\n> I'll replace it, too.\n> \n> But I don't understand why it matches up to only 39, not 40 in the\n> code above.\n> It seems trying to get the proper hash id if it's no full length id?\n> If so, the check should be rather like\n> \tif {![regexp {^[0-9a-f]{40}$} $head]}\n> ??  It makes the conversion a bit simpler.\n\nObviously, the code wants to turn abbreviated hashes to full hashes.\nThat can be skipped if it is already the full length. I haven't analyzed\nwhy this is needed or desirable.\n\n>>> @@ -879,7 +881,7 @@ method _do_clone_full_end {ok} {\n>>>  \t\tif {[file exists [gitdir FETCH_HEAD]]} {\n>>>  \t\t\tset fd [open [gitdir FETCH_HEAD] r]\n>>>  \t\t\twhile {[gets $fd line] >= 0} {\n>>> -\t\t\t\tif {[regexp \"^(.{40})\\t\\t\" $line line HEAD]} {\n>>> +\t\t\t\tif {[regexp [string map \"@@ $hashlength\" \"^(.{@@})\\t\\t\"] $line line HEAD]} {\n>>>  \t\t\t\t\tbreak\n>>>  \t\t\t\t}\n>>>  \t\t\t}\n>>\n>> The repository picker dialog runs before $hashlength is set. Therefore,\n>> at the time that this function is executed, $hashlength is not available.\n>>\n>> This procedure can depend on the file format, which is to have \\t\\t\n>> after the hash regardless of its length.\n> \n> Oh that's bad.  I'll rewrite without the reference to $hashlength.\n> I guess we can simply replace the above with a range check {40,64}.\n\nYes, let's do that.\n\nI had something like\n\n   set pos [string find \\t\\t $line]\n   if {pos > 0} {\n     set HEAD [string range $line 0 $pos]\n     break\n   }\n\nin mind.\n\n>>> @@ -986,7 +990,7 @@ method _readtree_wait {fd} {\n>>>  \n>>>  \t# -- Run the post-checkout hook.\n>>>  \t#\n>>> -\tset fd_ph [githook_read post-checkout [string repeat 0 40] \\\n>>> +\tset fd_ph [githook_read post-checkout [string repeat 0 $hashlength] \\\n>>\n>> Yet another case where $nullid can be used.\n> \n> But it's also in repo picker code, so we don't have $nullid yet?\n> I'll rewrite somehow without $hashlength reference here, too.\n> (e.g. use the length of \"git-rev-parse HEAD\" output that is called\n> below)\n> \n>>>  \t\t[git rev-parse HEAD] 1]\n\nGood call, and good idea for a fix!\n\n-- Hannes\n\n"},{"id":"522074","messageId":"87ple08upb.wl-tiwai@suse.de","threadId":"63737","inReplyTo":"c543a644-8e58-4601-8a79-247cd5e124c5@kdbg.org","subject":"Re: [PATCH v2] git-gui: Add support of SHA256 repo","fromName":"Takashi Iwai","fromEmail":"tiwai@suse.de","sentAt":"2025-07-16T07:24:00Z","receivedAt":"2025-07-16T07:24:08Z","isPatch":true,"sender":{"key":"tiwai@suse.de","avatar":"https://avatars.githubusercontent.com/u/306482?v=4"},"body":"On Tue, 15 Jul 2025 21:19:38 +0200,\nJohannes Sixt wrote:\n> \n> Am 15.07.25 um 16:18 schrieb Takashi Iwai:\n> > On Mon, 14 Jul 2025 18:28:13 +0200,\n> >> BTW, there is a case\n> >>\n> >>       if {[regexp {^[0-9a-f]{1,39}$} $head]}\n> >>\n> >> around line 3217 in git-gui.sh.\n> > \n> > Obviously I didn't look for numbers less than 40 :)\n> > I'll replace it, too.\n> > \n> > But I don't understand why it matches up to only 39, not 40 in the\n> > code above.\n> > It seems trying to get the proper hash id if it's no full length id?\n> > If so, the check should be rather like\n> > \tif {![regexp {^[0-9a-f]{40}$} $head]}\n> > ??  It makes the conversion a bit simpler.\n> \n> Obviously, the code wants to turn abbreviated hashes to full hashes.\n> That can be skipped if it is already the full length. I haven't analyzed\n> why this is needed or desirable.\n\nMaybe it wants only the abbreviated hashes and no other refs?\nI'll keep the logic in v3 patch.  If any, we can clean up later.\n\n\nthanks,\n\nTakashi\n"}]}