diff options
author | Johannes Sixt <j6t@kdbg.org> | 2025-07-22 17:37:33 +0200 |
---|---|---|
committer | Johannes Sixt <j6t@kdbg.org> | 2025-07-22 17:37:33 +0200 |
commit | 436dad00c5a717d56bf4feb8a1f5d39126579fe6 (patch) | |
tree | 078b369e413970933b4a7acf0c127b0716abc7b5 | |
parent | 594810d2a9ac754260d47c192164e8ab77695a91 (diff) | |
parent | f4b7ad5ab808ca733dbeede2c009faab0341b994 (diff) |
Merge branch 'ml/abandon-old-versions'
* ml/abandon-old-versions:
git-gui: eliminate _search_exe
git-gui: remove procs gitexec and _git_cmd
git-gui: use dashless 'git cmd' form for read/write
git-gui: default to full copy for linked worktrees
git-gui: use git-clone
git-gui: remove unused git-version
git-gui: use git_init to create new repository dir
git-gui: git-remote is always available
git-gui: git merge understands --strategy=recursive
git-gui: git-diff knows submodules and textconv
git-gui: git-blame understands -w and textconv
git-gui: git rev-parse knows show_toplevel
git-gui: use git-branch --show-current
git-gui: git-diff-index always knows submodules
git-gui: git ls-files knows --exclude-standard
git-gui: require git >= 2.36
Signed-off-by: Johannes Sixt <j6t@kdbg.org>
-rwxr-xr-x | git-gui.sh | 238 | ||||
-rw-r--r-- | lib/about.tcl | 2 | ||||
-rw-r--r-- | lib/blame.tcl | 10 | ||||
-rw-r--r-- | lib/choose_repository.tcl | 495 | ||||
-rw-r--r-- | lib/diff.tcl | 19 | ||||
-rw-r--r-- | lib/merge.tcl | 11 | ||||
-rw-r--r-- | lib/remote.tcl | 2 |
7 files changed, 92 insertions, 685 deletions
diff --git a/git-gui.sh b/git-gui.sh index 9bb16ea00b..8bb121db4f 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -79,10 +79,8 @@ proc is_Cygwin {} { if {[is_Windows]} { set _path_sep {;} - set _search_exe .exe } else { set _path_sep {:} - set _search_exe {} } if {[is_Windows]} { @@ -112,15 +110,15 @@ set env(PATH) [join $_search_path $_path_sep] if {[is_Windows]} { proc _which {what args} { - global _search_exe _search_path + global _search_path if {[lsearch -exact $args -script] >= 0} { set suffix {} - } elseif {[string match *$_search_exe [string tolower $what]]} { + } elseif {[string match *.exe [string tolower $what]]} { # The search string already has the file extension set suffix {} } else { - set suffix $_search_exe + set suffix .exe } foreach p $_search_path { @@ -363,7 +361,6 @@ set _appname {Git Gui} set _gitdir {} set _gitworktree {} set _isbare {} -set _gitexec {} set _githtmldir {} set _reponame {} set _shellpath {@@SHELL_PATH@@} @@ -428,20 +425,6 @@ proc gitdir {args} { return [eval [list file join $_gitdir] $args] } -proc gitexec {args} { - global _gitexec - if {$_gitexec eq {}} { - if {[catch {set _gitexec [git --exec-path]} err]} { - error "Git not installed?\n\n$err" - } - set _gitexec [file normalize $_gitexec] - } - if {$args eq {}} { - return $_gitexec - } - return [eval [list file join $_gitexec] $args] -} - proc githtmldir {args} { global _githtmldir if {$_githtmldir eq {}} { @@ -574,56 +557,6 @@ proc _trace_exec {cmd} { #'" fix poor old emacs font-lock mode -proc _git_cmd {name} { - global _git_cmd_path - - if {[catch {set v $_git_cmd_path($name)}]} { - switch -- $name { - version - - --version - - --exec-path { return [list $::_git $name] } - } - - set p [gitexec git-$name$::_search_exe] - if {[file exists $p]} { - set v [list $p] - } elseif {[is_Windows] && [file exists [gitexec git-$name]]} { - # Try to determine what sort of magic will make - # git-$name go and do its thing, because native - # Tcl on Windows doesn't know it. - # - set p [gitexec git-$name] - set f [safe_open_file $p r] - set s [gets $f] - close $f - - switch -glob -- [lindex $s 0] { - #!*sh { set i sh } - #!*perl { set i perl } - #!*python { set i python } - default { error "git-$name is not supported: $s" } - } - - upvar #0 _$i interp - if {![info exists interp]} { - set interp [_which $i] - } - if {$interp eq {}} { - error "git-$name requires $i (not in PATH)" - } - set v [concat [list $interp] [lrange $s 1 end] [list $p]] - } else { - # Assume it is builtin to git somehow and we - # aren't actually able to see a file for it. - # - set v [list $::_git $name] - } - set _git_cmd_path($name) $v - } - return $v -} - -# Run a shell command connected via pipes on stdout. # This is for use with textconv filters and uses sh -c "..." to allow it to # contain a command with arguments. We presume this # to be a shellscript that the configured shell (/bin/sh by default) knows @@ -679,30 +612,30 @@ proc safe_open_command {cmd {redir {}}} { } proc git_read {cmd {redir {}}} { - set cmdp [_git_cmd [lindex $cmd 0]] - set cmd [lrange $cmd 1 end] + global _git + set cmdp [concat [list $_git] $cmd] - return [safe_open_command [concat $cmdp $cmd] $redir] + return [safe_open_command $cmdp $redir] } proc git_read_nice {cmd} { + global _git set opt [list] _lappend_nice opt - set cmdp [_git_cmd [lindex $cmd 0]] - set cmd [lrange $cmd 1 end] + set cmdp [concat [list $_git] $cmd] - return [safe_open_command [concat $opt $cmdp $cmd]] + return [safe_open_command [concat $opt $cmdp]] } proc git_write {cmd} { + global _git set cmd [make_arglist_safe $cmd] - set cmdp [_git_cmd [lindex $cmd 0]] - set cmd [lrange $cmd 1 end] + set cmdp [concat [list $_git] $cmd] - _trace_exec [concat $cmdp $cmd] - return [open [concat [list | ] $cmdp $cmd] w] + _trace_exec $cmdp + return [open [concat [list | ] $cmdp] w] } proc githook_read {hook_name args} { @@ -742,27 +675,8 @@ proc sq {value} { proc load_current_branch {} { global current_branch is_detached - set fd [safe_open_file [gitdir HEAD] r] - fconfigure $fd -translation binary -encoding utf-8 - if {[gets $fd ref] < 1} { - set ref {} - } - close $fd - - set pfx {ref: refs/heads/} - set len [string length $pfx] - if {[string equal -length $len $pfx $ref]} { - # We're on a branch. It might not exist. But - # HEAD looks good enough to be a branch. - # - set current_branch [string range $ref $len end] - set is_detached 0 - } else { - # Assume this is a detached head. - # - set current_branch HEAD - set is_detached 1 - } + set current_branch [git branch --show-current] + set is_detached [expr [string length $current_branch] == 0] } auto_load tk_optionMenu @@ -981,6 +895,8 @@ if {$_git eq {}} { ## ## version check +set MIN_GIT_VERSION 2.36 + if {[catch {set _git_version [git --version]} err]} { catch {wm withdraw .} tk_messageBox \ @@ -991,9 +907,10 @@ if {[catch {set _git_version [git --version]} err]} { $err -[appname] requires Git 1.5.0 or later." +[appname] requires Git $MIN_GIT_VERSION or later." exit 1 } + if {![regsub {^git version } $_git_version {} _git_version]} { catch {wm withdraw .} tk_messageBox \ @@ -1018,85 +935,21 @@ proc get_trimmed_version {s} { set _real_git_version $_git_version set _git_version [get_trimmed_version $_git_version] -if {![regexp {^[1-9]+(\.[0-9]+)+$} $_git_version]} { - catch {wm withdraw .} - if {[tk_messageBox \ - -icon warning \ - -type yesno \ - -default no \ - -title "[appname]: warning" \ - -message [mc "Git version cannot be determined. - -%s claims it is version '%s'. +if {[catch {set vcheck [package vcompare $_git_version $MIN_GIT_VERSION]}] || + [expr $vcheck < 0] } { -%s requires at least Git 1.5.0 or later. - -Assume '%s' is version 1.5.0? -" $_git $_real_git_version [appname] $_real_git_version]] eq {yes}} { - set _git_version 1.5.0 - } else { - exit 1 - } -} -unset _real_git_version - -proc git-version {args} { - global _git_version - - switch [llength $args] { - 0 { - return $_git_version - } - - 2 { - set op [lindex $args 0] - set vr [lindex $args 1] - set cm [package vcompare $_git_version $vr] - return [expr $cm $op 0] - } - - 4 { - set type [lindex $args 0] - set name [lindex $args 1] - set parm [lindex $args 2] - set body [lindex $args 3] - - if {($type ne {proc} && $type ne {method})} { - error "Invalid arguments to git-version" - } - if {[llength $body] < 2 || [lindex $body end-1] ne {default}} { - error "Last arm of $type $name must be default" - } - - foreach {op vr cb} [lrange $body 0 end-2] { - if {[git-version $op $vr]} { - return [uplevel [list $type $name $parm $cb]] - } - } - - return [uplevel [list $type $name $parm [lindex $body end]]] - } - - default { - error "git-version >= x" - } - - } -} - -if {[git-version < 1.5]} { + set msg1 [mc "Insufficient git version, require: "] + set msg2 [mc "git returned:"] + set message "$msg1 $MIN_GIT_VERSION\n$msg2 $_real_git_version" catch {wm withdraw .} tk_messageBox \ -icon error \ -type ok \ -title [mc "git-gui: fatal error"] \ - -message "[appname] requires Git 1.5.0 or later. - -You are using [git-version]: - -[git --version]" + -message $message exit 1 } +unset _real_git_version ###################################################################### ## @@ -1261,7 +1114,7 @@ citool { # Suggest our implementation of askpass, if none is set if {![info exists env(SSH_ASKPASS)]} { - set env(SSH_ASKPASS) [gitexec git-gui--askpass] + set env(SSH_ASKPASS) [file join [git --exec-path] git-gui--askpass] } ###################################################################### @@ -1282,6 +1135,9 @@ if {[catch { load_config 1 apply_config choose_repository::pick + if {![file isdirectory $_gitdir]} { + exit 1 + } set picked 1 } @@ -1312,20 +1168,7 @@ if {![file isdirectory $_gitdir]} { load_config 0 apply_config -# v1.7.0 introduced --show-toplevel to return the canonical work-tree -if {[package vcompare $_git_version 1.7.0] >= 0} { - set _gitworktree [git rev-parse --show-toplevel] -} else { - # try to set work tree from environment, core.worktree or use - # cdup to obtain a relative path to the top of the worktree. If - # run from the top, the ./ prefix ensures normalize expands pwd. - if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} { - set _gitworktree [get_config core.worktree] - if {$_gitworktree eq ""} { - set _gitworktree [file normalize ./[git rev-parse --show-cdup]] - } - } -} +set _gitworktree [git rev-parse --show-toplevel] if {$_prefix ne {}} { if {$_gitworktree eq {}} { @@ -1551,18 +1394,7 @@ proc rescan_stage2 {fd after} { close $fd } - if {[package vcompare $::_git_version 1.6.3] >= 0} { - set ls_others [list --exclude-standard] - } else { - set ls_others [list --exclude-per-directory=.gitignore] - if {[have_info_exclude]} { - lappend ls_others "--exclude-from=[gitdir info exclude]" - } - set user_exclude [get_config core.excludesfile] - if {$user_exclude ne {} && [file readable $user_exclude]} { - lappend ls_others "--exclude-from=[file normalize $user_exclude]" - } - } + set ls_others [list --exclude-standard] set buf_rdi {} set buf_rdf {} @@ -1570,11 +1402,7 @@ proc rescan_stage2 {fd after} { set rescan_active 2 ui_status [mc "Scanning for modified files ..."] - if {[git-version >= "1.7.2"]} { - set fd_di [git_read [list diff-index --cached --ignore-submodules=dirty -z [PARENT]]] - } else { - set fd_di [git_read [list diff-index --cached -z [PARENT]]] - } + set fd_di [git_read [list diff-index --cached --ignore-submodules=dirty -z [PARENT]]] set fd_df [git_read [list diff-files -z]] fconfigure $fd_di -blocking 0 -translation binary -encoding binary diff --git a/lib/about.tcl b/lib/about.tcl index 90fda3915d..122ebfb71d 100644 --- a/lib/about.tcl +++ b/lib/about.tcl @@ -44,7 +44,7 @@ proc do_about {} { set d {} append d "git wrapper: $::_git\n" - append d "git exec dir: [gitexec]\n" + append d "git exec dir: [git --exec-path]\n" append d "git-gui lib: $oguilib" paddedlabel $w.vers -text $v diff --git a/lib/blame.tcl b/lib/blame.tcl index 15a229e8d4..9d4d1ac872 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -470,7 +470,7 @@ method _load {jump} { $w_path conf -text [escape_path $path] set do_textconv 0 - if {![is_config_false gui.textconv] && [git-version >= 1.7.2]} { + if {![is_config_false gui.textconv]} { set filter [gitattr $path diff set] set textconv [get_config [join [list diff $filter textconv] .]] if {$filter ne {set} && $textconv ne {}} { @@ -810,9 +810,7 @@ method _read_blame {fd cur_w cur_d} { # thorough copy search; insert before the threshold set original_options [linsert $original_options 0 -C] } - if {[git-version >= 1.5.3]} { - lappend original_options -w ; # ignore indentation changes - } + lappend original_options -w ; # ignore indentation changes _exec_blame $this $w_amov @amov_data \ $original_options \ @@ -860,9 +858,7 @@ method _fullcopyblame {} { set threshold [get_config gui.copyblamethreshold] set original_options [list -C -C "-C$threshold"] - if {[git-version >= 1.5.3]} { - lappend original_options -w ; # ignore indentation changes - } + lappend original_options -w ; # ignore indentation changes # Find the line range set pos @$::cursorX,$::cursorY diff --git a/lib/choose_repository.tcl b/lib/choose_repository.tcl index 3b6cac279b..7e1462a20c 100644 --- a/lib/choose_repository.tcl +++ b/lib/choose_repository.tcl @@ -10,22 +10,12 @@ field w_next ; # Next button field w_quit ; # Quit button field o_cons ; # Console object (if active) -# Status mega-widget instance during _do_clone2 (used by _copy_files and -# _link_files). Widget is destroyed before _do_clone2 calls -# _do_clone_checkout -field o_status - -# Operation displayed by status mega-widget during _do_clone_checkout => -# _readtree_wait => _postcheckout_wait => _do_clone_submodules => -# _do_validate_submodule_cloning. The status mega-widget is a different -# instance than that stored in $o_status in earlier operations. -field o_status_op - field w_types ; # List of type buttons in clone field w_recentlist ; # Listbox containing recent repositories field w_localpath ; # Entry widget bound to local_path field done 0 ; # Finished picking the repository? +field clone_ok false ; # clone succeeeded field local_path {} ; # Where this repository is locally field origin_url {} ; # Where we are cloning from field origin_name origin ; # What we shall call 'origin' @@ -322,7 +312,7 @@ method _write_local_path {args} { } method _git_init {} { - if {[catch {file mkdir $local_path} err]} { + if {[catch {git init $local_path} err]} { error_popup [strcat \ [mc "Failed to create repository %s:" $local_path] \ "\n\n$err"] @@ -336,13 +326,6 @@ method _git_init {} { return 0 } - if {[catch {git init} err]} { - error_popup [strcat \ - [mc "Failed to create repository %s:" $local_path] \ - "\n\n$err"] - return 0 - } - _append_recentrepos [pwd] set ::_gitdir .git set ::_prefix {} @@ -359,20 +342,6 @@ proc _is_git {path {outdir_var ""}} { return 1 } -proc _objdir {path} { - set objdir [file join $path .git objects] - if {[file isdirectory $objdir]} { - return $objdir - } - - set objdir [file join $path objects] - if {[file isdirectory $objdir]} { - return $objdir - } - - return {} -} - ###################################################################### ## ## Create New Repository @@ -585,6 +554,25 @@ method _update_clone {args} { method _do_clone2 {} { if {[file isdirectory $origin_url]} { set origin_url [file normalize $origin_url] + if {$clone_type eq {hardlink}} { + # cannot use hardlinks if this is a linked worktree (.gitfile or git-new-workdir) + if {[git -C $origin_url rev-parse --is-inside-work-tree] == {true}} { + set islink 0 + set dotgit [file join $origin_url .git] + if {[file isfile $dotgit]} { + set islink 1 + } else { + set objdir [file join $dotgit objects] + if {[file exists $objdir] && [file type $objdir] == {link}} { + set islink 1 + } + } + if {$islink} { + info_popup [mc "Hardlinks are unavailable. Falling back to copying."] + set clone_type full + } + } + } } if {$clone_type eq {hardlink} && ![file isdirectory $origin_url]} { @@ -596,14 +584,6 @@ method _do_clone2 {} { return } - if {$clone_type eq {hardlink} || $clone_type eq {shared}} { - set objdir [_objdir $origin_url] - if {$objdir eq {}} { - error_popup [mc "Not a Git repository: %s" [file tail $origin_url]] - return - } - } - set giturl $origin_url if {[file exists $local_path]} { @@ -611,435 +591,62 @@ method _do_clone2 {} { return } - if {![_git_init $this]} return - set local_path [pwd] - - if {[catch { - git config remote.$origin_name.url $giturl - git config remote.$origin_name.fetch +refs/heads/*:refs/remotes/$origin_name/* - } err]} { - error_popup [strcat [mc "Failed to configure origin"] "\n\n$err"] - return + set clone_options {--progress} + if {$recursive} { + append clone_options { --recurse-submodules} } destroy $w_body $w_next switch -exact -- $clone_type { - hardlink { - set o_status [status_bar::two_line $w_body] - pack $w_body -fill x -padx 10 -pady 10 - - set status_op [$o_status start \ - [mc "Counting objects"] \ - [mc "buckets"]] - update - - if {[file exists [file join $objdir info alternates]]} { - set pwd [pwd] - if {[catch { - file mkdir [gitdir objects info] - set f_in [safe_open_file [file join $objdir info alternates] r] - set f_cp [safe_open_file [gitdir objects info alternates] w] - fconfigure $f_in -translation binary -encoding binary - fconfigure $f_cp -translation binary -encoding binary - cd $objdir - while {[gets $f_in line] >= 0} { - puts $f_cp [file normalize $line] - } - close $f_in - close $f_cp - cd $pwd - } err]} { - catch {cd $pwd} - _clone_failed $this [mc "Unable to copy objects/info/alternates: %s" $err] - $status_op stop - return - } + full { + append clone_options { --no-hardlinks --no-local} } - - set tolink [list] - set buckets [glob \ - -tails \ - -nocomplain \ - -directory [file join $objdir] ??] - set bcnt [expr {[llength $buckets] + 2}] - set bcur 1 - $status_op update $bcur $bcnt - update - - file mkdir [file join .git objects pack] - foreach i [glob -tails -nocomplain \ - -directory [file join $objdir pack] *] { - lappend tolink [file join pack $i] - } - $status_op update [incr bcur] $bcnt - update - - foreach i $buckets { - file mkdir [file join .git objects $i] - foreach j [glob -tails -nocomplain \ - -directory [file join $objdir $i] *] { - lappend tolink [file join $i $j] - } - $status_op update [incr bcur] $bcnt - update - } - $status_op stop - - if {$tolink eq {}} { - info_popup [strcat \ - [mc "Nothing to clone from %s." $origin_url] \ - "\n" \ - [mc "The 'master' branch has not been initialized."] \ - ] - destroy $w_body - set done 1 - return - } - - set i [lindex $tolink 0] - if {[catch { - file link -hard \ - [file join .git objects $i] \ - [file join $objdir $i] - } err]} { - info_popup [mc "Hardlinks are unavailable. Falling back to copying."] - set i [_copy_files $this $objdir $tolink] - } else { - set i [_link_files $this $objdir [lrange $tolink 1 end]] + shared { + append clone_options { --shared} } - if {!$i} return - - destroy $w_body - - set o_status {} } - full { + + if {[catch { set o_cons [console::embed \ $w_body \ [mc "Cloning from %s" $origin_url]] pack $w_body -fill both -expand 1 -padx 10 $o_cons exec \ - [list git fetch --no-tags -k $origin_name] \ - [cb _do_clone_tags] - } - shared { - set fd [safe_open_file [gitdir objects info alternates] w] - fconfigure $fd -translation binary - puts $fd $objdir - close $fd - } - } - - if {$clone_type eq {hardlink} || $clone_type eq {shared}} { - if {![_clone_refs $this]} return - set pwd [pwd] - if {[catch { - cd $origin_url - set HEAD [git rev-parse --verify HEAD^0] - } err]} { - _clone_failed $this [mc "Not a Git repository: %s" [file tail $origin_url]] - return 0 - } - cd $pwd - _do_clone_checkout $this $HEAD - } -} - -method _copy_files {objdir tocopy} { - set status_op [$o_status start \ - [mc "Copying objects"] \ - [mc "KiB"]] - set tot 0 - set cmp 0 - foreach p $tocopy { - incr tot [file size [file join $objdir $p]] - } - foreach p $tocopy { - if {[catch { - set f_in [safe_open_file [file join $objdir $p] r] - set f_cp [safe_open_file [file join .git objects $p] w] - fconfigure $f_in -translation binary -encoding binary - fconfigure $f_cp -translation binary -encoding binary - - while {![eof $f_in]} { - incr cmp [fcopy $f_in $f_cp -size 16384] - $status_op update \ - [expr {$cmp / 1024}] \ - [expr {$tot / 1024}] - update - } - - close $f_in - close $f_cp - } err]} { - _clone_failed $this [mc "Unable to copy object: %s" $err] - $status_op stop - return 0 - } - } - $status_op stop - return 1 -} - -method _link_files {objdir tolink} { - set total [llength $tolink] - set status_op [$o_status start \ - [mc "Linking objects"] \ - [mc "objects"]] - for {set i 0} {$i < $total} {} { - set p [lindex $tolink $i] - if {[catch { - file link -hard \ - [file join .git objects $p] \ - [file join $objdir $p] - } err]} { - _clone_failed $this [mc "Unable to hardlink object: %s" $err] - $status_op stop - return 0 - } - - incr i - if {$i % 5 == 0} { - $status_op update $i $total - update - } - } - $status_op stop - return 1 -} - -method _clone_refs {} { - set pwd [pwd] - if {[catch {cd $origin_url} err]} { - error_popup [mc "Not a Git repository: %s" [file tail $origin_url]] - return 0 - } - set fd_in [git_read [list for-each-ref \ - --tcl \ - {--format=list %(refname) %(objectname) %(*objectname)}]] - cd $pwd - - set fd [safe_open_file [gitdir packed-refs] w] - fconfigure $fd -translation binary - puts $fd "# pack-refs with: peeled" - while {[gets $fd_in line] >= 0} { - set line [eval $line] - set refn [lindex $line 0] - set robj [lindex $line 1] - set tobj [lindex $line 2] - - if {[regsub ^refs/heads/ $refn \ - "refs/remotes/$origin_name/" refn]} { - puts $fd "$robj $refn" - } elseif {[string match refs/tags/* $refn]} { - puts $fd "$robj $refn" - if {$tobj ne {}} { - puts $fd "^$tobj" - } - } - } - close $fd_in - close $fd - return 1 -} - -method _do_clone_tags {ok} { - if {$ok} { - $o_cons exec \ - [list git fetch --tags -k $origin_name] \ - [cb _do_clone_HEAD] - } else { - $o_cons done $ok - _clone_failed $this [mc "Cannot fetch branches and objects. See console output for details."] + [list git clone {*}$clone_options $origin_url $local_path] \ + [cb _do_clone2_done] + } err]} { + error_popup [strcat [mc "Clone failed."] "\n" $err] + return } -} -method _do_clone_HEAD {ok} { - if {$ok} { - $o_cons exec \ - [list git fetch $origin_name HEAD] \ - [cb _do_clone_full_end] - } else { - $o_cons done $ok - _clone_failed $this [mc "Cannot fetch tags. See console output for details."] + tkwait variable @done + if {!$clone_ok} { + error_popup [mc "Clone failed."] + return } } -method _do_clone_full_end {ok} { +method _do_clone2_done {ok} { $o_cons done $ok - if {$ok} { - destroy $w_body - - set HEAD {} - if {[file exists [gitdir FETCH_HEAD]]} { - set fd [safe_open_file [gitdir FETCH_HEAD] r] - while {[gets $fd line] >= 0} { - if {[regexp "^(.{40,64})\t\t" $line line HEAD]} { - break - } - } - close $fd - } - - catch {git pack-refs} - _do_clone_checkout $this $HEAD - } else { - _clone_failed $this [mc "Cannot determine HEAD. See console output for details."] - } -} - -method _clone_failed {{why {}}} { - if {[catch {file delete -force $local_path} err]} { - set why [strcat \ - $why \ - "\n\n" \ - [mc "Unable to cleanup %s" $local_path] \ - "\n\n" \ - $err] - } - if {$why ne {}} { - update - error_popup [strcat [mc "Clone failed."] "\n" $why] - } -} - -method _do_clone_checkout {HEAD} { - if {$HEAD eq {}} { - info_popup [strcat \ - [mc "No default branch obtained."] \ - "\n" \ - [mc "The 'master' branch has not been initialized."] \ - ] - set done 1 - return - } - if {[catch { - git update-ref HEAD $HEAD^0 + if {[catch { + cd $local_path + set ::_gitdir .git + set ::_prefix {} + _append_recentrepos [pwd] } err]} { - info_popup [strcat \ - [mc "Cannot resolve %s as a commit." $HEAD^0] \ - "\n $err" \ - "\n" \ - [mc "The 'master' branch has not been initialized."] \ - ] - set done 1 - return - } - - set status [status_bar::two_line $w_body] - pack $w_body -fill x -padx 10 -pady 10 - - # We start the status operation here. - # - # This function calls _readtree_wait as a callback. - # - # _readtree_wait in turn either calls _do_clone_submodules directly, - # or calls _postcheckout_wait as a callback which then calls - # _do_clone_submodules. - # - # _do_clone_submodules calls _do_validate_submodule_cloning. - # - # _do_validate_submodule_cloning stops the status operation. - # - # There are no other calls into this chain from other code. - - set o_status_op [$status start \ - [mc "Creating working directory"] \ - [mc "files"]] - - set readtree_err {} - set fd [git_read [list read-tree \ - -m \ - -u \ - -v \ - HEAD \ - HEAD \ - ] \ - [list 2>@1]] - fconfigure $fd -blocking 0 -translation binary - fileevent $fd readable [cb _readtree_wait $fd] -} - -method _readtree_wait {fd} { - set buf [read $fd] - $o_status_op update_meter $buf - append readtree_err $buf - - fconfigure $fd -blocking 1 - if {![eof $fd]} { - fconfigure $fd -blocking 0 - return - } - - if {[catch {close $fd}]} { - set err $readtree_err - regsub {^fatal: } $err {} err - error_popup [strcat \ - [mc "Initial file checkout failed."] \ - "\n\n$err"] - return - } - - # -- Run the post-checkout hook. - # - set head_id [git rev-parse HEAD] - set fd_ph [githook_read post-checkout \ - [string repeat 0 [string length $head_id]] $head_id 1] - if {$fd_ph ne {}} { - global pch_error - set pch_error {} - fconfigure $fd_ph -blocking 0 -translation binary -eofchar {} - fileevent $fd_ph readable [cb _postcheckout_wait $fd_ph] - } else { - _do_clone_submodules $this - } -} - -method _postcheckout_wait {fd_ph} { - global pch_error - - append pch_error [read $fd_ph] - fconfigure $fd_ph -blocking 1 - if {[eof $fd_ph]} { - if {[catch {close $fd_ph}]} { - hook_failed_popup post-checkout $pch_error 0 + set ok 0 } - unset pch_error - _do_clone_submodules $this - return } - fconfigure $fd_ph -blocking 0 -} - -method _do_clone_submodules {} { - if {$recursive eq {true}} { - $o_status_op stop - set o_status_op {} - - destroy $w_body - - set o_cons [console::embed \ - $w_body \ - [mc "Cloning submodules"]] - pack $w_body -fill both -expand 1 -padx 10 - $o_cons exec \ - [list git submodule update --init --recursive] \ - [cb _do_validate_submodule_cloning] - } else { - set done 1 + if {!$ok} { + set ::_gitdir {} + set ::_prefix {} } + set clone_ok $ok + set done 1 } -method _do_validate_submodule_cloning {ok} { - if {$ok} { - $o_cons done $ok - set done 1 - } else { - _clone_failed $this [mc "Cannot clone submodules."] - } -} ###################################################################### ## diff --git a/lib/diff.tcl b/lib/diff.tcl index 9df555c505..1acd37bdb4 100644 --- a/lib/diff.tcl +++ b/lib/diff.tcl @@ -278,9 +278,7 @@ proc start_show_diff {cont_info {add_opts {}}} { if {$w eq $ui_index} { lappend cmd diff-index lappend cmd --cached - if {[git-version >= "1.7.2"]} { - lappend cmd --ignore-submodules=dirty - } + lappend cmd --ignore-submodules=dirty } elseif {$w eq $ui_workdir} { if {[string first {U} $m] >= 0} { lappend cmd diff @@ -288,17 +286,14 @@ proc start_show_diff {cont_info {add_opts {}}} { lappend cmd diff-files } } - if {![is_config_false gui.textconv] && [git-version >= 1.6.1]} { + if {![is_config_false gui.textconv]} { lappend cmd --textconv } if {[string match {160000 *} [lindex $s 2]] || [string match {160000 *} [lindex $s 3]]} { set is_submodule_diff 1 - - if {[git-version >= "1.6.6"]} { - lappend cmd --submodule - } + lappend cmd --submodule } lappend cmd -p @@ -317,14 +312,6 @@ proc start_show_diff {cont_info {add_opts {}}} { lappend cmd $path } - if {$is_submodule_diff && [git-version < "1.6.6"]} { - if {$w eq $ui_index} { - set cmd [list submodule summary --cached -- $path] - } else { - set cmd [list submodule summary --files -- $path] - } - } - if {[catch {set fd [git_read_nice $cmd]} err]} { set diff_active 0 unlock_index diff --git a/lib/merge.tcl b/lib/merge.tcl index 61524ec9ca..3490beddae 100644 --- a/lib/merge.tcl +++ b/lib/merge.tcl @@ -112,16 +112,7 @@ method _start {} { close $fh set _last_merged_branch $branch - if {[git-version >= "2.5.0"]} { - set cmd [list git merge --strategy=recursive FETCH_HEAD] - } else { - set cmd [list git] - lappend cmd merge - lappend cmd --strategy=recursive - lappend cmd [git_redir [list fmt-merge-msg] [list <[gitdir FETCH_HEAD]]] - lappend cmd HEAD - lappend cmd $name - } + set cmd [list git merge --strategy=recursive FETCH_HEAD] ui_status [mc "Merging %s and %s..." $current_branch $stitle] set cons [console::new [mc "Merge"] "merge $stitle"] diff --git a/lib/remote.tcl b/lib/remote.tcl index cf796d1601..9b49b6e462 100644 --- a/lib/remote.tcl +++ b/lib/remote.tcl @@ -233,8 +233,6 @@ proc make_sure_remote_submenues_exist {remote_m} { proc update_all_remotes_menu_entry {} { global all_remotes - if {[git-version < 1.6.6]} { return } - set have_remote 0 foreach r $all_remotes { incr have_remote |