merge(3p/git): Merge git subtree at v2.29.2

This also bumps the stable nixpkgs to 20.09 as of 2020-11-21, because
there is some breakage in the git build related to the netrc
credentials helper which someone has taken care of in nixpkgs.

The stable channel is not used for anything other than git, so this
should be fine.

Change-Id: I3575a19dab09e1e9556cf8231d717de9890484fb
This commit is contained in:
Vincent Ambo 2020-11-21 19:20:35 +01:00
parent 082c006c04
commit f4609b896f
1485 changed files with 241535 additions and 109418 deletions

174
third_party/git/git-gui/README.md vendored Normal file
View file

@ -0,0 +1,174 @@
# Git GUI - A graphical user interface for Git
Git GUI allows you to use the [Git source control management
tools](https://git-scm.com/) via a GUI. This includes staging, committing,
adding, pushing, etc. It can also be used as a blame viewer, a tree browser,
and a citool (make exactly one commit before exiting and returning to shell).
More details about Git GUI can be found in its manual page by either running
`man git-gui`, or by visiting the [online manual
page](https://git-scm.com/docs/git-gui).
Git GUI was initially written by Shawn O. Pearce, and is distributed with the
standard Git installation.
# Building and installing
You need to have the following dependencies installed before you begin:
- Git
- Tcl
- Tk
- wish
- Gitk (needed for browsing history)
- msgfmt
Most of Git GUI is written in Tcl, so there is no compilation involved. Still,
some things do need to be done (mostly some substitutions), so you do need to
"build" it.
You can build Git GUI using:
```
make
```
And then install it using:
```
make install
```
You probably need to have root/admin permissions to install.
# Contributing
The project is currently maintained by Pratyush Yadav over at
https://github.com/prati0100/git-gui. Even though the project is hosted at
GitHub, the development does not happen over GitHub Issues and Pull Requests.
Instead, an email based workflow is used. The Git mailing list
[git@vger.kernel.org](mailto:git@vger.kernel.org) is where the patches are
discussed and reviewed.
More information about the Git mailing list and instructions to subscribe can
be found [here](https://git.wiki.kernel.org/index.php/GitCommunity).
## Sending your changes
Since the development happens over email, you need to send in your commits in
text format. Commits can be converted to emails via the two tools provided by
Git: `git-send-email` and `git-format-patch`.
You can use `git-format-patch` to generate patches in mbox format from your
commits that can then be sent via email. Let's say you are working on a branch
called 'foo' that was created on top of 'master'. You can run:
```
git format-patch -o output_dir master..foo
```
to convert all the extra commits in 'foo' into a set of patches saved in the
folder `output_dir`.
If you are sending multiple patches, it is recommended to include a cover
letter. A cover letter is an email explaining in brief what the series is
supposed to do. A cover letter template can be generated by passing
`--cover-letter` to `git-format-patch`.
After you send your patches, you might get a review suggesting some changes.
Make those changes, and re-send your patch(es) in reply to the first patch of
your initial version. Also please mention the version of the patch. This can be
done by passing `-v X` to `git-format-patch`, where 'X' is the version number
of the patch(es).
### Using git-send-email
You can use `git-send-email` to send patches generated via `git-format-patch`.
While you can directly send patches via `git-send-email`, it is recommended
that you first use `git-format-patch` to generate the emails, audit them, and
then send them via `git-send-email`.
A pretty good guide to configuring and using `git-send-email` can be found
[here](https://www.freedesktop.org/wiki/Software/PulseAudio/HowToUseGitSendEmail/)
### Using your email client
If your email client supports sending mbox format emails, you can use
`git-format-patch` to get an mbox file for each commit, and then send them. If
there is more than one patch in the series, then all patches after the first
patch (or the cover letter) need to be sent as replies to the first.
`git-send-email` does this by default.
### Using GitGitGadget
Since some people prefer a GitHub pull request based workflow, they can use
[GitGitGadget](https://gitgitgadget.github.io/) to send in patches. The tool
was originally written for sending patches to the Git project, but it now also
supports sending patches for git-gui.
Instructions for using GitGitGadget to send git-gui patches, courtesy of
Johannes Schindelin:
If you don't already have a fork of the [git/git](https://github.com/git/git)
repo, you need to make one. Then clone your fork:
```
git clone https://github.com/<your-username>/git
```
Then add GitGitGadget as a remote:
```
git remote add gitgitgadget https://github.com/gitgitgadget/git
```
Then fetch the git-gui branch:
```
git fetch gitgitgadget git-gui/master
```
Then create a new branch based on git-gui/master:
```
git checkout -b <your-branch-name> git-gui/master
```
Make whatever commits you need to, push them to your fork, and then head over
to https://github.com/gitgitgadget/git/pulls and open a Pull Request targeting
git-gui/master.
GitGitGadget will welcome you with a (hopefully) helpful message.
## Signing off
You need to sign off your commits before sending them to the list. You can do
that by passing the `-s` option to `git-commit`. You can also use the "Sign
Off" option in Git GUI.
A sign-off is a simple 'Signed-off-by: A U Thor \<author@example.com\>' line at
the end of the commit message, after your explanation of the commit.
A sign-off means that you are legally allowed to send the code, and it serves
as a certificate of origin. More information can be found at
[developercertificate.org](https://developercertificate.org/).
## Responding to review comments
It is quite likely your patches will get review comments. Those comments are
sent on the Git mailing list as replies to your patch, and you will usually be
Cc'ed in those replies.
You are expected to respond by either explaining your code further to convince
the reviewer what you are doing is correct, or acknowledge the comments and
re-send the patches with those comments addressed.
Some tips for those not familiar with communication on a mailing list:
- Use only plain text emails. No HTML at all.
- Wrap lines at around 75 characters.
- Do not send attachments. If you do need to send some files, consider using a
hosting service, and paste the link in your email.
- Do not [top post](http://www.idallen.com/topposting.html).
- Always "reply all". Keep all correspondents and the list in Cc. If you reply
directly to a reviewer, and not Cc the list, other people would not be able
to chime in.

View file

@ -56,6 +56,11 @@ proc finish {} {
}
}
# On Windows, force the encoding to UTF-8: it is what `git.exe` expects
if {$::tcl_platform(platform) eq {windows}} {
set ::answer [encoding convertto utf-8 $::answer]
}
puts $::answer
set ::rc 0
}

View file

@ -30,8 +30,8 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.}]
##
## Tcl/Tk sanity check
if {[catch {package require Tcl 8.4} err]
|| [catch {package require Tk 8.4} err]
if {[catch {package require Tcl 8.5} err]
|| [catch {package require Tk 8.5} err]
} {
catch {wm withdraw .}
tk_messageBox \
@ -684,6 +684,7 @@ proc load_current_branch {} {
global current_branch is_detached
set fd [open [gitdir HEAD] r]
fconfigure $fd -translation binary -encoding utf-8
if {[gets $fd ref] < 1} {
set ref {}
}
@ -719,7 +720,9 @@ proc rmsel_tag {text} {
-background [$text cget -background] \
-foreground [$text cget -foreground] \
-borderwidth 0
$text tag conf in_sel -background lightgray
$text tag conf in_sel\
-background $color::select_bg \
-foreground $color::select_fg
bind $text <Motion> break
return $text
}
@ -862,6 +865,7 @@ proc apply_config {} {
set NS ttk
bind [winfo class .] <<ThemeChanged>> [list InitTheme]
pave_toplevel .
color::sync_with_theme
}
}
}
@ -946,15 +950,15 @@ if {![regsub {^git version } $_git_version {} _git_version]} {
}
proc get_trimmed_version {s} {
set r {}
foreach x [split $s -._] {
if {[string is integer -strict $x]} {
lappend r $x
} else {
break
}
}
return [join $r .]
set r {}
foreach x [split $s -._] {
if {[string is integer -strict $x]} {
lappend r $x
} else {
break
}
}
return [join $r .]
}
set _real_git_version $_git_version
set _git_version [get_trimmed_version $_git_version]
@ -966,7 +970,7 @@ if {![regexp {^[1-9]+(\.[0-9]+)+$} $_git_version]} {
-type yesno \
-default no \
-title "[appname]: warning" \
-message [mc "Git version cannot be determined.
-message [mc "Git version cannot be determined.
%s claims it is version '%s'.
@ -1340,6 +1344,7 @@ set HEAD {}
set PARENT {}
set MERGE_HEAD [list]
set commit_type {}
set commit_type_is_amend 0
set empty_tree {}
set current_branch {}
set is_detached 0
@ -1347,8 +1352,9 @@ set current_diff_path {}
set is_3way_diff 0
set is_submodule_diff 0
set is_conflict_diff 0
set selected_commit_type new
set diff_empty_count 0
set last_revert {}
set last_revert_enc {}
set nullid "0000000000000000000000000000000000000000"
set nullid2 "0000000000000000000000000000000000000001"
@ -1434,7 +1440,7 @@ proc PARENT {} {
}
proc force_amend {} {
global selected_commit_type
global commit_type_is_amend
global HEAD PARENT MERGE_HEAD commit_type
repository_state newType newHEAD newMERGE_HEAD
@ -1443,7 +1449,7 @@ proc force_amend {} {
set MERGE_HEAD $newMERGE_HEAD
set commit_type $newType
set selected_commit_type amend
set commit_type_is_amend 1
do_select_commit_type
}
@ -1650,7 +1656,7 @@ proc prepare_commit_msg_hook_wait {fd_ph} {
set pch_error {}
catch {file delete [gitdir PREPARE_COMMIT_MSG]}
return
}
}
fconfigure $fd_ph -blocking 0
catch {file delete [gitdir PREPARE_COMMIT_MSG]}
}
@ -1795,10 +1801,10 @@ proc ui_status {msg} {
}
}
proc ui_ready {{test {}}} {
proc ui_ready {} {
global main_status
if {[info exists main_status]} {
$main_status show [mc "Ready."] $test
$main_status show [mc "Ready."]
}
}
@ -1998,72 +2004,72 @@ set filemask {
#define mask_width 14
#define mask_height 15
static unsigned char mask_bits[] = {
0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f,
0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f,
0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f};
0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f,
0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f,
0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f};
}
image create bitmap file_plain -background white -foreground black -data {
#define plain_width 14
#define plain_height 15
static unsigned char plain_bits[] = {
0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10,
0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10,
0x02, 0x10, 0x02, 0x10, 0xfe, 0x1f};
0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10,
0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10,
0x02, 0x10, 0x02, 0x10, 0xfe, 0x1f};
} -maskdata $filemask
image create bitmap file_mod -background white -foreground blue -data {
#define mod_width 14
#define mod_height 15
static unsigned char mod_bits[] = {
0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10,
0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10,
0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f};
0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10,
0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10,
0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f};
} -maskdata $filemask
image create bitmap file_fulltick -background white -foreground "#007000" -data {
#define file_fulltick_width 14
#define file_fulltick_height 15
static unsigned char file_fulltick_bits[] = {
0xfe, 0x01, 0x02, 0x1a, 0x02, 0x0c, 0x02, 0x0c, 0x02, 0x16, 0x02, 0x16,
0x02, 0x13, 0x00, 0x13, 0x86, 0x11, 0x8c, 0x11, 0xd8, 0x10, 0xf2, 0x10,
0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f};
0xfe, 0x01, 0x02, 0x1a, 0x02, 0x0c, 0x02, 0x0c, 0x02, 0x16, 0x02, 0x16,
0x02, 0x13, 0x00, 0x13, 0x86, 0x11, 0x8c, 0x11, 0xd8, 0x10, 0xf2, 0x10,
0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f};
} -maskdata $filemask
image create bitmap file_question -background white -foreground black -data {
#define file_question_width 14
#define file_question_height 15
static unsigned char file_question_bits[] = {
0xfe, 0x01, 0x02, 0x02, 0xe2, 0x04, 0xf2, 0x09, 0x1a, 0x1b, 0x0a, 0x13,
0x82, 0x11, 0xc2, 0x10, 0x62, 0x10, 0x62, 0x10, 0x02, 0x10, 0x62, 0x10,
0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f};
0xfe, 0x01, 0x02, 0x02, 0xe2, 0x04, 0xf2, 0x09, 0x1a, 0x1b, 0x0a, 0x13,
0x82, 0x11, 0xc2, 0x10, 0x62, 0x10, 0x62, 0x10, 0x02, 0x10, 0x62, 0x10,
0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f};
} -maskdata $filemask
image create bitmap file_removed -background white -foreground red -data {
#define file_removed_width 14
#define file_removed_height 15
static unsigned char file_removed_bits[] = {
0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10,
0x1a, 0x16, 0x32, 0x13, 0xe2, 0x11, 0xc2, 0x10, 0xe2, 0x11, 0x32, 0x13,
0x1a, 0x16, 0x02, 0x10, 0xfe, 0x1f};
0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10,
0x1a, 0x16, 0x32, 0x13, 0xe2, 0x11, 0xc2, 0x10, 0xe2, 0x11, 0x32, 0x13,
0x1a, 0x16, 0x02, 0x10, 0xfe, 0x1f};
} -maskdata $filemask
image create bitmap file_merge -background white -foreground blue -data {
#define file_merge_width 14
#define file_merge_height 15
static unsigned char file_merge_bits[] = {
0xfe, 0x01, 0x02, 0x03, 0x62, 0x05, 0x62, 0x09, 0x62, 0x1f, 0x62, 0x10,
0xfa, 0x11, 0xf2, 0x10, 0x62, 0x10, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10,
0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f};
0xfe, 0x01, 0x02, 0x03, 0x62, 0x05, 0x62, 0x09, 0x62, 0x1f, 0x62, 0x10,
0xfa, 0x11, 0xf2, 0x10, 0x62, 0x10, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10,
0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f};
} -maskdata $filemask
image create bitmap file_statechange -background white -foreground green -data {
#define file_statechange_width 14
#define file_statechange_height 15
static unsigned char file_statechange_bits[] = {
0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x62, 0x10,
0x62, 0x10, 0xba, 0x11, 0xba, 0x11, 0x62, 0x10, 0x62, 0x10, 0x02, 0x10,
0x02, 0x10, 0x02, 0x10, 0xfe, 0x1f};
0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x62, 0x10,
0x62, 0x10, 0xba, 0x11, 0xba, 0x11, 0x62, 0x10, 0x62, 0x10, 0x02, 0x10,
0x02, 0x10, 0x02, 0x10, 0xfe, 0x1f};
} -maskdata $filemask
set ui_index .vpane.files.index.list
@ -2148,8 +2154,6 @@ proc incr_font_size {font {amt 1}} {
##
## ui commands
set starting_gitk_msg [mc "Starting gitk... please wait..."]
proc do_gitk {revs {is_submodule false}} {
global current_diff_path file_states current_diff_side ui_index
global _gitdir _gitworktree
@ -2204,9 +2208,12 @@ proc do_gitk {revs {is_submodule false}} {
set env(GIT_WORK_TREE) $_gitworktree
cd $pwd
ui_status $::starting_gitk_msg
after 10000 {
ui_ready $starting_gitk_msg
if {[info exists main_status]} {
set status_operation [$::main_status \
start \
[mc "Starting %s... please wait..." "gitk"]]
after 3500 [list $status_operation stop]
}
}
}
@ -2238,16 +2245,16 @@ proc do_git_gui {} {
set env(GIT_WORK_TREE) $_gitworktree
cd $pwd
ui_status $::starting_gitk_msg
after 10000 {
ui_ready $starting_gitk_msg
}
set status_operation [$::main_status \
start \
[mc "Starting %s... please wait..." "git-gui"]]
after 3500 [list $status_operation stop]
}
}
proc do_explore {} {
global _gitworktree
set explorer {}
# Get the system-specific explorer app/command.
proc get_explorer {} {
if {[is_Cygwin] || [is_Windows]} {
set explorer "explorer.exe"
} elseif {[is_MacOSX]} {
@ -2256,9 +2263,23 @@ proc do_explore {} {
# freedesktop.org-conforming system is our best shot
set explorer "xdg-open"
}
return $explorer
}
proc do_explore {} {
global _gitworktree
set explorer [get_explorer]
eval exec $explorer [list [file nativename $_gitworktree]] &
}
# Open file relative to the working tree by the default associated app.
proc do_file_open {file} {
global _gitworktree
set explorer [get_explorer]
set full_file_path [file join $_gitworktree $file]
exec $explorer [file nativename $full_file_path] &
}
set is_quitting 0
set ret_code 1
@ -2494,7 +2515,7 @@ proc force_first_diff {after} {
proc toggle_or_diff {mode w args} {
global file_states file_lists current_diff_path ui_index ui_workdir
global last_clicked selected_paths
global last_clicked selected_paths file_lists_last_clicked
if {$mode eq "click"} {
foreach {x y} $args break
@ -2551,6 +2572,8 @@ proc toggle_or_diff {mode w args} {
$ui_index tag remove in_sel 0.0 end
$ui_workdir tag remove in_sel 0.0 end
set file_lists_last_clicked($w) $path
# Determine the state of the file
if {[info exists file_states($path)]} {
set state [lindex $file_states($path) 0]
@ -2580,12 +2603,12 @@ proc toggle_or_diff {mode w args} {
update_indexinfo \
"Unstaging [short_path $path] from commit" \
[list $path] \
[concat $after [list ui_ready]]
[concat $after {ui_ready;}]
} elseif {$w eq $ui_workdir} {
update_index \
"Adding [short_path $path]" \
[list $path] \
[concat $after [list ui_ready]]
[concat $after {ui_ready;}]
}
} else {
set selected_paths($path) 1
@ -2664,6 +2687,32 @@ proc show_less_context {} {
}
}
proc focus_widget {widget} {
global file_lists last_clicked selected_paths
global file_lists_last_clicked
if {[llength $file_lists($widget)] > 0} {
set path $file_lists_last_clicked($widget)
set index [lsearch -sorted -exact $file_lists($widget) $path]
if {$index < 0} {
set index 0
set path [lindex $file_lists($widget) $index]
}
focus $widget
set last_clicked [list $widget [expr $index + 1]]
array unset selected_paths
set selected_paths($path) 1
show_diff $path $widget
}
}
proc toggle_commit_type {} {
global commit_type_is_amend
set commit_type_is_amend [expr !$commit_type_is_amend]
do_select_commit_type
}
######################################################################
##
## ui construction
@ -2706,10 +2755,18 @@ if {![is_bare]} {
}
if {[is_Windows]} {
# Use /git-bash.exe if available
set normalized [file normalize $::argv0]
regsub "/mingw../libexec/git-core/git-gui$" \
$normalized "/git-bash.exe" cmdLine
if {$cmdLine != $normalized && [file exists $cmdLine]} {
set cmdLine [list "Git Bash" $cmdLine &]
} else {
set cmdLine [list "Git Bash" bash --login -l &]
}
.mbar.repository add command \
-label [mc "Git Bash"] \
-command {eval exec [auto_execok start] \
[list "Git Bash" bash --login -l &]}
-command {eval exec [auto_execok start] $cmdLine}
}
if {[is_Windows] || ![is_bare]} {
@ -2852,19 +2909,11 @@ if {[is_enabled multicommit] || [is_enabled singlecommit]} {
menu .mbar.commit
if {![is_enabled nocommit]} {
.mbar.commit add radiobutton \
-label [mc "New Commit"] \
-command do_select_commit_type \
-variable selected_commit_type \
-value new
lappend disable_on_lock \
[list .mbar.commit entryconf [.mbar.commit index last] -state]
.mbar.commit add radiobutton \
.mbar.commit add checkbutton \
-label [mc "Amend Last Commit"] \
-command do_select_commit_type \
-variable selected_commit_type \
-value amend
-accelerator $M1T-E \
-variable commit_type_is_amend \
-command do_select_commit_type
lappend disable_on_lock \
[list .mbar.commit entryconf [.mbar.commit index last] -state]
@ -3030,8 +3079,23 @@ unset doc_path doc_url
wm protocol . WM_DELETE_WINDOW do_quit
bind all <$M1B-Key-q> do_quit
bind all <$M1B-Key-Q> do_quit
bind all <$M1B-Key-w> {destroy [winfo toplevel %W]}
bind all <$M1B-Key-W> {destroy [winfo toplevel %W]}
set m1b_w_script {
set toplvl_win [winfo toplevel %W]
# If we are destroying the main window, we should call do_quit to take
# care of cleanup before exiting the program.
if {$toplvl_win eq "."} {
do_quit
} else {
destroy $toplvl_win
}
}
bind all <$M1B-Key-w> $m1b_w_script
bind all <$M1B-Key-W> $m1b_w_script
unset m1b_w_script
set subcommand_args {}
proc usage {} {
@ -3211,7 +3275,7 @@ pack .vpane -anchor n -side top -fill both -expand 1
textframe .vpane.files.workdir -height 100 -width 200
tlabel .vpane.files.workdir.title -text [mc "Unstaged Changes"] \
-background lightsalmon -foreground black
ttext $ui_workdir -background white -foreground black \
ttext $ui_workdir \
-borderwidth 0 \
-width 20 -height 10 \
-wrap none \
@ -3233,7 +3297,7 @@ textframe .vpane.files.index -height 100 -width 200
tlabel .vpane.files.index.title \
-text [mc "Staged Changes (Will Commit)"] \
-background lightgreen -foreground black
ttext $ui_index -background white -foreground black \
ttext $ui_index \
-borderwidth 0 \
-width 20 -height 10 \
-wrap none \
@ -3260,7 +3324,9 @@ if {!$use_ttk} {
foreach i [list $ui_index $ui_workdir] {
rmsel_tag $i
$i tag conf in_diff -background [$i tag cget in_sel -background]
$i tag conf in_diff \
-background $color::select_bg \
-foreground $color::select_fg
}
unset i
@ -3337,18 +3403,10 @@ set ui_comm .vpane.lower.commarea.buffer.frame.t
set ui_coml .vpane.lower.commarea.buffer.header.l
if {![is_enabled nocommit]} {
${NS}::radiobutton .vpane.lower.commarea.buffer.header.new \
-text [mc "New Commit"] \
-command do_select_commit_type \
-variable selected_commit_type \
-value new
lappend disable_on_lock \
[list .vpane.lower.commarea.buffer.header.new conf -state]
${NS}::radiobutton .vpane.lower.commarea.buffer.header.amend \
${NS}::checkbutton .vpane.lower.commarea.buffer.header.amend \
-text [mc "Amend Last Commit"] \
-command do_select_commit_type \
-variable selected_commit_type \
-value amend
-variable commit_type_is_amend \
-command do_select_commit_type
lappend disable_on_lock \
[list .vpane.lower.commarea.buffer.header.amend conf -state]
}
@ -3373,11 +3431,10 @@ pack $ui_coml -side left -fill x
if {![is_enabled nocommit]} {
pack .vpane.lower.commarea.buffer.header.amend -side right
pack .vpane.lower.commarea.buffer.header.new -side right
}
textframe .vpane.lower.commarea.buffer.frame
ttext $ui_comm -background white -foreground black \
ttext $ui_comm \
-borderwidth 1 \
-undo true \
-maxundo 20 \
@ -3387,10 +3444,16 @@ ttext $ui_comm -background white -foreground black \
-relief sunken \
-width $repo_config(gui.commitmsgwidth) -height 9 -wrap none \
-font font_diff \
-xscrollcommand {.vpane.lower.commarea.buffer.frame.sbx set} \
-yscrollcommand {.vpane.lower.commarea.buffer.frame.sby set}
${NS}::scrollbar .vpane.lower.commarea.buffer.frame.sbx \
-orient horizontal \
-command [list $ui_comm xview]
${NS}::scrollbar .vpane.lower.commarea.buffer.frame.sby \
-orient vertical \
-command [list $ui_comm yview]
pack .vpane.lower.commarea.buffer.frame.sbx -side bottom -fill x
pack .vpane.lower.commarea.buffer.frame.sby -side right -fill y
pack $ui_comm -side left -fill y
pack .vpane.lower.commarea.buffer.header -side top -fill x
@ -3470,9 +3533,11 @@ tlabel .vpane.lower.diff.header.file \
-justify left
tlabel .vpane.lower.diff.header.path \
-background gold \
-foreground black \
-foreground blue \
-anchor w \
-justify left
-justify left \
-font [eval font create [font configure font_ui] -underline 1] \
-cursor hand2
pack .vpane.lower.diff.header.status -side left
pack .vpane.lower.diff.header.file -side left
pack .vpane.lower.diff.header.path -fill x
@ -3487,14 +3552,18 @@ $ctxm add command \
-type STRING \
-- $current_diff_path
}
$ctxm add command \
-label [mc Open] \
-command {do_file_open $current_diff_path}
lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
bind_button3 .vpane.lower.diff.header.path "tk_popup $ctxm %X %Y"
bind .vpane.lower.diff.header.path <Button-1> {do_file_open $current_diff_path}
# -- Diff Body
#
textframe .vpane.lower.diff.body
set ui_diff .vpane.lower.diff.body.t
ttext $ui_diff -background white -foreground black \
ttext $ui_diff \
-borderwidth 0 \
-width 80 -height 5 -wrap none \
-font font_diff \
@ -3547,6 +3616,9 @@ $ui_diff tag conf d_s- \
$ui_diff tag conf d< \
-foreground orange \
-font font_diffbold
$ui_diff tag conf d| \
-foreground orange \
-font font_diffbold
$ui_diff tag conf d= \
-foreground orange \
-font font_diffbold
@ -3606,15 +3678,31 @@ set ctxm .vpane.lower.diff.body.ctxm
menu $ctxm -tearoff 0
$ctxm add command \
-label [mc "Apply/Reverse Hunk"] \
-command {apply_hunk $cursorX $cursorY}
-command {apply_or_revert_hunk $cursorX $cursorY 0}
set ui_diff_applyhunk [$ctxm index last]
lappend diff_actions [list $ctxm entryconf $ui_diff_applyhunk -state]
$ctxm add command \
-label [mc "Apply/Reverse Line"] \
-command {apply_range_or_line $cursorX $cursorY; do_rescan}
-command {apply_or_revert_range_or_line $cursorX $cursorY 0; do_rescan}
set ui_diff_applyline [$ctxm index last]
lappend diff_actions [list $ctxm entryconf $ui_diff_applyline -state]
$ctxm add separator
$ctxm add command \
-label [mc "Revert Hunk"] \
-command {apply_or_revert_hunk $cursorX $cursorY 1}
set ui_diff_reverthunk [$ctxm index last]
lappend diff_actions [list $ctxm entryconf $ui_diff_reverthunk -state]
$ctxm add command \
-label [mc "Revert Line"] \
-command {apply_or_revert_range_or_line $cursorX $cursorY 1; do_rescan}
set ui_diff_revertline [$ctxm index last]
lappend diff_actions [list $ctxm entryconf $ui_diff_revertline -state]
$ctxm add command \
-label [mc "Undo Last Revert"] \
-command {undo_last_revert; do_rescan}
set ui_diff_undorevert [$ctxm index last]
lappend diff_actions [list $ctxm entryconf $ui_diff_undorevert -state]
$ctxm add separator
$ctxm add command \
-label [mc "Show Less Context"] \
-command show_less_context
@ -3693,7 +3781,7 @@ proc has_textconv {path} {
}
proc popup_diff_menu {ctxm ctxmmg ctxmsm x y X Y} {
global current_diff_path file_states
global current_diff_path file_states last_revert
set ::cursorX $x
set ::cursorY $y
if {[info exists file_states($current_diff_path)]} {
@ -3707,19 +3795,28 @@ proc popup_diff_menu {ctxm ctxmmg ctxmsm x y X Y} {
tk_popup $ctxmsm $X $Y
} else {
set has_range [expr {[$::ui_diff tag nextrange sel 0.0] != {}}]
set u [mc "Undo Last Revert"]
if {$::ui_index eq $::current_diff_side} {
set l [mc "Unstage Hunk From Commit"]
set h [mc "Revert Hunk"]
if {$has_range} {
set t [mc "Unstage Lines From Commit"]
set r [mc "Revert Lines"]
} else {
set t [mc "Unstage Line From Commit"]
set r [mc "Revert Line"]
}
} else {
set l [mc "Stage Hunk For Commit"]
set h [mc "Revert Hunk"]
if {$has_range} {
set t [mc "Stage Lines For Commit"]
set r [mc "Revert Lines"]
} else {
set t [mc "Stage Line For Commit"]
set r [mc "Revert Line"]
}
}
if {$::is_3way_diff
@ -3730,11 +3827,35 @@ proc popup_diff_menu {ctxm ctxmmg ctxmsm x y X Y} {
|| [string match {T?} $state]
|| [has_textconv $current_diff_path]} {
set s disabled
set revert_state disabled
} else {
set s normal
# Only allow reverting changes in the working tree. If
# the user wants to revert changes in the index, they
# need to unstage those first.
if {$::ui_workdir eq $::current_diff_side} {
set revert_state normal
} else {
set revert_state disabled
}
}
if {$last_revert eq {}} {
set undo_state disabled
} else {
set undo_state normal
}
$ctxm entryconf $::ui_diff_applyhunk -state $s -label $l
$ctxm entryconf $::ui_diff_applyline -state $s -label $t
$ctxm entryconf $::ui_diff_revertline -state $revert_state \
-label $r
$ctxm entryconf $::ui_diff_reverthunk -state $revert_state \
-label $h
$ctxm entryconf $::ui_diff_undorevert -state $undo_state \
-label $u
tk_popup $ctxm $X $Y
}
}
@ -3762,18 +3883,18 @@ proc on_application_mapped {} {
set gm $repo_config(gui.geometry)
if {$use_ttk} {
bind .vpane <Map> \
[list on_ttk_pane_mapped %W 0 [lindex $gm 1]]
[list on_ttk_pane_mapped %W 0 [lindex $gm 1]]
bind .vpane.files <Map> \
[list on_ttk_pane_mapped %W 0 [lindex $gm 2]]
[list on_ttk_pane_mapped %W 0 [lindex $gm 2]]
} else {
bind .vpane <Map> \
[list on_tk_pane_mapped %W 0 \
[lindex $gm 1] \
[lindex [.vpane sash coord 0] 1]]
[list on_tk_pane_mapped %W 0 \
[lindex $gm 1] \
[lindex [.vpane sash coord 0] 1]]
bind .vpane.files <Map> \
[list on_tk_pane_mapped %W 0 \
[lindex [.vpane.files sash coord 0] 0] \
[lindex $gm 2]]
[list on_tk_pane_mapped %W 0 \
[lindex [.vpane.files sash coord 0] 0] \
[lindex $gm 2]]
}
wm geometry . [lindex $gm 0]
}
@ -3812,6 +3933,8 @@ bind $ui_comm <$M1B-Key-KP_Subtract> {show_less_context;break}
bind $ui_comm <$M1B-Key-equal> {show_more_context;break}
bind $ui_comm <$M1B-Key-plus> {show_more_context;break}
bind $ui_comm <$M1B-Key-KP_Add> {show_more_context;break}
bind $ui_comm <$M1B-Key-BackSpace> {event generate %W <Meta-Delete>;break}
bind $ui_comm <$M1B-Key-Delete> {event generate %W <Meta-d>;break}
bind $ui_diff <$M1B-Key-x> {tk_textCopy %W;break}
bind $ui_diff <$M1B-Key-X> {tk_textCopy %W;break}
@ -3861,6 +3984,8 @@ bind . <$M1B-Key-j> do_revert_selection
bind . <$M1B-Key-J> do_revert_selection
bind . <$M1B-Key-i> do_add_all
bind . <$M1B-Key-I> do_add_all
bind . <$M1B-Key-e> toggle_commit_type
bind . <$M1B-Key-E> toggle_commit_type
bind . <$M1B-Key-minus> {show_less_context;break}
bind . <$M1B-Key-KP_Subtract> {show_less_context;break}
bind . <$M1B-Key-equal> {show_more_context;break}
@ -3877,6 +4002,14 @@ foreach i [list $ui_index $ui_workdir] {
}
unset i
bind . <Alt-Key-1> {focus_widget $::ui_workdir}
bind . <Alt-Key-2> {focus_widget $::ui_index}
bind . <Alt-Key-3> {focus $::ui_diff}
bind . <Alt-Key-4> {focus $::ui_comm}
set file_lists_last_clicked($ui_index) {}
set file_lists_last_clicked($ui_workdir) {}
set file_lists($ui_index) [list]
set file_lists($ui_workdir) [list]
@ -4055,6 +4188,9 @@ if {$picked && [is_config_true gui.autoexplore]} {
do_explore
}
# Clear "Initializing..." status
after 500 {$main_status show ""}
# Local variables:
# mode: tcl
# indent-tabs-mode: t

View file

@ -24,6 +24,7 @@ field w_cviewer ; # pane showing commit message
field finder ; # find mini-dialog frame
field gotoline ; # line goto mini-dialog frame
field status ; # status mega-widget instance
field status_operation ; # operation displayed by status mega-widget
field old_height ; # last known height of $w.file_pane
@ -274,6 +275,7 @@ constructor new {i_commit i_path i_jump} {
pack $w_cviewer -expand 1 -fill both
set status [::status_bar::new $w.status]
set status_operation {}
menu $w.ctxm -tearoff 0
$w.ctxm add command \
@ -326,6 +328,7 @@ constructor new {i_commit i_path i_jump} {
bind $i <Any-Motion> [cb _show_tooltip $i @%x,%y]
bind $i <Any-Enter> [cb _hide_tooltip]
bind $i <Any-Leave> [cb _hide_tooltip]
bind $i <Deactivate> [cb _hide_tooltip]
bind_button3 $i "
[cb _hide_tooltip]
set cursorX %x
@ -602,16 +605,23 @@ method _exec_blame {cur_w cur_d options cur_s} {
} else {
lappend options $commit
}
# We may recurse in from another call to _exec_blame and already have
# a status operation.
if {$status_operation == {}} {
set status_operation [$status start \
$cur_s \
[mc "lines annotated"]]
} else {
$status_operation restart $cur_s
}
lappend options -- $path
set fd [eval git_read --nice blame $options]
fconfigure $fd -blocking 0 -translation lf -encoding utf-8
fileevent $fd readable [cb _read_blame $fd $cur_w $cur_d]
set current_fd $fd
set blame_lines 0
$status start \
$cur_s \
[mc "lines annotated"]
}
method _read_blame {fd cur_w cur_d} {
@ -806,10 +816,11 @@ method _read_blame {fd cur_w cur_d} {
[mc "Loading original location annotations..."]
} else {
set current_fd {}
$status stop [mc "Annotation complete."]
$status_operation stop [mc "Annotation complete."]
set status_operation {}
}
} else {
$status update $blame_lines $total_lines
$status_operation update $blame_lines $total_lines
}
} ifdeleted { catch {close $fd} }
@ -1124,7 +1135,7 @@ method _blameparent {} {
set diffcmd [list diff-tree --unified=0 $cparent $cmit -- $new_path]
}
if {[catch {set fd [eval git_read $diffcmd]} err]} {
$status stop [mc "Unable to display parent"]
$status_operation stop [mc "Unable to display parent"]
error_popup [strcat [mc "Error loading diff:"] "\n\n$err"]
return
}

View file

@ -8,6 +8,7 @@ proc load_all_heads {} {
set rh_len [expr {[string length $rh] + 1}]
set all_heads [list]
set fd [git_read for-each-ref --format=%(refname) $rh]
fconfigure $fd -translation binary -encoding utf-8
while {[gets $fd line] > 0} {
if {!$some_heads_tracking || ![is_tracking_branch $line]} {
lappend all_heads [string range $line $rh_len end]
@ -24,6 +25,7 @@ proc load_all_tags {} {
--sort=-taggerdate \
--format=%(refname) \
refs/tags]
fconfigure $fd -translation binary -encoding utf-8
while {[gets $fd line] > 0} {
if {![regsub ^refs/tags/ $line {} name]} continue
lappend all_tags $name

View file

@ -341,9 +341,9 @@ method _readtree {} {
global HEAD
set readtree_d {}
$::main_status start \
set status_bar_operation [$::main_status start \
[mc "Updating working directory to '%s'..." [_name $this]] \
[mc "files checked out"]
[mc "files checked out"]]
set fd [git_read --stderr read-tree \
-m \
@ -354,26 +354,27 @@ method _readtree {} {
$new_hash \
]
fconfigure $fd -blocking 0 -translation binary
fileevent $fd readable [cb _readtree_wait $fd]
fileevent $fd readable [cb _readtree_wait $fd $status_bar_operation]
}
method _readtree_wait {fd} {
method _readtree_wait {fd status_bar_operation} {
global current_branch
set buf [read $fd]
$::main_status update_meter $buf
$status_bar_operation update_meter $buf
append readtree_d $buf
fconfigure $fd -blocking 1
if {![eof $fd]} {
fconfigure $fd -blocking 0
$status_bar_operation stop
return
}
if {[catch {close $fd}]} {
set err $readtree_d
regsub {^fatal: } $err {} err
$::main_status stop [mc "Aborted checkout of '%s' (file level merging is required)." [_name $this]]
$status_bar_operation stop [mc "Aborted checkout of '%s' (file level merging is required)." [_name $this]]
warn_popup [strcat [mc "File level merge required."] "
$err
@ -384,12 +385,12 @@ $err
return
}
$::main_status stop
$status_bar_operation stop
_after_readtree $this
}
method _after_readtree {} {
global selected_commit_type commit_type HEAD MERGE_HEAD PARENT
global commit_type HEAD MERGE_HEAD PARENT
global current_branch is_detached
global ui_comm
@ -490,12 +491,12 @@ method _update_repo_state {} {
# amend mode our file lists are accurate and we can avoid
# the rescan.
#
global selected_commit_type commit_type HEAD MERGE_HEAD PARENT
global commit_type_is_amend commit_type HEAD MERGE_HEAD PARENT
global ui_comm
unlock_index
set name [_name $this]
set selected_commit_type new
set commit_type_is_amend 0
if {[string match amend* $commit_type]} {
$ui_comm delete 0.0 end
$ui_comm edit reset

View file

@ -9,6 +9,18 @@ field w_body ; # Widget holding the center content
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
@ -345,31 +357,10 @@ proc _is_git {path {outdir_var ""}} {
if {$outdir_var ne ""} {
upvar 1 $outdir_var outdir
}
if {[file isfile $path]} {
set fp [open $path r]
gets $fp line
close $fp
if {[regexp "^gitdir: (.+)$" $line line link_target]} {
set path [file join [file dirname $path] $link_target]
set path [file normalize $path]
}
if {[catch {set outdir [git rev-parse --resolve-git-dir $path]}]} {
return 0
}
if {[file exists [file join $path HEAD]]
&& [file exists [file join $path objects]]
&& [file exists [file join $path config]]} {
set outdir $path
return 1
}
if {[is_Cygwin]} {
if {[file exists [file join $path HEAD]]
&& [file exists [file join $path objects.lnk]]
&& [file exists [file join $path config.lnk]]} {
set outdir $path
return 1
}
}
return 0
return 1
}
proc _objdir {path} {
@ -659,12 +650,12 @@ method _do_clone2 {} {
switch -exact -- $clone_type {
hardlink {
set o_cons [status_bar::two_line $w_body]
set o_status [status_bar::two_line $w_body]
pack $w_body -fill x -padx 10 -pady 10
$o_cons start \
set status_op [$o_status start \
[mc "Counting objects"] \
[mc "buckets"]
[mc "buckets"]]
update
if {[file exists [file join $objdir info alternates]]} {
@ -689,6 +680,7 @@ method _do_clone2 {} {
} err]} {
catch {cd $pwd}
_clone_failed $this [mc "Unable to copy objects/info/alternates: %s" $err]
$status_op stop
return
}
}
@ -700,7 +692,7 @@ method _do_clone2 {} {
-directory [file join $objdir] ??]
set bcnt [expr {[llength $buckets] + 2}]
set bcur 1
$o_cons update $bcur $bcnt
$status_op update $bcur $bcnt
update
file mkdir [file join .git objects pack]
@ -708,7 +700,7 @@ method _do_clone2 {} {
-directory [file join $objdir pack] *] {
lappend tolink [file join pack $i]
}
$o_cons update [incr bcur] $bcnt
$status_op update [incr bcur] $bcnt
update
foreach i $buckets {
@ -717,10 +709,10 @@ method _do_clone2 {} {
-directory [file join $objdir $i] *] {
lappend tolink [file join $i $j]
}
$o_cons update [incr bcur] $bcnt
$status_op update [incr bcur] $bcnt
update
}
$o_cons stop
$status_op stop
if {$tolink eq {}} {
info_popup [strcat \
@ -747,6 +739,8 @@ method _do_clone2 {} {
if {!$i} return
destroy $w_body
set o_status {}
}
full {
set o_cons [console::embed \
@ -781,9 +775,9 @@ method _do_clone2 {} {
}
method _copy_files {objdir tocopy} {
$o_cons start \
set status_op [$o_status start \
[mc "Copying objects"] \
[mc "KiB"]
[mc "KiB"]]
set tot 0
set cmp 0
foreach p $tocopy {
@ -798,7 +792,7 @@ method _copy_files {objdir tocopy} {
while {![eof $f_in]} {
incr cmp [fcopy $f_in $f_cp -size 16384]
$o_cons update \
$status_op update \
[expr {$cmp / 1024}] \
[expr {$tot / 1024}]
update
@ -808,17 +802,19 @@ method _copy_files {objdir tocopy} {
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]
$o_cons start \
set status_op [$o_status start \
[mc "Linking objects"] \
[mc "objects"]
[mc "objects"]]
for {set i 0} {$i < $total} {} {
set p [lindex $tolink $i]
if {[catch {
@ -827,15 +823,17 @@ method _link_files {objdir tolink} {
[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} {
$o_cons update $i $total
$status_op update $i $total
update
}
}
$status_op stop
return 1
}
@ -958,11 +956,26 @@ method _do_clone_checkout {HEAD} {
return
}
set o_cons [status_bar::two_line $w_body]
set status [status_bar::two_line $w_body]
pack $w_body -fill x -padx 10 -pady 10
$o_cons start \
# 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"]
[mc "files"]]
set readtree_err {}
set fd [git_read --stderr read-tree \
@ -976,33 +989,9 @@ method _do_clone_checkout {HEAD} {
fileevent $fd readable [cb _readtree_wait $fd]
}
method _do_validate_submodule_cloning {ok} {
if {$ok} {
$o_cons done $ok
set done 1
} else {
_clone_failed $this [mc "Cannot clone submodules."]
}
}
method _do_clone_submodules {} {
if {$recursive eq {true}} {
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
}
}
method _readtree_wait {fd} {
set buf [read $fd]
$o_cons update_meter $buf
$o_status_op update_meter $buf
append readtree_err $buf
fconfigure $fd -blocking 1
@ -1050,6 +1039,34 @@ method _postcheckout_wait {fd_ph} {
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
}
}
method _do_validate_submodule_cloning {ok} {
if {$ok} {
$o_cons done $ok
set done 1
} else {
_clone_failed $this [mc "Cannot clone submodules."]
}
}
######################################################################
##
## Open Existing Repository

158
third_party/git/git-gui/lib/chord.tcl vendored Normal file
View file

@ -0,0 +1,158 @@
# Simple Chord for Tcl
#
# A "chord" is a method with more than one entrypoint and only one body, such
# that the body runs only once all the entrypoints have been called by
# different asynchronous tasks. In this implementation, the chord is defined
# dynamically for each invocation. A SimpleChord object is created, supplying
# body script to be run when the chord is completed, and then one or more notes
# are added to the chord. Each note can be called like a proc, and returns
# immediately if the chord isn't yet complete. When the last remaining note is
# called, the body runs before the note returns.
#
# The SimpleChord class has a constructor that takes the body script, and a
# method add_note that returns a note object. Since the body script does not
# run in the context of the procedure that defined it, a mechanism is provided
# for injecting variables into the chord for use by the body script. The
# activation of a note is idempotent; multiple calls have the same effect as
# a simple call.
#
# If you are invoking asynchronous operations with chord notes as completion
# callbacks, and there is a possibility that earlier operations could complete
# before later ones are started, it is a good practice to create a "common"
# note on the chord that prevents it from being complete until you're certain
# you've added all the notes you need.
#
# Example:
#
# # Turn off the UI while running a couple of async operations.
# lock_ui
#
# set chord [SimpleChord::new {
# unlock_ui
# # Note: $notice here is not referenced in the calling scope
# if {$notice} { info_popup $notice }
# }
#
# # Configure a note to keep the chord from completing until
# # all operations have been initiated.
# set common_note [$chord add_note]
#
# # Activate notes in 'after' callbacks to other operations
# set newnote [$chord add_note]
# async_operation $args [list $newnote activate]
#
# # Communicate with the chord body
# if {$condition} {
# # This sets $notice in the same context that the chord body runs in.
# $chord eval { set notice "Something interesting" }
# }
#
# # Activate the common note, making the chord eligible to complete
# $common_note activate
#
# At this point, the chord will complete at some unknown point in the future.
# The common note might have been the first note activated, or the async
# operations might have completed synchronously and the common note is the
# last one, completing the chord before this code finishes, or anything in
# between. The purpose of the chord is to not have to worry about the order.
# SimpleChord class:
# Represents a procedure that conceptually has multiple entrypoints that must
# all be called before the procedure executes. Each entrypoint is called a
# "note". The chord is only "completed" when all the notes are "activated".
class SimpleChord {
field notes
field body
field is_completed
field eval_ns
# Constructor:
# set chord [SimpleChord::new {body}]
# Creates a new chord object with the specified body script. The
# body script is evaluated at most once, when a note is activated
# and the chord has no other non-activated notes.
constructor new {i_body} {
set notes [list]
set body $i_body
set is_completed 0
set eval_ns "[namespace qualifiers $this]::eval"
return $this
}
# Method:
# $chord eval {script}
# Runs the specified script in the same context (namespace) in which
# the chord body will be evaluated. This can be used to set variable
# values for the chord body to use.
method eval {script} {
namespace eval $eval_ns $script
}
# Method:
# set note [$chord add_note]
# Adds a new note to the chord, an instance of ChordNote. Raises an
# error if the chord is already completed, otherwise the chord is
# updated so that the new note must also be activated before the
# body is evaluated.
method add_note {} {
if {$is_completed} { error "Cannot add a note to a completed chord" }
set note [ChordNote::new $this]
lappend notes $note
return $note
}
# This method is for internal use only and is intentionally undocumented.
method notify_note_activation {} {
if {!$is_completed} {
foreach note $notes {
if {![$note is_activated]} { return }
}
set is_completed 1
namespace eval $eval_ns $body
delete_this
}
}
}
# ChordNote class:
# Represents a note within a chord, providing a way to activate it. When the
# final note of the chord is activated (this can be any note in the chord,
# with all other notes already previously activated in any order), the chord's
# body is evaluated.
class ChordNote {
field chord
field is_activated
# Constructor:
# Instances of ChordNote are created internally by calling add_note on
# SimpleChord objects.
constructor new {c} {
set chord $c
set is_activated 0
return $this
}
# Method:
# [$note is_activated]
# Returns true if this note has already been activated.
method is_activated {} {
return $is_activated
}
# Method:
# $note activate
# Activates the note, if it has not already been activated, and
# completes the chord if there are no other notes awaiting
# activation. Subsequent calls will have no further effect.
method activate {} {
if {!$is_activated} {
set is_activated 1
$chord notify_note_activation
}
}
}

View file

@ -333,7 +333,7 @@ proc commit_writetree {curHEAD msg_p} {
proc commit_committree {fd_wt curHEAD msg_p} {
global HEAD PARENT MERGE_HEAD commit_type commit_author
global current_branch
global ui_comm selected_commit_type
global ui_comm commit_type_is_amend
global file_states selected_paths rescan_active
global repo_config
global env
@ -467,8 +467,8 @@ A rescan will be automatically started now.
# -- Update in memory status
#
set selected_commit_type new
set commit_type normal
set commit_type_is_amend 0
set HEAD $cmt_id
set PARENT $cmt_id
set MERGE_HEAD [list]

View file

@ -203,6 +203,8 @@ method done {ok} {
focus $w.ok
}
}
bind $w <Key-Escape> "destroy $w;break"
}
method _sb_set {sb orient first last} {

View file

@ -55,7 +55,7 @@ proc reshow_diff {{after {}}} {
proc force_diff_encoding {enc} {
global current_diff_path
if {$current_diff_path ne {}} {
force_path_encoding $current_diff_path $enc
reshow_diff
@ -270,19 +270,6 @@ proc show_other_diff {path w m cont_info} {
}
}
proc get_conflict_marker_size {path} {
set size 7
catch {
set fd_rc [eval [list git_read check-attr "conflict-marker-size" -- $path]]
set ret [gets $fd_rc line]
close $fd_rc
if {$ret > 0} {
regexp {.*: conflict-marker-size: (\d+)$} $line line size
}
}
return $size
}
proc start_show_diff {cont_info {add_opts {}}} {
global file_states file_lists
global is_3way_diff is_submodule_diff diff_active repo_config
@ -298,7 +285,7 @@ proc start_show_diff {cont_info {add_opts {}}} {
set is_submodule_diff 0
set diff_active 1
set current_diff_header {}
set conflict_size [get_conflict_marker_size $path]
set conflict_size [gitattr $path conflict-marker-size 7]
set cmd [list]
if {$w eq $ui_index} {
@ -360,6 +347,10 @@ proc start_show_diff {cont_info {add_opts {}}} {
}
set ::current_diff_inheader 1
# Detect pre-image lines of the diff3 conflict-style. They are just
# '++' lines which is not bijective. Thus, we need to maintain a state
# across lines.
set ::conflict_in_pre_image 0
fconfigure $fd \
-blocking 0 \
-encoding [get_path_encoding $path] \
@ -462,11 +453,23 @@ proc read_diff {fd conflict_size cont_info} {
{--} {set tags d_--}
{++} {
set regexp [string map [list %conflict_size $conflict_size]\
{^\+\+([<>=]){%conflict_size}(?: |$)}]
{^\+\+([<>=|]){%conflict_size}(?: |$)}]
if {[regexp $regexp $line _g op]} {
set is_conflict_diff 1
set line [string replace $line 0 1 { }]
set tags d$op
# The ||| conflict-marker marks the start of the pre-image.
# All those lines are also prefixed with '++'. Thus we need
# to maintain this state.
set ::conflict_in_pre_image [expr {$op eq {|}}]
} elseif {$::conflict_in_pre_image} {
# This is a pre-image line. It is the one which both sides
# are based on. As it has also the '++' line start, it is
# normally shown as 'added'. Invert this to '--' to make
# it a 'removed' line.
set line [string replace $line 0 1 {--}]
set tags d_--
} else {
set tags d_++
}
@ -567,24 +570,31 @@ proc read_diff {fd conflict_size cont_info} {
}
}
proc apply_hunk {x y} {
proc apply_or_revert_hunk {x y revert} {
global current_diff_path current_diff_header current_diff_side
global ui_diff ui_index file_states
global ui_diff ui_index file_states last_revert last_revert_enc
if {$current_diff_path eq {} || $current_diff_header eq {}} return
if {![lock_index apply_hunk]} return
set apply_cmd {apply --cached --whitespace=nowarn}
set apply_cmd {apply --whitespace=nowarn}
set mi [lindex $file_states($current_diff_path) 0]
if {$current_diff_side eq $ui_index} {
set failed_msg [mc "Failed to unstage selected hunk."]
lappend apply_cmd --reverse
lappend apply_cmd --reverse --cached
if {[string index $mi 0] ne {M}} {
unlock_index
return
}
} else {
set failed_msg [mc "Failed to stage selected hunk."]
if {$revert} {
set failed_msg [mc "Failed to revert selected hunk."]
lappend apply_cmd --reverse
} else {
set failed_msg [mc "Failed to stage selected hunk."]
lappend apply_cmd --cached
}
if {[string index $mi 1] ne {M}} {
unlock_index
return
@ -603,29 +613,40 @@ proc apply_hunk {x y} {
set e_lno end
}
set wholepatch "$current_diff_header[$ui_diff get $s_lno $e_lno]"
if {[catch {
set enc [get_path_encoding $current_diff_path]
set p [eval git_write $apply_cmd]
fconfigure $p -translation binary -encoding $enc
puts -nonewline $p $current_diff_header
puts -nonewline $p [$ui_diff get $s_lno $e_lno]
puts -nonewline $p $wholepatch
close $p} err]} {
error_popup "$failed_msg\n\n$err"
unlock_index
return
}
if {$revert} {
# Save a copy of this patch for undoing reverts.
set last_revert $wholepatch
set last_revert_enc $enc
}
$ui_diff conf -state normal
$ui_diff delete $s_lno $e_lno
$ui_diff conf -state disabled
# Check if the hunk was the last one in the file.
if {[$ui_diff get 1.0 end] eq "\n"} {
set o _
} else {
set o ?
}
if {$current_diff_side eq $ui_index} {
# Update the status flags.
if {$revert} {
set mi [string index $mi 0]$o
} elseif {$current_diff_side eq $ui_index} {
set mi ${o}M
} elseif {[string index $mi 0] eq {_}} {
set mi M$o
@ -640,9 +661,9 @@ proc apply_hunk {x y} {
}
}
proc apply_range_or_line {x y} {
proc apply_or_revert_range_or_line {x y revert} {
global current_diff_path current_diff_header current_diff_side
global ui_diff ui_index file_states
global ui_diff ui_index file_states last_revert
set selected [$ui_diff tag nextrange sel 0.0]
@ -660,19 +681,27 @@ proc apply_range_or_line {x y} {
if {$current_diff_path eq {} || $current_diff_header eq {}} return
if {![lock_index apply_hunk]} return
set apply_cmd {apply --cached --whitespace=nowarn}
set apply_cmd {apply --whitespace=nowarn}
set mi [lindex $file_states($current_diff_path) 0]
if {$current_diff_side eq $ui_index} {
set failed_msg [mc "Failed to unstage selected line."]
set to_context {+}
lappend apply_cmd --reverse
lappend apply_cmd --reverse --cached
if {[string index $mi 0] ne {M}} {
unlock_index
return
}
} else {
set failed_msg [mc "Failed to stage selected line."]
set to_context {-}
if {$revert} {
set failed_msg [mc "Failed to revert selected line."]
set to_context {+}
lappend apply_cmd --reverse
} else {
set failed_msg [mc "Failed to stage selected line."]
set to_context {-}
lappend apply_cmd --cached
}
if {[string index $mi 1] ne {M}} {
unlock_index
return
@ -830,7 +859,47 @@ proc apply_range_or_line {x y} {
puts -nonewline $p $wholepatch
close $p} err]} {
error_popup "$failed_msg\n\n$err"
unlock_index
return
}
if {$revert} {
# Save a copy of this patch for undoing reverts.
set last_revert $current_diff_header$wholepatch
set last_revert_enc $enc
}
unlock_index
}
# Undo the last line/hunk reverted. When hunks and lines are reverted, a copy
# of the diff applied is saved. Re-apply that diff to undo the revert.
#
# Right now, we only use a single variable to hold the copy, and not a
# stack/deque for simplicity, so multiple undos are not possible. Maybe this
# can be added if the need for something like this is felt in the future.
proc undo_last_revert {} {
global last_revert current_diff_path current_diff_header
global last_revert_enc
if {$last_revert eq {}} return
if {![lock_index apply_hunk]} return
set apply_cmd {apply --whitespace=nowarn}
set failed_msg [mc "Failed to undo last revert."]
if {[catch {
set enc $last_revert_enc
set p [eval git_write $apply_cmd]
fconfigure $p -translation binary -encoding $enc
puts -nonewline $p $last_revert
close $p} err]} {
error_popup "$failed_msg\n\n$err"
unlock_index
return
}
set last_revert {}
unlock_index
}

View file

@ -7,67 +7,74 @@ proc _delete_indexlock {} {
}
}
proc _close_updateindex {fd after} {
global use_ttk NS
fconfigure $fd -blocking 1
if {[catch {close $fd} err]} {
set w .indexfried
Dialog $w
wm withdraw $w
wm title $w [strcat "[appname] ([reponame]): " [mc "Index Error"]]
wm geometry $w "+[winfo rootx .]+[winfo rooty .]"
set s [mc "Updating the Git index failed. A rescan will be automatically started to resynchronize git-gui."]
text $w.msg -yscrollcommand [list $w.vs set] \
-width [string length $s] -relief flat \
-borderwidth 0 -highlightthickness 0 \
-background [get_bg_color $w]
$w.msg tag configure bold -font font_uibold -justify center
${NS}::scrollbar $w.vs -command [list $w.msg yview]
$w.msg insert end $s bold \n\n$err {}
$w.msg configure -state disabled
${NS}::button $w.continue \
-text [mc "Continue"] \
-command [list destroy $w]
${NS}::button $w.unlock \
-text [mc "Unlock Index"] \
-command "destroy $w; _delete_indexlock"
grid $w.msg - $w.vs -sticky news
grid $w.unlock $w.continue - -sticky se -padx 2 -pady 2
grid columnconfigure $w 0 -weight 1
grid rowconfigure $w 0 -weight 1
wm protocol $w WM_DELETE_WINDOW update
bind $w.continue <Visibility> "
grab $w
focus %W
"
wm deiconify $w
tkwait window $w
$::main_status stop
proc close_and_unlock_index {fd after} {
if {![catch {_close_updateindex $fd} err]} {
unlock_index
rescan $after 0
return
uplevel #0 $after
} else {
rescan_on_error $err $after
}
$::main_status stop
unlock_index
uplevel #0 $after
}
proc update_indexinfo {msg pathList after} {
proc _close_updateindex {fd} {
fconfigure $fd -blocking 1
close $fd
}
proc rescan_on_error {err {after {}}} {
global use_ttk NS
set w .indexfried
Dialog $w
wm withdraw $w
wm title $w [strcat "[appname] ([reponame]): " [mc "Index Error"]]
wm geometry $w "+[winfo rootx .]+[winfo rooty .]"
set s [mc "Updating the Git index failed. A rescan will be automatically started to resynchronize git-gui."]
text $w.msg -yscrollcommand [list $w.vs set] \
-width [string length $s] -relief flat \
-borderwidth 0 -highlightthickness 0 \
-background [get_bg_color $w]
$w.msg tag configure bold -font font_uibold -justify center
${NS}::scrollbar $w.vs -command [list $w.msg yview]
$w.msg insert end $s bold \n\n$err {}
$w.msg configure -state disabled
${NS}::button $w.continue \
-text [mc "Continue"] \
-command [list destroy $w]
${NS}::button $w.unlock \
-text [mc "Unlock Index"] \
-command "destroy $w; _delete_indexlock"
grid $w.msg - $w.vs -sticky news
grid $w.unlock $w.continue - -sticky se -padx 2 -pady 2
grid columnconfigure $w 0 -weight 1
grid rowconfigure $w 0 -weight 1
wm protocol $w WM_DELETE_WINDOW update
bind $w.continue <Visibility> "
grab $w
focus %W
"
wm deiconify $w
tkwait window $w
$::main_status stop_all
unlock_index
rescan [concat $after {ui_ready;}] 0
}
proc update_indexinfo {msg path_list after} {
global update_index_cp
if {![lock_index update]} return
set update_index_cp 0
set pathList [lsort $pathList]
set totalCnt [llength $pathList]
set batch [expr {int($totalCnt * .01) + 1}]
set path_list [lsort $path_list]
set total_cnt [llength $path_list]
set batch [expr {int($total_cnt * .01) + 1}]
if {$batch > 25} {set batch 25}
$::main_status start $msg [mc "files"]
set status_bar_operation [$::main_status start $msg [mc "files"]]
set fd [git_write update-index -z --index-info]
fconfigure $fd \
-blocking 0 \
@ -78,26 +85,29 @@ proc update_indexinfo {msg pathList after} {
fileevent $fd writable [list \
write_update_indexinfo \
$fd \
$pathList \
$totalCnt \
$path_list \
$total_cnt \
$batch \
$status_bar_operation \
$after \
]
}
proc write_update_indexinfo {fd pathList totalCnt batch after} {
proc write_update_indexinfo {fd path_list total_cnt batch status_bar_operation \
after} {
global update_index_cp
global file_states current_diff_path
if {$update_index_cp >= $totalCnt} {
_close_updateindex $fd $after
if {$update_index_cp >= $total_cnt} {
$status_bar_operation stop
close_and_unlock_index $fd $after
return
}
for {set i $batch} \
{$update_index_cp < $totalCnt && $i > 0} \
{$update_index_cp < $total_cnt && $i > 0} \
{incr i -1} {
set path [lindex $pathList $update_index_cp]
set path [lindex $path_list $update_index_cp]
incr update_index_cp
set s $file_states($path)
@ -119,21 +129,21 @@ proc write_update_indexinfo {fd pathList totalCnt batch after} {
display_file $path $new
}
$::main_status update $update_index_cp $totalCnt
$status_bar_operation update $update_index_cp $total_cnt
}
proc update_index {msg pathList after} {
proc update_index {msg path_list after} {
global update_index_cp
if {![lock_index update]} return
set update_index_cp 0
set pathList [lsort $pathList]
set totalCnt [llength $pathList]
set batch [expr {int($totalCnt * .01) + 1}]
set path_list [lsort $path_list]
set total_cnt [llength $path_list]
set batch [expr {int($total_cnt * .01) + 1}]
if {$batch > 25} {set batch 25}
$::main_status start $msg [mc "files"]
set status_bar_operation [$::main_status start $msg [mc "files"]]
set fd [git_write update-index --add --remove -z --stdin]
fconfigure $fd \
-blocking 0 \
@ -144,26 +154,29 @@ proc update_index {msg pathList after} {
fileevent $fd writable [list \
write_update_index \
$fd \
$pathList \
$totalCnt \
$path_list \
$total_cnt \
$batch \
$status_bar_operation \
$after \
]
}
proc write_update_index {fd pathList totalCnt batch after} {
proc write_update_index {fd path_list total_cnt batch status_bar_operation \
after} {
global update_index_cp
global file_states current_diff_path
if {$update_index_cp >= $totalCnt} {
_close_updateindex $fd $after
if {$update_index_cp >= $total_cnt} {
$status_bar_operation stop
close_and_unlock_index $fd $after
return
}
for {set i $batch} \
{$update_index_cp < $totalCnt && $i > 0} \
{$update_index_cp < $total_cnt && $i > 0} \
{incr i -1} {
set path [lindex $pathList $update_index_cp]
set path [lindex $path_list $update_index_cp]
incr update_index_cp
switch -glob -- [lindex $file_states($path) 0] {
@ -190,21 +203,21 @@ proc write_update_index {fd pathList totalCnt batch after} {
display_file $path $new
}
$::main_status update $update_index_cp $totalCnt
$status_bar_operation update $update_index_cp $total_cnt
}
proc checkout_index {msg pathList after} {
proc checkout_index {msg path_list after capture_error} {
global update_index_cp
if {![lock_index update]} return
set update_index_cp 0
set pathList [lsort $pathList]
set totalCnt [llength $pathList]
set batch [expr {int($totalCnt * .01) + 1}]
set path_list [lsort $path_list]
set total_cnt [llength $path_list]
set batch [expr {int($total_cnt * .01) + 1}]
if {$batch > 25} {set batch 25}
$::main_status start $msg [mc "files"]
set status_bar_operation [$::main_status start $msg [mc "files"]]
set fd [git_write checkout-index \
--index \
--quiet \
@ -221,26 +234,45 @@ proc checkout_index {msg pathList after} {
fileevent $fd writable [list \
write_checkout_index \
$fd \
$pathList \
$totalCnt \
$path_list \
$total_cnt \
$batch \
$status_bar_operation \
$after \
$capture_error \
]
}
proc write_checkout_index {fd pathList totalCnt batch after} {
proc write_checkout_index {fd path_list total_cnt batch status_bar_operation \
after capture_error} {
global update_index_cp
global file_states current_diff_path
if {$update_index_cp >= $totalCnt} {
_close_updateindex $fd $after
if {$update_index_cp >= $total_cnt} {
$status_bar_operation stop
# We do not unlock the index directly here because this
# operation expects to potentially run in parallel with file
# deletions scheduled by revert_helper. We're done with the
# update index, so we close it, but actually unlocking the index
# and dealing with potential errors is deferred to the chord
# body that runs when all async operations are completed.
#
# (See after_chord in revert_helper.)
if {[catch {_close_updateindex $fd} err]} {
uplevel #0 $capture_error [list $err]
}
uplevel #0 $after
return
}
for {set i $batch} \
{$update_index_cp < $totalCnt && $i > 0} \
{$update_index_cp < $total_cnt && $i > 0} \
{incr i -1} {
set path [lindex $pathList $update_index_cp]
set path [lindex $path_list $update_index_cp]
incr update_index_cp
switch -glob -- [lindex $file_states($path) 0] {
U? {continue}
@ -253,7 +285,7 @@ proc write_checkout_index {fd pathList totalCnt batch after} {
}
}
$::main_status update $update_index_cp $totalCnt
$status_bar_operation update $update_index_cp $total_cnt
}
proc unstage_helper {txt paths} {
@ -261,7 +293,7 @@ proc unstage_helper {txt paths} {
if {![lock_index begin-update]} return
set pathList [list]
set path_list [list]
set after {}
foreach path $paths {
switch -glob -- [lindex $file_states($path) 0] {
@ -269,20 +301,20 @@ proc unstage_helper {txt paths} {
M? -
T? -
D? {
lappend pathList $path
lappend path_list $path
if {$path eq $current_diff_path} {
set after {reshow_diff;}
}
}
}
}
if {$pathList eq {}} {
if {$path_list eq {}} {
unlock_index
} else {
update_indexinfo \
$txt \
$pathList \
[concat $after [list ui_ready]]
$path_list \
[concat $after {ui_ready;}]
}
}
@ -305,7 +337,7 @@ proc add_helper {txt paths} {
if {![lock_index begin-update]} return
set pathList [list]
set path_list [list]
set after {}
foreach path $paths {
switch -glob -- [lindex $file_states($path) 0] {
@ -321,20 +353,20 @@ proc add_helper {txt paths} {
?M -
?D -
?T {
lappend pathList $path
lappend path_list $path
if {$path eq $current_diff_path} {
set after {reshow_diff;}
}
}
}
}
if {$pathList eq {}} {
if {$path_list eq {}} {
unlock_index
} else {
update_index \
$txt \
$pathList \
[concat $after {ui_status [mc "Ready to commit."]}]
$path_list \
[concat $after {ui_status [mc "Ready to commit."];}]
}
}
@ -388,66 +420,303 @@ proc do_add_all {} {
add_helper [mc "Adding all changed files"] $paths
}
# Copied from TclLib package "lambda".
proc lambda {arguments body args} {
return [list ::apply [list $arguments $body] {*}$args]
}
proc revert_helper {txt paths} {
global file_states current_diff_path
if {![lock_index begin-update]} return
set pathList [list]
set after {}
# Common "after" functionality that waits until multiple asynchronous
# operations are complete (by waiting for them to activate their notes
# on the chord).
#
# The asynchronous operations are each indicated below by a comment
# before the code block that starts the async operation.
set after_chord [SimpleChord::new {
if {[string trim $err] != ""} {
rescan_on_error $err
} else {
unlock_index
if {$should_reshow_diff} { reshow_diff }
ui_ready
}
}]
$after_chord eval { set should_reshow_diff 0 }
# This function captures an error for processing when after_chord is
# completed. (The chord is curried into the lambda function.)
set capture_error [lambda \
{chord error} \
{ $chord eval [list set err $error] } \
$after_chord]
# We don't know how many notes we're going to create (it's dynamic based
# on conditional paths below), so create a common note that will delay
# the chord's completion until we activate it, and then activate it
# after all the other notes have been created.
set after_common_note [$after_chord add_note]
set path_list [list]
set untracked_list [list]
foreach path $paths {
switch -glob -- [lindex $file_states($path) 0] {
U? {continue}
?O {
lappend untracked_list $path
}
?M -
?T -
?D {
lappend pathList $path
lappend path_list $path
if {$path eq $current_diff_path} {
set after {reshow_diff;}
$after_chord eval { set should_reshow_diff 1 }
}
}
}
}
set path_cnt [llength $path_list]
set untracked_cnt [llength $untracked_list]
# Split question between singular and plural cases, because
# such distinction is needed in some languages. Previously, the
# code used "Revert changes in" for both, but that can't work
# in languages where 'in' must be combined with word from
# rest of string (in different way for both cases of course).
#
# FIXME: Unfortunately, even that isn't enough in some languages
# as they have quite complex plural-form rules. Unfortunately,
# msgcat doesn't seem to support that kind of string translation.
#
set n [llength $pathList]
if {$n == 0} {
unlock_index
return
} elseif {$n == 1} {
set query [mc "Revert changes in file %s?" [short_path [lindex $pathList]]]
} else {
set query [mc "Revert changes in these %i files?" $n]
}
# Asynchronous operation: revert changes by checking them out afresh
# from the index.
if {$path_cnt > 0} {
# Split question between singular and plural cases, because
# such distinction is needed in some languages. Previously, the
# code used "Revert changes in" for both, but that can't work
# in languages where 'in' must be combined with word from
# rest of string (in different way for both cases of course).
#
# FIXME: Unfortunately, even that isn't enough in some languages
# as they have quite complex plural-form rules. Unfortunately,
# msgcat doesn't seem to support that kind of string
# translation.
#
if {$path_cnt == 1} {
set query [mc \
"Revert changes in file %s?" \
[short_path [lindex $path_list]] \
]
} else {
set query [mc \
"Revert changes in these %i files?" \
$path_cnt]
}
set reply [tk_dialog \
.confirm_revert \
"[appname] ([reponame])" \
"$query
set reply [tk_dialog \
.confirm_revert \
"[appname] ([reponame])" \
"$query
[mc "Any unstaged changes will be permanently lost by the revert."]" \
question \
1 \
[mc "Do Nothing"] \
[mc "Revert Changes"] \
]
if {$reply == 1} {
checkout_index \
$txt \
$pathList \
[concat $after [list ui_ready]]
question \
1 \
[mc "Do Nothing"] \
[mc "Revert Changes"] \
]
if {$reply == 1} {
set note [$after_chord add_note]
checkout_index \
$txt \
$path_list \
[list $note activate] \
$capture_error
}
}
# Asynchronous operation: Deletion of untracked files.
if {$untracked_cnt > 0} {
# Split question between singular and plural cases, because
# such distinction is needed in some languages.
#
# FIXME: Unfortunately, even that isn't enough in some languages
# as they have quite complex plural-form rules. Unfortunately,
# msgcat doesn't seem to support that kind of string
# translation.
#
if {$untracked_cnt == 1} {
set query [mc \
"Delete untracked file %s?" \
[short_path [lindex $untracked_list]] \
]
} else {
set query [mc \
"Delete these %i untracked files?" \
$untracked_cnt \
]
}
set reply [tk_dialog \
.confirm_revert \
"[appname] ([reponame])" \
"$query
[mc "Files will be permanently deleted."]" \
question \
1 \
[mc "Do Nothing"] \
[mc "Delete Files"] \
]
if {$reply == 1} {
$after_chord eval { set should_reshow_diff 1 }
set note [$after_chord add_note]
delete_files $untracked_list [list $note activate]
}
}
# Activate the common note. If no other notes were created, this
# completes the chord. If other notes were created, then this common
# note prevents a race condition where the chord might complete early.
$after_common_note activate
}
# Delete all of the specified files, performing deletion in batches to allow the
# UI to remain responsive and updated.
proc delete_files {path_list after} {
# Enable progress bar status updates
set status_bar_operation [$::main_status \
start \
[mc "Deleting"] \
[mc "files"]]
set path_index 0
set deletion_errors [list]
set batch_size 50
delete_helper \
$path_list \
$path_index \
$deletion_errors \
$batch_size \
$status_bar_operation \
$after
}
# Helper function to delete a list of files in batches. Each call deletes one
# batch of files, and then schedules a call for the next batch after any UI
# messages have been processed.
proc delete_helper {path_list path_index deletion_errors batch_size \
status_bar_operation after} {
global file_states
set path_cnt [llength $path_list]
set batch_remaining $batch_size
while {$batch_remaining > 0} {
if {$path_index >= $path_cnt} { break }
set path [lindex $path_list $path_index]
set deletion_failed [catch {file delete -- $path} deletion_error]
if {$deletion_failed} {
lappend deletion_errors [list "$deletion_error"]
} else {
remove_empty_directories [file dirname $path]
# Don't assume the deletion worked. Remove the file from
# the UI, but only if it no longer exists.
if {![path_exists $path]} {
unset file_states($path)
display_file $path __
}
}
incr path_index 1
incr batch_remaining -1
}
# Update the progress bar to indicate that this batch has been
# completed. The update will be visible when this procedure returns
# and allows the UI thread to process messages.
$status_bar_operation update $path_index $path_cnt
if {$path_index < $path_cnt} {
# The Tcler's Wiki lists this as the best practice for keeping
# a UI active and processing messages during a long-running
# operation.
after idle [list after 0 [list \
delete_helper \
$path_list \
$path_index \
$deletion_errors \
$batch_size \
$status_bar_operation \
$after
]]
} else {
unlock_index
# Finish the status bar operation.
$status_bar_operation stop
# Report error, if any, based on how many deletions failed.
set deletion_error_cnt [llength $deletion_errors]
if {($deletion_error_cnt > 0)
&& ($deletion_error_cnt <= [MAX_VERBOSE_FILES_IN_DELETION_ERROR])} {
set error_text [mc "Encountered errors deleting files:\n"]
foreach deletion_error $deletion_errors {
append error_text "* [lindex $deletion_error 0]\n"
}
error_popup $error_text
} elseif {$deletion_error_cnt == $path_cnt} {
error_popup [mc \
"None of the %d selected files could be deleted." \
$path_cnt \
]
} elseif {$deletion_error_cnt > 1} {
error_popup [mc \
"%d of the %d selected files could not be deleted." \
$deletion_error_cnt \
$path_cnt \
]
}
uplevel #0 $after
}
}
proc MAX_VERBOSE_FILES_IN_DELETION_ERROR {} { return 10; }
# This function is from the TCL documentation:
#
# https://wiki.tcl-lang.org/page/file+exists
#
# [file exists] returns false if the path does exist but is a symlink to a path
# that doesn't exist. This proc returns true if the path exists, regardless of
# whether it is a symlink and whether it is broken.
proc path_exists {name} {
expr {![catch {file lstat $name finfo}]}
}
# Remove as many empty directories as we can starting at the specified path,
# walking up the directory tree. If we encounter a directory that is not
# empty, or if a directory deletion fails, then we stop the operation and
# return to the caller. Even if this procedure fails to delete any
# directories at all, it does not report failure.
proc remove_empty_directories {directory_path} {
set parent_path [file dirname $directory_path]
while {$parent_path != $directory_path} {
set contents [glob -nocomplain -dir $directory_path *]
if {[llength $contents] > 0} { break }
if {[catch {file delete -- $directory_path}]} { break }
set directory_path $parent_path
set parent_path [file dirname $directory_path]
}
}
@ -466,19 +735,19 @@ proc do_revert_selection {} {
}
proc do_select_commit_type {} {
global commit_type selected_commit_type
global commit_type commit_type_is_amend
if {$selected_commit_type eq {new}
if {$commit_type_is_amend == 0
&& [string match amend* $commit_type]} {
create_new_commit
} elseif {$selected_commit_type eq {amend}
} elseif {$commit_type_is_amend == 1
&& ![string match amend* $commit_type]} {
load_last_commit
# The amend request was rejected...
#
if {![string match amend* $commit_type]} {
set selected_commit_type new
set commit_type_is_amend 0
}
}
}

View file

@ -241,23 +241,27 @@ Continue with resetting the current changes?"]
if {[ask_popup $op_question] eq {yes}} {
set fd [git_read --stderr read-tree --reset -u -v HEAD]
fconfigure $fd -blocking 0 -translation binary
fileevent $fd readable [namespace code [list _reset_wait $fd]]
$::main_status start [mc "Aborting"] [mc "files reset"]
set status_bar_operation [$::main_status \
start \
[mc "Aborting"] \
[mc "files reset"]]
fileevent $fd readable [namespace code [list \
_reset_wait $fd $status_bar_operation]]
} else {
unlock_index
}
}
proc _reset_wait {fd} {
proc _reset_wait {fd status_bar_operation} {
global ui_comm
$::main_status update_meter [read $fd]
$status_bar_operation update_meter [read $fd]
fconfigure $fd -blocking 1
if {[eof $fd]} {
set fail [catch {close $fd} err]
$::main_status stop
unlock_index
$status_bar_operation stop
$ui_comm delete 0.0 end
$ui_comm edit modified false

View file

@ -59,7 +59,7 @@ proc merge_add_resolution {path} {
update_index \
[mc "Adding resolution for %s" [short_path $path]] \
[list $path] \
[concat $after [list ui_ready]]
[concat $after {ui_ready;}]
}
proc merge_force_stage {stage} {

View file

@ -1,16 +1,42 @@
# git-gui status bar mega-widget
# Copyright (C) 2007 Shawn Pearce
# The status_bar class manages the entire status bar. It is possible for
# multiple overlapping asynchronous operations to want to display status
# simultaneously. Each one receives a status_bar_operation when it calls the
# start method, and the status bar combines all active operations into the
# line of text it displays. Most of the time, there will be at most one
# ongoing operation.
#
# Note that the entire status bar can be either in single-line or two-line
# mode, depending on the constructor. Multiple active operations are only
# supported for single-line status bars.
class status_bar {
field allow_multiple ; # configured at construction
field w ; # our own window path
field w_l ; # text widget we draw messages into
field w_c ; # canvas we draw a progress bar into
field c_pack ; # script to pack the canvas with
field status {}; # single line of text we show
field prefix {}; # text we format into status
field units {}; # unit of progress
field meter {}; # current core git progress meter (if active)
field baseline_text ; # text to show if there are no operations
field status_bar_text ; # combined text for all operations
field operations ; # list of current ongoing operations
# The status bar can display a progress bar, updated when consumers call the
# update method on their status_bar_operation. When there are multiple
# operations, the status bar shows the combined status of all operations.
#
# When an overlapping operation completes, the progress bar is going to
# abruptly have one fewer operation in the calculation, causing a discontinuity.
# Therefore, whenever an operation completes, if it is not the last operation,
# this counter is increased, and the progress bar is calculated as though there
# were still another operation at 100%. When the last operation completes, this
# is reset to 0.
field completed_operation_count
constructor new {path} {
global use_ttk NS
@ -18,12 +44,19 @@ constructor new {path} {
set w_l $w.l
set w_c $w.c
# Standard single-line status bar: Permit overlapping operations
set allow_multiple 1
set baseline_text ""
set operations [list]
set completed_operation_count 0
${NS}::frame $w
if {!$use_ttk} {
$w configure -borderwidth 1 -relief sunken
}
${NS}::label $w_l \
-textvariable @status \
-textvariable @status_bar_text \
-anchor w \
-justify left
pack $w_l -side left
@ -44,9 +77,16 @@ constructor two_line {path} {
set w_l $w.l
set w_c $w.c
# Two-line status bar: Only one ongoing operation permitted.
set allow_multiple 0
set baseline_text ""
set operations [list]
set completed_operation_count 0
${NS}::frame $w
${NS}::label $w_l \
-textvariable @status \
-textvariable @status_bar_text \
-anchor w \
-justify left
pack $w_l -anchor w -fill x
@ -56,7 +96,7 @@ constructor two_line {path} {
return $this
}
method start {msg uds} {
method ensure_canvas {} {
if {[winfo exists $w_c]} {
$w_c coords bar 0 0 0 20
} else {
@ -68,31 +108,170 @@ method start {msg uds} {
$w_c create rectangle 0 0 0 20 -tags bar -fill navy
eval $c_pack
}
}
method show {msg} {
$this ensure_canvas
set baseline_text $msg
$this refresh
}
method start {msg {uds {}}} {
set baseline_text ""
if {!$allow_multiple && [llength $operations]} {
return [lindex $operations 0]
}
$this ensure_canvas
set operation [status_bar_operation::new $this $msg $uds]
lappend operations $operation
$this refresh
return $operation
}
method refresh {} {
set new_text ""
set total [expr $completed_operation_count * 100]
set have $total
foreach operation $operations {
if {$new_text != ""} {
append new_text " / "
}
append new_text [$operation get_status]
set total [expr $total + 100]
set have [expr $have + [$operation get_progress]]
}
if {$new_text == ""} {
set new_text $baseline_text
}
set status_bar_text $new_text
if {[winfo exists $w_c]} {
set pixel_width 0
if {$have > 0} {
set pixel_width [expr {[winfo width $w_c] * $have / $total}]
}
$w_c coords bar 0 0 $pixel_width 20
}
}
method stop {operation stop_msg} {
set idx [lsearch $operations $operation]
if {$idx >= 0} {
set operations [lreplace $operations $idx $idx]
set completed_operation_count [expr \
$completed_operation_count + 1]
if {[llength $operations] == 0} {
set completed_operation_count 0
destroy $w_c
if {$stop_msg ne {}} {
set baseline_text $stop_msg
}
}
$this refresh
}
}
method stop_all {{stop_msg {}}} {
# This makes the operation's call to stop a no-op.
set operations_copy $operations
set operations [list]
foreach operation $operations_copy {
$operation stop
}
if {$stop_msg ne {}} {
set baseline_text $stop_msg
}
$this refresh
}
method _delete {current} {
if {$current eq $w} {
delete_this
}
}
}
# The status_bar_operation class tracks a single consumer's ongoing status bar
# activity, with the context that there are a few situations where multiple
# overlapping asynchronous operations might want to display status information
# simultaneously. Instances of status_bar_operation are created by calling
# start on the status_bar, and when the caller is done with its stauts bar
# operation, it calls stop on the operation.
class status_bar_operation {
field status_bar; # reference back to the status_bar that owns this object
field is_active;
field status {}; # single line of text we show
field progress {}; # current progress (0 to 100)
field prefix {}; # text we format into status
field units {}; # unit of progress
field meter {}; # current core git progress meter (if active)
constructor new {owner msg uds} {
set status_bar $owner
set status $msg
set progress 0
set prefix $msg
set units $uds
set meter {}
set is_active 1
return $this
}
method get_is_active {} { return $is_active }
method get_status {} { return $status }
method get_progress {} { return $progress }
method update {have total} {
set pdone 0
set cdone 0
if {!$is_active} { return }
set progress 0
if {$total > 0} {
set pdone [expr {100 * $have / $total}]
set cdone [expr {[winfo width $w_c] * $have / $total}]
set progress [expr {100 * $have / $total}]
}
set prec [string length [format %i $total]]
set status [mc "%s ... %*i of %*i %s (%3i%%)" \
$prefix \
$prec $have \
$prec $total \
$units $pdone]
$w_c coords bar 0 0 $cdone 20
$units $progress]
$status_bar refresh
}
method update_meter {buf} {
if {!$is_active} { return }
append meter $buf
set r [string last "\r" $meter]
if {$r == -1} {
@ -109,23 +288,25 @@ method update_meter {buf} {
}
}
method stop {{msg {}}} {
destroy $w_c
if {$msg ne {}} {
set status $msg
method stop {{stop_msg {}}} {
if {$is_active} {
set is_active 0
$status_bar stop $this $stop_msg
}
}
method show {msg {test {}}} {
if {$test eq {} || $status eq $test} {
set status $msg
}
method restart {msg} {
if {!$is_active} { return }
set status $msg
set prefix $msg
set meter {}
$status_bar refresh
}
method _delete {current} {
if {$current eq $w} {
delete_this
}
method _delete {} {
stop
delete_this
}
}

View file

@ -1,6 +1,44 @@
# Functions for supporting the use of themed Tk widgets in git-gui.
# Copyright (C) 2009 Pat Thoyts <patthoyts@users.sourceforge.net>
namespace eval color {
# Variable colors
# Preffered way to set widget colors is using add_option.
# In some cases, like with tags in_diff/in_sel, we use these colors.
variable select_bg lightgray
variable select_fg black
proc sync_with_theme {} {
set base_bg [ttk::style lookup . -background]
set base_fg [ttk::style lookup . -foreground]
set text_bg [ttk::style lookup Treeview -background]
set text_fg [ttk::style lookup Treeview -foreground]
set select_bg [ttk::style lookup Default -selectbackground]
set select_fg [ttk::style lookup Default -selectforeground]
set color::select_bg $select_bg
set color::select_fg $select_fg
proc add_option {key val} {
option add $key $val widgetDefault
}
# Add options for plain Tk widgets
# Using `option add` instead of tk_setPalette to avoid unintended
# consequences.
if {![is_MacOSX]} {
add_option *Menu.Background $base_bg
add_option *Menu.Foreground $base_fg
add_option *Menu.activeBackground $select_bg
add_option *Menu.activeForeground $select_fg
}
add_option *Text.Background $text_bg
add_option *Text.Foreground $text_fg
add_option *Text.HighlightBackground $base_bg
add_option *Text.HighlightColor $select_bg
}
}
proc ttk_get_current_theme {} {
# Handle either current Tk or older versions of 8.5
if {[catch {set theme [ttk::style theme use]}]} {

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -6,10 +6,11 @@
msgid ""
msgstr ""
"Project-Id-Version: git-gui glossary\n"
"POT-Creation-Date: 2008-01-07 21:20+0100\n"
"PO-Revision-Date: 2008-02-16 21:48+0100\n"
"POT-Creation-Date: 2020-01-26 22:26+0100\n"
"PO-Revision-Date: 2020-02-09 21:22+0100\n"
"Last-Translator: Christian Stimming <stimming@tuhh.de>\n"
"Language-Team: German \n"
"Language: de_DE\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@ -19,6 +20,9 @@ msgid ""
"English Term (Dear translator: This file will never be visible to the user!)"
msgstr ""
"Deutsche Übersetzung.\n"
"Git-core glossary:\n"
" https://github.com/ruester/git-po-de/wiki/Translation-Guidelines\n"
"\n"
"Andere deutsche SCM:\n"
" http://tortoisesvn.net/docs/release/TortoiseSVN_de/index.html und http://"
"tortoisesvn.tigris.org/svn/tortoisesvn/trunk/Languages/Tortoise_de.po "
@ -32,33 +36,77 @@ msgstr ""
" http://rapidsvn.tigris.org/svn/rapidsvn/trunk/src/locale/de/rapidsvn.po "
"(username=guest, password empty, schlecht)"
#. "prematurely stop and abandon an operation"
msgid "abort"
msgstr "abbrechen"
#. ""
msgid "amend"
msgstr "nachbessern (ergänzen)"
#. "a commit that succeeds the current one in git's graph of commits (not necessarily directly)"
msgid "ancestor"
msgstr "Vorgänger-Commit"
#. ""
msgid "annotate"
msgstr "annotieren"
#. "The person who initially created (authored) a commit"
msgid "author"
msgstr "Autor"
#. "a repository with only .git directory, without working directory"
msgid "bare repository"
msgstr "bloßes Projektarchiv"
#. "a parent version of the current file"
msgid "base"
msgstr "Ursprung"
#. ""
msgid "bisect"
msgstr "binäre Suche [noun], binäre Suche benutzen [verb]"
#. "get the authors responsible for each line in a file"
msgid "blame"
msgstr "annotieren"
#. ""
msgid "blob"
msgstr "Blob"
#. "A 'branch' is an active line of development."
msgid "branch [noun]"
msgstr "Zweig"
msgstr "Branch"
#. ""
msgid "branch [verb]"
msgstr "verzweigen"
msgstr "branchen"
#. ""
msgid "checkout [noun]"
msgstr ""
"Arbeitskopie (Erstellung einer Arbeitskopie; Auscheck? Ausspielung? Abruf? "
"Source Safe: Auscheckvorgang)"
"Arbeitskopie (Checkout; Erstellung einer Arbeitskopie; Auscheck? Source "
"Safe: Auscheckvorgang)"
#. "The action of updating the working tree to a revision which was stored in the object database."
msgid "checkout [verb]"
msgstr ""
"Arbeitskopie erstellen; Zweig umstellen [checkout a branch] (auschecken? "
"ausspielen? abrufen? Source Safe: auschecken)"
"Arbeitskopie erstellen; Branch auschecken [checkout a branch] (umstellen? "
"Source Safe: auschecken)"
#. "to select and apply a single commit to the current HEAD without merging"
msgid "cherry-pick"
msgstr "cherry-pick (pflücken?)"
#. "a commit that directly succeeds the current one in git's graph of commits"
msgid "child commit"
msgstr "Kind-Commit"
#. "clean the state of the git repository, often after manually stopped operation"
msgid "cleanup"
msgstr "aufräumen"
#. ""
msgid "clone [verb]"
@ -66,39 +114,98 @@ msgstr "klonen"
#. "A single point in the git history."
msgid "commit [noun]"
msgstr ""
"Version; Eintragung; Änderung (Buchung?, Eintragung?, Übertragung?, "
"Sendung?, Übergabe?, Einspielung?, Ablagevorgang?)"
msgstr "Commit (Version?)"
#. "The action of storing a new snapshot of the project's state in the git history."
msgid "commit [verb]"
msgstr ""
"eintragen (TortoiseSVN: übertragen; Source Safe: einchecken; senden?, "
"übergeben?, einspielen?, einpflegen?, ablegen?)"
"committen (eintragen?, TortoiseSVN: übertragen; Source Safe: einchecken)"
#. "a message that gets attached with any commit"
msgid "commit message"
msgstr "Commit-Beschreibung (Meldung?, Nachricht?; Source Safe: Kommentar)"
#. "The person who committed a commit (to the current branch), which might be different than the author."
msgid "committer"
msgstr "Committer"
#. "a commit that precedes the current one in git's graph of commits (not necessarily directly)"
msgid "descendant"
msgstr "Nachfolger-Commit"
#. "checkout of a revision rather than some head"
msgid "detached HEAD"
msgstr "losgelöster HEAD / Branchspitze"
#. "checkout of a revision rather than some head"
msgid "detached checkout"
msgstr "losgelöster Commit (von Branch losgelöster Commit?)"
#. ""
msgid "diff [noun]"
msgstr "Vergleich (Source Safe: Unterschiede)"
msgstr "Vergleich (Diff? Source Safe: Unterschiede)"
#. ""
msgid "diff [verb]"
msgstr "vergleichen"
#. "A fast-forward is a special type of merge where you have a revision and you are merging another branch's changes that happen to be a descendant of what you have."
msgid "fast forward merge"
msgstr "Schnellzusammenführung"
#. ""
msgid "directory"
msgstr "Verzeichnis"
#. "A fast-forward merge is a special type of merge where you have a revision and you are merging another branch's changes that happen to be a descendant of what you have."
msgid "fast-forward"
msgstr "vorspulen"
#. "Fetching a branch means to get the branch's head from a remote repository, to find out which objects are missing from the local object database, and to get them, too."
msgid "fetch"
msgstr "anfordern (holen?)"
#. "any merge strategy that works on a file by file basis"
msgid "file level merging"
msgstr "Datei-basiertes zusammenführen"
#. ""
msgid "file"
msgstr "Datei"
#. "the last revision in a branch"
msgid "head"
msgstr "HEAD / Branchspitze"
#. "script that gets executed automatically on some event"
msgid "hook"
msgstr "Hook (in der dt. Informatik wohl als Einschubmethode bezeichnet)"
#. "One context of consecutive lines in a whole patch, which consists of many such hunks"
msgid "hunk"
msgstr "Kontext"
msgstr "Patch-Block (Kontext?)"
#. "A collection of files. The index is a stored version of your working tree."
msgid "index (in git-gui: staging area)"
msgstr "Bereitstellung"
msgstr ""
"Bereitstellung (sofern der git index gemeint ist. In git-gui sowieso: "
"staging area)"
#. "the first checkout during a clone operation"
msgid "initial checkout"
msgstr "Erstellen der Arbeitskopie, auschecken"
#. "The very first commit in a repository"
msgid "initial commit"
msgstr "Allererster Commit"
#. "a branch that resides in the local git repository"
msgid "local branch"
msgstr "Lokaler Branch"
#. "a Git object that is not part of any pack"
msgid "loose object"
msgstr "loses Objekt"
#. "a branch called by convention 'master' that exists in a newly created git repository"
msgid "master branch"
msgstr "Master-Branch"
#. "A successful merge results in the creation of a new commit representing the result of the merge."
msgid "merge [noun]"
@ -112,78 +219,212 @@ msgstr "zusammenführen"
msgid "message"
msgstr "Beschreibung (Meldung?, Nachricht?; Source Safe: Kommentar)"
#. "Deletes all stale tracking branches under <name>. These stale branches have already been removed from the remote repository referenced by <name>, but are still locally available in 'remotes/<name>'."
#. "a remote called by convention 'origin' that the current git repository has been cloned from"
msgid "origin"
msgstr "origin"
#. ""
msgid "orphan commit"
msgstr "verwaister Commit"
#. ""
msgid "orphan reference"
msgstr "verwaiste Referenz"
#. "a file containing many git objects packed together"
msgid "pack [noun]"
msgstr "Pack-Datei"
#. "the process of creating a pack file"
msgid "pack [verb]"
msgstr "Pack-Datei erstellen"
#. "a Git object part of some pack"
msgid "packed object"
msgstr "gepacktes Objekt"
#. "a commit that directly precedes the current one in git's graph of commits"
msgid "parent commit"
msgstr "Eltern-Commit"
msgid "patch"
msgstr "Patch"
#. "The path to a file"
msgid "path"
msgstr "Pfad"
#. "Delete all stale tracking branches under <name>. These stale branches have already been removed from the remote repository referenced by <name>, but are still locally available in 'remotes/<name>'."
msgid "prune"
msgstr "aufräumen (entfernen?)"
msgstr "veraltete Branches entfernen (aufräumen?, entfernen?)"
#. "Pulling a branch means to fetch it and merge it."
msgid "pull"
msgstr "übernehmen (ziehen?)"
msgstr ""
"übernehmen (pull? ziehen? Vorsicht: zusammenführen = merge, aber pull kann "
"auch rebase bewirken)"
#. "Pushing a branch means to get the branch's head ref from a remote repository, and ... (well, can someone please explain it for mere mortals?)"
msgid "push"
msgstr "versenden (ausliefern? hochladen? verschicken? schieben?)"
#. "The process of rebasing one set of commits on top of another branch's head"
msgid "rebase [noun]"
msgstr "der Rebase (das Umpflanzen)"
#. "Re-apply one set of commits on top of another branch's head. Contrary to merge."
msgid "rebase [verb]"
msgstr "rebase (umpflanzen)"
#. ""
msgid "redo"
msgstr "wiederholen"
#. "An other repository ('remote'). One might have a set of remotes whose branches one tracks."
msgid "remote"
msgstr "Andere Archive (Gegenseite?, Entfernte?, Server?)"
#. ""
msgid "reference"
msgstr "Referenz"
#. "the log file containing all states of the HEAD reference (in other words past pristine states of the working copy)"
msgid "reflog"
msgstr "Commit-Log, »reflog«"
msgid "refmap"
msgstr "Refmap"
#. ""
msgid "refspec"
msgstr "Refspec"
#. "The adjective for anything which is outside of the current (local) repository"
msgid "remote [adj]"
msgstr "Extern (Andere?, Gegenseite?, Entfernte?, Server?)"
#. "A branch in any other ('remote') repository"
msgid "remote branch"
msgstr "Externer branch"
#. "An other repository ('remote'). One might have a set of remotes whose branches one tracks."
msgid "remote repository"
msgstr "Externes Repository"
#. "A collection of refs (?) together with an object database containing all objects which are reachable from the refs... (oops, you've lost me here. Again, please an explanation for mere mortals?)"
msgid "repository"
msgstr "Projektarchiv"
msgstr "Repository"
#. ""
msgid "reset"
msgstr "zurücksetzen (zurückkehren?)"
msgstr "umsetzen (reset to commit), Änderungen verwerfen (reset to HEAD)"
#. "decide which changes from alternative versions of a file should persist in Git"
msgid "resolve (a conflict)"
msgstr "auflösen (einen Konflikt)"
#. "abandon changes and go to pristine version"
msgid "revert changes"
msgstr ""
"verwerfen (bei git-reset bzw. checkout), zurücknehmen (bei git-revert, also "
"mit neuem commit; umkehren?)"
#. ""
msgid "revert"
msgstr "verwerfen (bei git-reset), revidieren (bei git-revert, also mit neuem commit)"
msgstr ""
"verwerfen (bei git-reset bzw. checkout), zurücknehmen (bei git-revert, also "
"mit neuem commit; umkehren?)"
#. "expression that signifies a revision in git"
msgid "revision expression"
msgstr "Version Regexp-Ausdruck"
#. "A particular state of files and directories which was stored in the object database."
msgid "revision"
msgstr "Version (TortoiseSVN: Revision; Source Safe: Version)"
msgstr ""
"Version (aber was macht das Wort revision hier im Git?? TortoiseSVN: "
"Revision; Source Safe: Version)"
#. ""
msgid "sign off"
msgstr "abzeichnen (gegenzeichnen?, freizeichnen?, absegnen?)"
msgstr "abzeichnen (signieren? gegenzeichnen?, freizeichnen?)"
#. ""
#. "see: staging area. In some areas of git this is called 'index'."
msgid "stage [noun], index"
msgstr "Bereitstellung"
#. "add some content of files and directories to the staging area in preparation for a commit"
msgid "stage [verb]"
msgstr "bereitstellen"
#. "The place where changes from files are marked to be included for the next commit. In some areas of git this is called 'index'."
msgid "staging area"
msgstr "Bereitstellung"
#. "The place (stack) where changes can be temporarily saved without committing"
msgid "stash [noun]"
msgstr "der Stash"
#. "temporarily save changes in a stack without committing"
msgid "stash [verb]"
msgstr "in Stash speichern; \"stash\" benutzen"
#. ""
msgid "status"
msgstr "Status"
#. "A ref pointing to a tag or commit object"
msgid "tag [noun]"
msgstr "Markierung"
#. ""
msgid "submodule"
msgstr "Submodul (Untermodul?)"
#. "A ref pointing to some commit object. In other words: A label on a specific commit."
msgid "tag [noun]"
msgstr "Tag (Markierung?)"
#. "The process of creating a tag at a specific commit object"
msgid "tag [verb]"
msgstr "markieren"
msgstr "taggen (markieren?)"
#. "The person who created a tag"
msgid "tagger"
msgstr "Tag-Ersteller (Markierungs-Ersteller?)"
#. "file whose content is tracked/not tracked by git"
msgid "tracked/untracked"
msgstr "versioniert/unversioniert"
#. "A regular git branch that is used to follow changes from another repository."
msgid "tracking branch"
msgstr "Übernahmezweig"
msgstr "Tracking-Branch (Verfolgungsbranch? Übernahmebranch?)"
#. ""
msgid "trailer"
msgstr "Anhang"
#. "1. tree object, 2. directory tree"
msgid "tree"
msgstr "1. Baum-Objekt, 2. Verzeichnisbaum"
#. ""
msgid "undo"
msgstr "rückgängig"
#. "Remove content of files from the staging area again so that it will not be part of the next commit"
msgid "unstage"
msgstr "aus Bereitstellung herausnehmen"
#. "Retrieving the temporarily saved changes back again from the stash"
msgid "unstash [verb]"
msgstr "aus Stash zurückladen"
#. ""
msgid "update"
msgstr "aktualisieren"
#. ""
msgid "upstream branch"
msgstr "Upstream-Branch"
#. ""
msgid "verify"
msgstr "überprüfen"
#. "The tree of actual checked out files."
msgid "working copy, working tree"
msgid "working directory, working copy, working tree"
msgstr "Arbeitskopie"

View file

@ -6,7 +6,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2008-01-07 21:20+0100\n"
"POT-Creation-Date: 2020-01-26 22:26+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -18,14 +18,46 @@ msgstr ""
msgid "English Term (Dear translator: This file will never be visible to the user!)"
msgstr ""
#. "prematurely stop and abandon an operation"
msgid "abort"
msgstr ""
#. ""
msgid "amend"
msgstr ""
#. "a commit that succeeds the current one in git's graph of commits (not necessarily directly)"
msgid "ancestor"
msgstr ""
#. ""
msgid "annotate"
msgstr ""
#. "The person who initially created (authored) a commit"
msgid "author"
msgstr ""
#. "a repository with only .git directory, without working directory"
msgid "bare repository"
msgstr ""
#. "a parent version of the current file"
msgid "base"
msgstr ""
#. ""
msgid "bisect"
msgstr ""
#. "get the authors responsible for each line in a file"
msgid "blame"
msgstr ""
#. ""
msgid "blob"
msgstr ""
#. "A 'branch' is an active line of development."
msgid "branch [noun]"
msgstr ""
@ -42,6 +74,18 @@ msgstr ""
msgid "checkout [verb]"
msgstr ""
#. "to select and apply a single commit to the current HEAD without merging"
msgid "cherry-pick"
msgstr ""
#. "a commit that directly succeeds the current one in git's graph of commits"
msgid "child commit"
msgstr ""
#. "clean the state of the git repository, often after manually stopped operation"
msgid "cleanup"
msgstr ""
#. ""
msgid "clone [verb]"
msgstr ""
@ -54,6 +98,26 @@ msgstr ""
msgid "commit [verb]"
msgstr ""
#. "a message that gets attached with any commit"
msgid "commit message"
msgstr ""
#. "The person who committed a commit (to the current branch), which might be different than the author."
msgid "committer"
msgstr ""
#. "a commit that precedes the current one in git's graph of commits (not necessarily directly)"
msgid "descendant"
msgstr ""
#. "checkout of a revision rather than some head"
msgid "detached HEAD"
msgstr ""
#. "checkout of a revision rather than some head"
msgid "detached checkout"
msgstr ""
#. ""
msgid "diff [noun]"
msgstr ""
@ -62,14 +126,34 @@ msgstr ""
msgid "diff [verb]"
msgstr ""
#. "A fast-forward is a special type of merge where you have a revision and you are merging another branch's changes that happen to be a descendant of what you have."
msgid "fast forward merge"
#. ""
msgid "directory"
msgstr ""
#. "A fast-forward merge is a special type of merge where you have a revision and you are merging another branch's changes that happen to be a descendant of what you have."
msgid "fast-forward"
msgstr ""
#. "Fetching a branch means to get the branch's head from a remote repository, to find out which objects are missing from the local object database, and to get them, too."
msgid "fetch"
msgstr ""
#. "any merge strategy that works on a file by file basis"
msgid "file level merging"
msgstr ""
#. ""
msgid "file"
msgstr ""
#. "the last revision in a branch"
msgid "head"
msgstr ""
#. "script that gets executed automatically on some event"
msgid "hook"
msgstr ""
#. "One context of consecutive lines in a whole patch, which consists of many such hunks"
msgid "hunk"
msgstr ""
@ -78,6 +162,26 @@ msgstr ""
msgid "index (in git-gui: staging area)"
msgstr ""
#. "the first checkout during a clone operation"
msgid "initial checkout"
msgstr ""
#. "The very first commit in a repository"
msgid "initial commit"
msgstr ""
#. "a branch that resides in the local git repository"
msgid "local branch"
msgstr ""
#. "a Git object that is not part of any pack"
msgid "loose object"
msgstr ""
#. "a branch called by convention 'master' that exists in a newly created git repository"
msgid "master branch"
msgstr ""
#. "A successful merge results in the creation of a new commit representing the result of the merge."
msgid "merge [noun]"
msgstr ""
@ -90,7 +194,42 @@ msgstr ""
msgid "message"
msgstr ""
#. "Deletes all stale tracking branches under <name>. These stale branches have already been removed from the remote repository referenced by <name>, but are still locally available in 'remotes/<name>'."
#. "a remote called by convention 'origin' that the current git repository has been cloned from"
msgid "origin"
msgstr ""
#. ""
msgid "orphan commit"
msgstr ""
#. ""
msgid "orphan reference"
msgstr ""
#. "a file containing many git objects packed together"
msgid "pack [noun]"
msgstr ""
#. "the process of creating a pack file"
msgid "pack [verb]"
msgstr ""
#. "a Git object part of some pack"
msgid "packed object"
msgstr ""
#. "a commit that directly precedes the current one in git's graph of commits"
msgid "parent commit"
msgstr ""
msgid "patch" ""
msgstr ""
#. "The path to a file"
msgid "path"
msgstr ""
#. "Delete all stale tracking branches under <name>. These stale branches have already been removed from the remote repository referenced by <name>, but are still locally available in 'remotes/<name>'."
msgid "prune"
msgstr ""
@ -102,12 +241,43 @@ msgstr ""
msgid "push"
msgstr ""
#. "The process of rebasing one set of commits on top of another branch's head"
msgid "rebase [noun]"
msgstr ""
#. "Re-apply one set of commits on top of another branch's head. Contrary to merge."
msgid "rebase [verb]"
msgstr ""
#. ""
msgid "redo"
msgstr ""
#. "An other repository ('remote'). One might have a set of remotes whose branches one tracks."
msgid "remote"
#. ""
msgid "reference"
msgstr ""
#. "the log file containing all states of the HEAD reference (in other words past pristine states of the working copy)"
msgid "reflog"
msgstr ""
msgid "refmap" ""
msgstr ""
#. ""
msgid "refspec"
msgstr ""
#. "The adjective for anything which is outside of the current (local) repository"
msgid "remote [adj]"
msgstr ""
#. "A branch in any other ('remote') repository"
msgid "remote branch"
msgstr ""
#. "An other repository ('remote'). One might have a set of remotes whose branches one tracks."
msgid "remote repository"
msgstr ""
#. "A collection of refs (?) together with an object database containing all objects which are reachable from the refs... (oops, you've lost me here. Again, please an explanation for mere mortals?)"
@ -118,10 +288,22 @@ msgstr ""
msgid "reset"
msgstr ""
#. "decide which changes from alternative versions of a file should persist in Git"
msgid "resolve (a conflict)"
msgstr ""
#. "abandon changes and go to pristine version"
msgid "revert changes"
msgstr ""
#. ""
msgid "revert"
msgstr ""
#. "expression that signifies a revision in git"
msgid "revision expression"
msgstr ""
#. "A particular state of files and directories which was stored in the object database."
msgid "revision"
msgstr ""
@ -130,39 +312,87 @@ msgstr ""
msgid "sign off"
msgstr ""
#. ""
#. "see: staging area. In some areas of git this is called 'index'."
msgid "stage [noun], index"
msgstr ""
#. "add some content of files and directories to the staging area in preparation for a commit"
msgid "stage [verb]"
msgstr ""
#. "The place where changes from files are marked to be included for the next commit. In some areas of git this is called 'index'."
msgid "staging area"
msgstr ""
#. "The place (stack) where changes can be temporarily saved without committing"
msgid "stash [noun]"
msgstr ""
#. "temporarily save changes in a stack without committing"
msgid "stash [verb]"
msgstr ""
#. ""
msgid "status"
msgstr ""
#. "A ref pointing to a tag or commit object"
#. ""
msgid "submodule"
msgstr ""
#. "A ref pointing to some commit object. In other words: A label on a specific commit."
msgid "tag [noun]"
msgstr ""
#. ""
#. "The process of creating a tag at a specific commit object"
msgid "tag [verb]"
msgstr ""
#. "The person who created a tag"
msgid "tagger"
msgstr ""
#. "file whose content is tracked/not tracked by git"
msgid "tracked/untracked"
msgstr ""
#. "A regular git branch that is used to follow changes from another repository."
msgid "tracking branch"
msgstr ""
#. ""
msgid "trailer"
msgstr ""
#. "1. tree object, 2. directory tree"
msgid "tree"
msgstr ""
#. ""
msgid "undo"
msgstr ""
#. "Remove content of files from the staging area again so that it will not be part of the next commit"
msgid "unstage"
msgstr ""
#. "Retrieving the temporarily saved changes back again from the stash"
msgid "unstash [verb]"
msgstr ""
#. ""
msgid "update"
msgstr ""
#. ""
msgid "upstream branch"
msgstr ""
#. ""
msgid "verify"
msgstr ""
#. "The tree of actual checked out files."
msgid "working copy, working tree"
msgid "working directory, working copy, working tree"
msgstr ""

View file

@ -1,67 +1,96 @@
"English Term (Dear translator: This file will never be visible to the user!)" "English Definition (Dear translator: This file will never be visible to the user! It should only serve as a tool for you, the translator. Nothing more.)"
"abort" "prematurely stop and abandon an operation"
"amend" ""
"ancestor" "a commit that succeeds the current one in git's graph of commits (not necessarily directly)"
"annotate" ""
"author" "The person who initially created (authored) a commit"
"bare repository" "a repository with only .git directory, without working directory"
"base" "a parent version of the current file"
"bisect" ""
"blame" "get the authors responsible for each line in a file"
"blob" ""
"branch [noun]" "A 'branch' is an active line of development."
"branch [verb]" ""
"checkout [noun]" ""
"checkout [verb]" "The action of updating the working tree to a revision which was stored in the object database."
"cherry-pick" "to select and apply a single commit to the current HEAD without merging"
"child commit" "a commit that directly succeeds the current one in git's graph of commits"
"cleanup" "clean the state of the git repository, often after manually stopped operation"
"clone [verb]" ""
"commit [noun]" "A single point in the git history."
"commit [verb]" "The action of storing a new snapshot of the project's state in the git history."
"commit message" "a message that gets attached with any commit"
"committer" "The person who committed a commit (to the current branch), which might be different than the author."
"descendant" "a commit that precedes the current one in git's graph of commits (not necessarily directly)"
"detached HEAD" "checkout of a revision rather than some head"
"detached checkout" "checkout of a revision rather than some head"
"diff [noun]" ""
"diff [verb]" ""
"fast forward merge" "A fast-forward is a special type of merge where you have a revision and you are merging another branch's changes that happen to be a descendant of what you have."
"directory" ""
"fast-forward" "A fast-forward merge is a special type of merge where you have a revision and you are merging another branch's changes that happen to be a descendant of what you have."
"fetch" "Fetching a branch means to get the branch's head from a remote repository, to find out which objects are missing from the local object database, and to get them, too."
"hunk" "One context of consecutive lines in a whole patch, which consists of many such hunks"
"index (in git-gui: staging area)" "A collection of files. The index is a stored version of your working tree."
"merge [noun]" "A successful merge results in the creation of a new commit representing the result of the merge."
"merge [verb]" "To bring the contents of another branch into the current branch."
"message" ""
"prune" "Deletes all stale tracking branches under <name>. These stale branches have already been removed from the remote repository referenced by <name>, but are still locally available in 'remotes/<name>'."
"pull" "Pulling a branch means to fetch it and merge it."
"push" "Pushing a branch means to get the branch's head ref from a remote repository, and ... (well, can someone please explain it for mere mortals?)"
"redo" ""
"remote" "An other repository ('remote'). One might have a set of remotes whose branches one tracks."
"repository" "A collection of refs (?) together with an object database containing all objects which are reachable from the refs... (oops, you've lost me here. Again, please an explanation for mere mortals?)"
"reset" ""
"revert" ""
"revision" "A particular state of files and directories which was stored in the object database."
"sign off" ""
"staging area" ""
"status" ""
"tag [noun]" "A ref pointing to a tag or commit object"
"tag [verb]" ""
"tracking branch" "A regular git branch that is used to follow changes from another repository."
"undo" ""
"update" ""
"verify" ""
"working copy, working tree" "The tree of actual checked out files."
"ancestor" "a commit that succeeds the current one in git's graph of commits (not necessarily directly)"
"abort" "prematurely stop and abandon an operation"
"bare repository" "a repository with only .git directory, without working directory"
"base" "a parent version of the current file"
"blame" "get the authors responsible for each line in a file"
"cherry-pick" "to select and apply a single commit without merging"
"child" "a commit that directly succeeds the current one in git's graph of commits"
"cleanup" "clean the state of the git repository, often after manually stopped operation"
"commit message" "a message that gets attached with any commit"
"descendant" "a commit that precedes the current one in git's graph of commits (not necessarily directly)"
"detached checkout" "checkout of a revision rather than a some head"
"file level merging" "any merge strategy that works on a file by file basis"
"file" ""
"head" "the last revision in a branch"
"hook" "script that gets executed automatically on some event"
"hunk" "One context of consecutive lines in a whole patch, which consists of many such hunks"
"index (in git-gui: staging area)" "A collection of files. The index is a stored version of your working tree."
"initial checkout" "the first checkout during a clone operation"
"initial commit" "The very first commit in a repository"
"local branch" "a branch that resides in the local git repository"
"loose object" "a Git object that is not part of any pack"
"master branch" "a branch called by convention 'master' that exists in a newly created git repository"
"merge [noun]" "A successful merge results in the creation of a new commit representing the result of the merge."
"merge [verb]" "To bring the contents of another branch into the current branch."
"message" ""
"origin" "a remote called by convention 'origin' that the current git repository has been cloned from"
"orphan commit" ""
"orphan reference" ""
"pack [noun]" "a file containing many git objects packed together"
"pack [verb]" "the process of creating a pack file"
"packed object" "a Git object part of some pack"
"parent" "a commit that directly precedes the current one in git's graph of commits"
"parent commit" "a commit that directly precedes the current one in git's graph of commits"
"patch" ""
"path" "The path to a file"
"prune" "Delete all stale tracking branches under <name>. These stale branches have already been removed from the remote repository referenced by <name>, but are still locally available in 'remotes/<name>'."
"pull" "Pulling a branch means to fetch it and merge it."
"push" "Pushing a branch means to get the branch's head ref from a remote repository, and ... (well, can someone please explain it for mere mortals?)"
"rebase [noun]" "The process of rebasing one set of commits on top of another branch's head"
"rebase [verb]" "Re-apply one set of commits on top of another branch's head. Contrary to merge."
"redo" ""
"reference" ""
"reflog" "the log file containing all states of the HEAD reference (in other words past pristine states of the working copy)"
"refmap" ""
"refspec" ""
"remote [adj]" "The adjective for anything which is outside of the current (local) repository"
"remote branch" "A branch in any other ('remote') repository"
"remote repository" "An other repository ('remote'). One might have a set of remotes whose branches one tracks."
"repository" "A collection of refs (?) together with an object database containing all objects which are reachable from the refs... (oops, you've lost me here. Again, please an explanation for mere mortals?)"
"reset" ""
"resolve (a conflict)" "decide which changes from alternative versions of a file should persist in Git"
"revert changes" "abandon changes and go to pristine version"
"revert" ""
"revision expression" "expression that signifies a revision in git"
"stage/unstage" "add some content of files and directories to the staging area in preparation for a commit"
"stash" "temporarily save changes in a stack without committing"
"revision" "A particular state of files and directories which was stored in the object database."
"sign off" ""
"stage [noun], index" "see: staging area. In some areas of git this is called 'index'."
"stage [verb]" "add some content of files and directories to the staging area in preparation for a commit"
"staging area" "The place where changes from files are marked to be included for the next commit. In some areas of git this is called 'index'."
"stash [noun]" "The place (stack) where changes can be temporarily saved without committing"
"stash [verb]" "temporarily save changes in a stack without committing"
"status" ""
"submodule" ""
"tag [noun]" "A ref pointing to some commit object. In other words: A label on a specific commit."
"tag [verb]" "The process of creating a tag at a specific commit object"
"tagger" "The person who created a tag"
"tracked/untracked" "file whose content is tracked/not tracked by git"
"tracking branch" "A regular git branch that is used to follow changes from another repository."
"trailer" ""
"tree" "1. tree object, 2. directory tree"
"undo" ""
"unstage" "Remove content of files from the staging area again so that it will not be part of the next commit"
"unstash [verb]" "Retrieving the temporarily saved changes back again from the stash"
"update" ""
"upstream branch" ""
"verify" ""
"working directory, working copy, working tree" "The tree of actual checked out files."

View file

@ -4,14 +4,15 @@
#
# しらいし ななこ <nanako3@bluebottle.com>, 2007.
# Satoshi Yasushima <s.yasushima@gmail.com>, 2016.
# KIDANI Akito <a.kid.1985@gmail.com>, 2019.
#
msgid ""
msgstr ""
"Project-Id-Version: git-gui\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-05-27 17:52+0900\n"
"PO-Revision-Date: 2016-06-22 12:50+0900\n"
"Last-Translator: Satoshi Yasushima <s.yasushima@gmail.com>\n"
"PO-Revision-Date: 2019-10-13 23:20+0900\n"
"Last-Translator: KIDANI Akito <a.kid.1985@gmail.com>\n"
"Language-Team: Japanese\n"
"Language: ja\n"
"MIME-Version: 1.0\n"
@ -661,7 +662,7 @@ msgstr ""
#: lib/merge.tcl:108
#, tcl-format
msgid "%s of %s"
msgstr "%s の %s ブランチ"
msgstr "%2$s の %1$s ブランチ"
#: lib/merge.tcl:122
#, tcl-format
@ -956,7 +957,7 @@ msgstr "エラー: コマンドが失敗しました"
#: lib/checkout_op.tcl:85
#, tcl-format
msgid "Fetching %s from %s"
msgstr "%s から %s をフェッチしています"
msgstr "%2$s から %1$s をフェッチしています"
#: lib/checkout_op.tcl:133
#, tcl-format