summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Documentation/RelNotes/2.29.0.txt76
-rw-r--r--Documentation/config.txt4
-rw-r--r--Documentation/config/commitgraph.txt8
-rw-r--r--Documentation/config/feature.txt4
-rw-r--r--Documentation/config/fmt-merge-msg.txt2
-rw-r--r--Documentation/config/maintenance.txt16
-rw-r--r--Documentation/config/protocol.txt3
-rw-r--r--Documentation/config/receive.txt22
-rw-r--r--Documentation/config/uploadpack.txt2
-rw-r--r--Documentation/fetch-options.txt6
-rw-r--r--Documentation/git-clone.txt6
-rw-r--r--Documentation/git-commit-graph.txt7
-rw-r--r--Documentation/git-mailinfo.txt7
-rw-r--r--Documentation/git-maintenance.txt79
-rw-r--r--Documentation/git-shortlog.txt31
-rw-r--r--Documentation/gitfaq.txt86
-rw-r--r--Documentation/githooks.txt62
-rw-r--r--Documentation/technical/commit-graph-format.txt2
-rw-r--r--Documentation/technical/pack-protocol.txt41
-rw-r--r--Documentation/technical/protocol-capabilities.txt17
-rw-r--r--Makefile68
-rw-r--r--bisect.c13
-rw-r--r--blame.c8
-rw-r--r--bloom.c59
-rw-r--r--bloom.h29
-rw-r--r--builtin.h1
-rw-r--r--builtin/am.c2
-rw-r--r--builtin/bisect--helper.c282
-rw-r--r--builtin/blame.c27
-rw-r--r--builtin/clone.c2
-rw-r--r--builtin/commit-graph.c63
-rw-r--r--builtin/commit.c2
-rw-r--r--builtin/diff.c3
-rw-r--r--builtin/fast-export.c10
-rw-r--r--builtin/fetch.c6
-rw-r--r--builtin/gc.c337
-rw-r--r--builtin/init-db.c6
-rw-r--r--builtin/log.c1
-rw-r--r--builtin/merge.c2
-rw-r--r--builtin/pull.c3
-rw-r--r--builtin/rebase.c4
-rw-r--r--builtin/receive-pack.c472
-rw-r--r--builtin/send-pack.c19
-rw-r--r--builtin/shortlog.c213
-rw-r--r--cache.h2
-rwxr-xr-xci/lib.sh1
-rw-r--r--combine-diff.c21
-rw-r--r--command-list.txt1
-rw-r--r--commit-graph.c149
-rw-r--r--commit-graph.h18
-rw-r--r--commit-reach.c8
-rw-r--r--compat/bswap.h24
-rw-r--r--contrib/completion/git-completion.bash73
-rw-r--r--contrib/diff-highlight/DiffHighlight.pm2
-rwxr-xr-xcontrib/mw-to-git/git-mw.perl2
-rwxr-xr-xcontrib/mw-to-git/git-remote-mediawiki.perl80
-rw-r--r--contrib/mw-to-git/git-remote-mediawiki.txt2
-rw-r--r--contrib/mw-to-git/t/.gitignore2
-rw-r--r--contrib/mw-to-git/t/README10
-rw-r--r--contrib/mw-to-git/t/install-wiki/.gitignore1
-rw-r--r--contrib/mw-to-git/t/install-wiki/LocalSettings.php129
-rw-r--r--contrib/mw-to-git/t/install-wiki/db_install.php120
-rwxr-xr-xcontrib/mw-to-git/t/t9360-mw-to-git-clone.sh8
-rwxr-xr-xcontrib/mw-to-git/t/t9363-mw-to-git-export-import.sh9
-rwxr-xr-xcontrib/mw-to-git/t/test-gitmw-lib.sh162
-rwxr-xr-xcontrib/mw-to-git/t/test-gitmw.pl22
-rw-r--r--contrib/mw-to-git/t/test.config23
-rw-r--r--diff-lib.c6
-rw-r--r--diff.c12
-rw-r--r--diff.h8
-rw-r--r--fuzz-commit-graph.c5
-rwxr-xr-xgit-bisect.sh70
-rwxr-xr-xgit-p4.py2
-rw-r--r--git.c1
-rwxr-xr-xgitk-git/gitk10654
-rw-r--r--line-log.c2
-rw-r--r--log-tree.c2
-rw-r--r--object.h1
-rw-r--r--oidset.c9
-rw-r--r--oidset.h9
-rw-r--r--pack-write.c12
-rw-r--r--packfile.c48
-rw-r--r--protocol.c6
-rw-r--r--ref-filter.c8
-rw-r--r--remote.h9
-rw-r--r--repo-settings.c3
-rw-r--r--repository.h1
-rw-r--r--revision.c7
-rw-r--r--run-command.c16
-rw-r--r--run-command.h2
-rw-r--r--send-pack.c159
-rw-r--r--sequencer.c11
-rw-r--r--shortlog.h8
-rw-r--r--submodule.c3
-rw-r--r--t/helper/test-bloom.c4
-rw-r--r--t/helper/test-proc-receive.c176
-rw-r--r--t/helper/test-reach.c2
-rw-r--r--t/helper/test-read-graph.c3
-rw-r--r--t/helper/test-tool.c1
-rw-r--r--t/helper/test-tool.h1
-rwxr-xr-xt/t0095-bloom.sh8
-rwxr-xr-xt/t1506-rev-parse-diagnosis.sh18
-rwxr-xr-xt/t3200-branch.sh34
-rwxr-xr-xt/t3206-range-diff.sh12
-rwxr-xr-xt/t3427-rebase-subtree.sh42
-rwxr-xr-xt/t4150-am.sh8
-rwxr-xr-xt/t4201-shortlog.sh141
-rwxr-xr-xt/t4216-log-bloom.sh242
-rwxr-xr-xt/t5324-split-commit-graph.sh13
-rwxr-xr-xt/t5411-proc-receive-hook.sh117
-rw-r--r--t/t5411/common-functions.sh56
-rw-r--r--t/t5411/once-0010-report-status-v1.sh94
-rw-r--r--t/t5411/test-0000-standard-git-push.sh143
-rw-r--r--t/t5411/test-0001-standard-git-push--porcelain.sh147
-rw-r--r--t/t5411/test-0002-pre-receive-declined.sh33
-rw-r--r--t/t5411/test-0003-pre-receive-declined--porcelain.sh34
-rw-r--r--t/t5411/test-0010-proc-receive-settings.sh7
-rw-r--r--t/t5411/test-0011-no-hook-error.sh64
-rw-r--r--t/t5411/test-0012-no-hook-error--porcelain.sh66
-rw-r--r--t/t5411/test-0013-bad-protocol.sh217
-rw-r--r--t/t5411/test-0014-bad-protocol--porcelain.sh160
-rw-r--r--t/t5411/test-0020-report-ng.sh67
-rw-r--r--t/t5411/test-0021-report-ng--porcelain.sh69
-rw-r--r--t/t5411/test-0022-report-unexpect-ref.sh45
-rw-r--r--t/t5411/test-0023-report-unexpect-ref--porcelain.sh46
-rw-r--r--t/t5411/test-0024-report-unknown-ref.sh34
-rw-r--r--t/t5411/test-0025-report-unknown-ref--porcelain.sh35
-rw-r--r--t/t5411/test-0026-push-options.sh79
-rw-r--r--t/t5411/test-0027-push-options--porcelain.sh82
-rw-r--r--t/t5411/test-0030-report-ok.sh35
-rw-r--r--t/t5411/test-0031-report-ok--porcelain.sh36
-rw-r--r--t/t5411/test-0032-report-with-options.sh256
-rw-r--r--t/t5411/test-0033-report-with-options--porcelain.sh265
-rw-r--r--t/t5411/test-0034-report-ft.sh44
-rw-r--r--t/t5411/test-0035-report-ft--porcelain.sh45
-rw-r--r--t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh227
-rw-r--r--t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh172
-rw-r--r--t/t5411/test-0038-report-mixed-refs.sh89
-rw-r--r--t/t5411/test-0039-report-mixed-refs--porcelain.sh91
-rw-r--r--t/t5411/test-0040-process-all-refs.sh113
-rw-r--r--t/t5411/test-0041-process-all-refs--porcelain.sh114
-rw-r--r--t/t5411/test-0050-proc-receive-refs-with-modifiers.sh135
-rwxr-xr-xt/t5510-fetch.sh2
-rwxr-xr-xt/t5514-fetch-multiple.sh2
-rwxr-xr-xt/t5515-fetch-merge-logic.sh6
-rwxr-xr-xt/t5516-fetch-push.sh2
-rwxr-xr-xt/t5523-push-upstream.sh20
-rwxr-xr-xt/t5534-push-signed.sh23
-rwxr-xr-xt/t5601-clone.sh14
-rwxr-xr-xt/t6018-rev-list-glob.sh6
-rwxr-xr-xt/t6030-bisect-porcelain.sh7
-rwxr-xr-xt/t6040-tracking-info.sh20
-rwxr-xr-xt/t6409-merge-subtree.sh14
-rwxr-xr-xt/t6600-test-reach.sh30
-rwxr-xr-xt/t7601-merge-pull-config.sh21
-rwxr-xr-xt/t7900-maintenance.sh65
-rwxr-xr-xt/t8013-blame-ignore-revs.sh61
-rwxr-xr-xt/t9832-unshelve.sh5
-rwxr-xr-xt/t9902-completion.sh10
-rw-r--r--t/test-lib-functions.sh33
-rwxr-xr-xt/test-terminal.perl32
-rwxr-xr-xtemplates/hooks--pre-push.sample18
-rwxr-xr-xtemplates/hooks--update.sample2
-rw-r--r--trailer.c36
-rw-r--r--trailer.h45
-rw-r--r--transport-helper.c128
-rw-r--r--transport.c156
-rw-r--r--tree-diff.c5
-rw-r--r--worktree.c46
-rw-r--r--worktree.h7
-rw-r--r--wt-status.c72
-rw-r--r--wt-status.h7
173 files changed, 12379 insertions, 6495 deletions
diff --git a/.gitignore b/.gitignore
index 6521f3c..6232d33 100644
--- a/.gitignore
+++ b/.gitignore
@@ -90,6 +90,7 @@
/git-ls-tree
/git-mailinfo
/git-mailsplit
+/git-maintenance
/git-merge
/git-merge-base
/git-merge-index
diff --git a/Documentation/RelNotes/2.29.0.txt b/Documentation/RelNotes/2.29.0.txt
index d728e81..41a78a4 100644
--- a/Documentation/RelNotes/2.29.0.txt
+++ b/Documentation/RelNotes/2.29.0.txt
@@ -80,6 +80,36 @@ UI, Workflows & Features
one --merged or --no-merged to filter them; they learned to take
combination of both kind of filtering.
+ * "git maintenance", a "git gc"'s big brother, has been introduced to
+ take care of more repository maintenance tasks, not limited to the
+ object database cleaning.
+
+ * "git receive-pack" that accepts requests by "git push" learned to
+ outsource most of the ref updates to the new "proc-receive" hook.
+
+ * "git push" that wants to be atomic and wants to send push
+ certificate learned not to prepare and sign the push certificate
+ when it fails the local check (hence due to atomicity it is known
+ that no certificate is needed).
+
+ * "git commit-graph write" learned to limit the number of bloom
+ filters that are computed from scratch with the --max-new-filters
+ option.
+
+ * The transport protocol v2 has become the default again.
+
+ * The installation procedure learned to optionally omit "git-foo"
+ executable files for each 'foo' built-in subcommand, which are only
+ required by old timers that still rely on the age old promise that
+ prepending "git --exec-path" output to PATH early in their script
+ will keep the "git-foo" calls they wrote working.
+
+ * The command line completion (in contrib/) learned that "git restore
+ -s <TAB>" is often followed by a refname.
+
+ * "git shortlog" has been taught to group commits by the contents of
+ the trailer lines, like "Reviewed-by:", "Coauthored-by:", etc.
+
Performance, Internal Implementation, Development Support etc.
@@ -171,6 +201,9 @@ Performance, Internal Implementation, Development Support etc.
* "git index-pack" learned to resolve deltified objects with greater
parallelism.
+ * "diff-highlight" (in contrib/) had a logic to flush its output upon
+ seeing a blank line but the way it detected a blank line was broken.
+
Fixes since v2.28
-----------------
@@ -366,6 +399,48 @@ Fixes since v2.28
which has been corrected.
(merge 4e735c1326 ar/fetch-ipversion-in-all later to maint).
+ * The "unshelve" subcommand of "git p4" used incorrectly used
+ commit^N where it meant to say commit~N to name the Nth generation
+ ancestor, which has been corrected.
+ (merge 0acbf5997f ld/p4-unshelve-fix later to maint).
+
+ * "git clone" that clones from SHA-1 repository, while
+ GIT_DEFAULT_HASH set to use SHA-256 already, resulted in an
+ unusable repository that half-claims to be SHA-256 repository
+ with SHA-1 objects and refs. This has been corrected.
+
+ * Adjust sample hooks for hash algorithm other than SHA-1.
+ (merge d8d3d632f4 dl/zero-oid-in-hooks later to maint).
+
+ * "git range-diff" showed incorrect diffstat, which has been
+ corrected.
+
+ * Earlier we taught "git pull" to warn when the user does not say the
+ histories need to be merged, rebased or accepts only fast-
+ forwarding, but the warning triggered for those who have set the
+ pull.ff configuration variable.
+ (merge 54200cef86 ah/pull later to maint).
+
+ * Compilation fix around type punning.
+ (merge 176380fd11 jk/drop-unaligned-loads later to maint).
+
+ * "git blame --ignore-rev/--ignore-revs-file" failed to validate
+ their input are valid revision, and failed to take into account
+ that the user may want to give an annotated tag instead of a
+ commit, which has been corrected.
+ (merge 610e2b9240 jc/blame-ignore-fix later to maint).
+
+ * "git bisect start X Y", when X and Y are not valid committish
+ object names, should take X and Y as pathspec, but didn't.
+ (merge 73c6de06af cc/bisect-start-fix later to maint).
+
+ * The explanation of the "scissors line" has been clarified.
+ (merge 287416dba6 eg/mailinfo-doc-scissors later to maint).
+
+ * A race that leads to an access to a free'd data was corrected in
+ the codepath that reads pack files.
+ (merge bda959c476 mt/delta-base-cache-races later to maint).
+
* Other code cleanup, docfix, build fix, etc.
(merge 84544f2ea3 sk/typofixes later to maint).
(merge b17f411ab5 ar/help-guides-doc later to maint).
@@ -397,3 +472,4 @@ Fixes since v2.28
(merge 324efcf6b6 pw/add-p-leakfix later to maint).
(merge 1c6ffb546b jk/add-i-fixes later to maint).
(merge e40e936551 cd/commit-graph-doc later to maint).
+ (merge 0512eabd91 jc/sequencer-stopped-sha-simplify later to maint).
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 3042d80..bf706b9 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -340,6 +340,8 @@ include::config/column.txt[]
include::config/commit.txt[]
+include::config/commitgraph.txt[]
+
include::config/credential.txt[]
include::config/completion.txt[]
@@ -398,6 +400,8 @@ include::config/mailinfo.txt[]
include::config/mailmap.txt[]
+include::config/maintenance.txt[]
+
include::config/man.txt[]
include::config/merge.txt[]
diff --git a/Documentation/config/commitgraph.txt b/Documentation/config/commitgraph.txt
new file mode 100644
index 0000000..4582c39
--- /dev/null
+++ b/Documentation/config/commitgraph.txt
@@ -0,0 +1,8 @@
+commitGraph.maxNewFilters::
+ Specifies the default value for the `--max-new-filters` option of `git
+ commit-graph write` (c.f., linkgit:git-commit-graph[1]).
+
+commitGraph.readChangedPaths::
+ If true, then git will use the changed-path Bloom filters in the
+ commit-graph file (if it exists, and they are present). Defaults to
+ true. See linkgit:git-commit-graph[1] for more information.
diff --git a/Documentation/config/feature.txt b/Documentation/config/feature.txt
index c0cbf2b..cdecd04 100644
--- a/Documentation/config/feature.txt
+++ b/Documentation/config/feature.txt
@@ -14,10 +14,6 @@ feature.experimental::
+
* `fetch.negotiationAlgorithm=skipping` may improve fetch negotiation times by
skipping more commits at a time, reducing the number of round trips.
-+
-* `protocol.version=2` speeds up fetches from repositories with many refs by
-allowing the client to specify which refs to list before the server lists
-them.
feature.manyFiles::
Enable config options that optimize for repos with many files in the
diff --git a/Documentation/config/fmt-merge-msg.txt b/Documentation/config/fmt-merge-msg.txt
index a8e8f74..3fbf40e 100644
--- a/Documentation/config/fmt-merge-msg.txt
+++ b/Documentation/config/fmt-merge-msg.txt
@@ -13,7 +13,7 @@ merge.suppressDest::
By adding a glob that matches the names of integration
branches to this multi-valued configuration variable, the
default merge message computed for merges into these
- integration branches will omit " into <branch name>" from
+ integration branches will omit "into <branch name>" from
its title.
+
An element with an empty value can be used to clear the list
diff --git a/Documentation/config/maintenance.txt b/Documentation/config/maintenance.txt
new file mode 100644
index 0000000..7cc6700
--- /dev/null
+++ b/Documentation/config/maintenance.txt
@@ -0,0 +1,16 @@
+maintenance.<task>.enabled::
+ This boolean config option controls whether the maintenance task
+ with name `<task>` is run when no `--task` option is specified to
+ `git maintenance run`. These config values are ignored if a
+ `--task` option exists. By default, only `maintenance.gc.enabled`
+ is true.
+
+maintenance.commit-graph.auto::
+ This integer config option controls how often the `commit-graph` task
+ should be run as part of `git maintenance run --auto`. If zero, then
+ the `commit-graph` task will not run with the `--auto` option. A
+ negative value will force the task to run every time. Otherwise, a
+ positive value implies the command should run when the number of
+ reachable commits that are not in the commit-graph file is at least
+ the value of `maintenance.commit-graph.auto`. The default value is
+ 100.
diff --git a/Documentation/config/protocol.txt b/Documentation/config/protocol.txt
index c46e9b3..756591d 100644
--- a/Documentation/config/protocol.txt
+++ b/Documentation/config/protocol.txt
@@ -48,8 +48,7 @@ protocol.version::
If set, clients will attempt to communicate with a server
using the specified protocol version. If the server does
not support it, communication falls back to version 0.
- If unset, the default is `0`, unless `feature.experimental`
- is enabled, in which case the default is `2`.
+ If unset, the default is `2`.
Supported versions:
+
--
diff --git a/Documentation/config/receive.txt b/Documentation/config/receive.txt
index 65f78aa..85d5b5a 100644
--- a/Documentation/config/receive.txt
+++ b/Documentation/config/receive.txt
@@ -114,6 +114,28 @@ receive.hideRefs::
An attempt to update or delete a hidden ref by `git push` is
rejected.
+receive.procReceiveRefs::
+ This is a multi-valued variable that defines reference prefixes
+ to match the commands in `receive-pack`. Commands matching the
+ prefixes will be executed by an external hook "proc-receive",
+ instead of the internal `execute_commands` function. If this
+ variable is not defined, the "proc-receive" hook will never be
+ used, and all commands will be executed by the internal
+ `execute_commands` function.
++
+For example, if this variable is set to "refs/for", pushing to reference
+such as "refs/for/master" will not create or update a reference named
+"refs/for/master", but may create or update a pull request directly by
+running the hook "proc-receive".
++
+Optional modifiers can be provided in the beginning of the value to filter
+commands for specific actions: create (a), modify (m), delete (d).
+A `!` can be included in the modifiers to negate the reference prefix entry.
+E.g.:
++
+ git config --system --add receive.procReceiveRefs ad:refs/heads
+ git config --system --add receive.procReceiveRefs !:refs/heads
+
receive.updateServerInfo::
If set to true, git-receive-pack will run git-update-server-info
after receiving data from git-push and updating refs.
diff --git a/Documentation/config/uploadpack.txt b/Documentation/config/uploadpack.txt
index ee7b3ac..b0d7612 100644
--- a/Documentation/config/uploadpack.txt
+++ b/Documentation/config/uploadpack.txt
@@ -70,7 +70,7 @@ uploadpackfilter.<filter>.allow::
kinds must be allowed. Defaults to `uploadpackfilter.allow`.
uploadpackfilter.tree.maxDepth::
- Only allow `--filter=tree=<n>` when `n` is no more than the value of
+ Only allow `--filter=tree:<n>` when `<n>` is no more than the value of
`uploadpackfilter.tree.maxDepth`. If set, this also implies
`uploadpackfilter.tree.allow=true`, unless this configuration
variable had already been set. Has no effect if unset.
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index e8104c0..2bf77b4 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -95,9 +95,11 @@ ifndef::git-pull[]
Allow several <repository> and <group> arguments to be
specified. No <refspec>s may be specified.
+--[no-]auto-maintenance::
--[no-]auto-gc::
- Run `git gc --auto` at the end to perform garbage collection
- if needed. This is enabled by default.
+ Run `git maintenance run --auto` at the end to perform automatic
+ repository maintenance if needed. (`--[no-]auto-gc` is a synonym.)
+ This is enabled by default.
--[no-]write-commit-graph::
Write a commit-graph after fetching. This overrides the config
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index c898310..097e6a8 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -78,9 +78,9 @@ repository using this option and then delete branches (or use any
other Git command that makes any existing commit unreferenced) in the
source repository, some objects may become unreferenced (or dangling).
These objects may be removed by normal Git operations (such as `git commit`)
-which automatically call `git gc --auto`. (See linkgit:git-gc[1].)
-If these objects are removed and were referenced by the cloned repository,
-then the cloned repository will become corrupt.
+which automatically call `git maintenance run --auto`. (See
+linkgit:git-maintenance[1].) If these objects are removed and were referenced
+by the cloned repository, then the cloned repository will become corrupt.
+
Note that running `git repack` without the `--local` option in a repository
cloned with `--shared` will copy objects from the source repository into a pack
diff --git a/Documentation/git-commit-graph.txt b/Documentation/git-commit-graph.txt
index 17405c7..de6b6de 100644
--- a/Documentation/git-commit-graph.txt
+++ b/Documentation/git-commit-graph.txt
@@ -67,6 +67,13 @@ this option is given, future commit-graph writes will automatically assume
that this option was intended. Use `--no-changed-paths` to stop storing this
data.
+
+With the `--max-new-filters=<n>` option, generate at most `n` new Bloom
+filters (if `--changed-paths` is specified). If `n` is `-1`, no limit is
+enforced. Only commits present in the new layer count against this
+limit. To retroactively compute Bloom filters over earlier layers, it is
+advised to use `--split=replace`. Overrides the `commitGraph.maxNewFilters`
+configuration.
++
With the `--split[=<strategy>]` option, write the commit-graph as a
chain of multiple commit-graph files stored in
`<dir>/info/commit-graphs`. Commit-graph layers are merged based on the
diff --git a/Documentation/git-mailinfo.txt b/Documentation/git-mailinfo.txt
index 3bbc731..7a6aed0 100644
--- a/Documentation/git-mailinfo.txt
+++ b/Documentation/git-mailinfo.txt
@@ -72,10 +72,9 @@ conversion, even with this flag.
is useful in order to associate commits with mailing list discussions.
--scissors::
- Remove everything in body before a scissors line. A line that
- mainly consists of scissors (either ">8" or "8<") and perforation
- (dash "-") marks is called a scissors line, and is used to request
- the reader to cut the message at that line. If such a line
+ Remove everything in body before a scissors line (e.g. "-- >8 --").
+ The line represents scissors and perforation marks, and is used to
+ request the reader to cut the message at that line. If that line
appears in the body of the message before the patch, everything
before it (including the scissors line itself) is ignored when
this option is used.
diff --git a/Documentation/git-maintenance.txt b/Documentation/git-maintenance.txt
new file mode 100644
index 0000000..6abcb82
--- /dev/null
+++ b/Documentation/git-maintenance.txt
@@ -0,0 +1,79 @@
+git-maintenance(1)
+==================
+
+NAME
+----
+git-maintenance - Run tasks to optimize Git repository data
+
+
+SYNOPSIS
+--------
+[verse]
+'git maintenance' run [<options>]
+
+
+DESCRIPTION
+-----------
+Run tasks to optimize Git repository data, speeding up other Git commands
+and reducing storage requirements for the repository.
+
+Git commands that add repository data, such as `git add` or `git fetch`,
+are optimized for a responsive user experience. These commands do not take
+time to optimize the Git data, since such optimizations scale with the full
+size of the repository while these user commands each perform a relatively
+small action.
+
+The `git maintenance` command provides flexibility for how to optimize the
+Git repository.
+
+SUBCOMMANDS
+-----------
+
+run::
+ Run one or more maintenance tasks. If one or more `--task` options
+ are specified, then those tasks are run in that order. Otherwise,
+ the tasks are determined by which `maintenance.<task>.enabled`
+ config options are true. By default, only `maintenance.gc.enabled`
+ is true.
+
+TASKS
+-----
+
+commit-graph::
+ The `commit-graph` job updates the `commit-graph` files incrementally,
+ then verifies that the written data is correct. The incremental
+ write is safe to run alongside concurrent Git processes since it
+ will not expire `.graph` files that were in the previous
+ `commit-graph-chain` file. They will be deleted by a later run based
+ on the expiration delay.
+
+gc::
+ Clean up unnecessary files and optimize the local repository. "GC"
+ stands for "garbage collection," but this task performs many
+ smaller tasks. This task can be expensive for large repositories,
+ as it repacks all Git objects into a single pack-file. It can also
+ be disruptive in some situations, as it deletes stale data. See
+ linkgit:git-gc[1] for more details on garbage collection in Git.
+
+OPTIONS
+-------
+--auto::
+ When combined with the `run` subcommand, run maintenance tasks
+ only if certain thresholds are met. For example, the `gc` task
+ runs when the number of loose objects exceeds the number stored
+ in the `gc.auto` config setting, or when the number of pack-files
+ exceeds the `gc.autoPackLimit` config setting.
+
+--quiet::
+ Do not report progress or other information over `stderr`.
+
+--task=<task>::
+ If this option is specified one or more times, then only run the
+ specified tasks in the specified order. If no `--task=<task>`
+ arguments are specified, then only the tasks with
+ `maintenance.<task>.enabled` configured as `true` are considered.
+ See the 'TASKS' section for the list of accepted `<task>` values.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-shortlog.txt b/Documentation/git-shortlog.txt
index a72ea7f..fd93cd4 100644
--- a/Documentation/git-shortlog.txt
+++ b/Documentation/git-shortlog.txt
@@ -47,9 +47,38 @@ OPTIONS
Each pretty-printed commit will be rewrapped before it is shown.
+--group=<type>::
+ Group commits based on `<type>`. If no `--group` option is
+ specified, the default is `author`. `<type>` is one of:
++
+--
+ - `author`, commits are grouped by author
+ - `committer`, commits are grouped by committer (the same as `-c`)
+ - `trailer:<field>`, the `<field>` is interpreted as a case-insensitive
+ commit message trailer (see linkgit:git-interpret-trailers[1]). For
+ example, if your project uses `Reviewed-by` trailers, you might want
+ to see who has been reviewing with
+ `git shortlog -ns --group=trailer:reviewed-by`.
++
+Note that commits that do not include the trailer will not be counted.
+Likewise, commits with multiple trailers (e.g., multiple signoffs) may
+be counted more than once (but only once per unique trailer value in
+that commit).
++
+Shortlog will attempt to parse each trailer value as a `name <email>`
+identity. If successful, the mailmap is applied and the email is omitted
+unless the `--email` option is specified. If the value cannot be parsed
+as an identity, it will be taken literally and completely.
+--
++
+If `--group` is specified multiple times, commits are counted under each
+value (but again, only once per unique value in that commit). For
+example, `git shortlog --group=author --group=trailer:co-authored-by`
+counts both authors and co-authors.
+
-c::
--committer::
- Collect and show committer identities instead of authors.
+ This is an alias for `--group=committer`.
-w[<width>[,<indent1>[,<indent2>]]]::
Linewrap the output by wrapping each line at `width`. The first
diff --git a/Documentation/gitfaq.txt b/Documentation/gitfaq.txt
index 9cd7a59..afdaeab 100644
--- a/Documentation/gitfaq.txt
+++ b/Documentation/gitfaq.txt
@@ -241,6 +241,59 @@ How do I know if I want to do a fetch or a pull?::
ignore the upstream changes. A pull consists of a fetch followed
immediately by either a merge or rebase. See linkgit:git-pull[1].
+Merging and Rebasing
+--------------------
+
+[[long-running-squash-merge]]
+What kinds of problems can occur when merging long-lived branches with squash merges?::
+ In general, there are a variety of problems that can occur when using squash
+ merges to merge two branches multiple times. These can include seeing extra
+ commits in `git log` output, with a GUI, or when using the `...` notation to
+ express a range, as well as the possibility of needing to re-resolve conflicts
+ again and again.
++
+When Git does a normal merge between two branches, it considers exactly three
+points: the two branches and a third commit, called the _merge base_, which is
+usually the common ancestor of the commits. The result of the merge is the sum
+of the changes between the merge base and each head. When you merge two
+branches with a regular merge commit, this results in a new commit which will
+end up as a merge base when they're merged again, because there is now a new
+common ancestor. Git doesn't have to consider changes that occurred before the
+merge base, so you don't have to re-resolve any conflicts you resolved before.
++
+When you perform a squash merge, a merge commit isn't created; instead, the
+changes from one side are applied as a regular commit to the other side. This
+means that the merge base for these branches won't have changed, and so when Git
+goes to perform its next merge, it considers all of the changes that it
+considered the last time plus the new changes. That means any conflicts may
+need to be re-resolved. Similarly, anything using the `...` notation in `git
+diff`, `git log`, or a GUI will result in showing all of the changes since the
+original merge base.
++
+As a consequence, if you want to merge two long-lived branches repeatedly, it's
+best to always use a regular merge commit.
+
+[[merge-two-revert-one]]
+If I make a change on two branches but revert it on one, why does the merge of those branches include the change?::
+ By default, when Git does a merge, it uses a strategy called the recursive
+ strategy, which does a fancy three-way merge. In such a case, when Git
+ performs the merge, it considers exactly three points: the two heads and a
+ third point, called the _merge base_, which is usually the common ancestor of
+ those commits. Git does not consider the history or the individual commits
+ that have happened on those branches at all.
++
+As a result, if both sides have a change and one side has reverted that change,
+the result is to include the change. This is because the code has changed on
+one side and there is no net change on the other, and in this scenario, Git
+adopts the change.
++
+If this is a problem for you, you can do a rebase instead, rebasing the branch
+with the revert onto the other branch. A rebase in this scenario will revert
+the change, because a rebase applies each individual commit, including the
+revert. Note that rebases rewrite history, so you should avoid rebasing
+published branches unless you're sure you're comfortable with that. See the
+NOTES section in linkgit:git-rebase[1] for more details.
+
Hooks
-----
@@ -310,6 +363,39 @@ information about how to configure files as text or binary.
You can also control this behavior with the `core.whitespace` setting if you
don't wish to remove the carriage returns from your line endings.
+[[always-modified-files-case]]
+Why do I have a file that's always modified?::
+ Internally, Git always stores file names as sequences of bytes and doesn't
+ perform any encoding or case folding. However, Windows and macOS by default
+ both perform case folding on file names. As a result, it's possible to end up
+ with multiple files or directories whose names differ only in case. Git can
+ handle this just fine, but the file system can store only one of these files,
+ so when Git reads the other file to see its contents, it looks modified.
++
+It's best to remove one of the files such that you only have one file. You can
+do this with commands like the following (assuming two files `AFile.txt` and
+`afile.txt`) on an otherwise clean working tree:
++
+----
+$ git rm --cached AFile.txt
+$ git commit -m 'Remove files conflicting in case'
+$ git checkout .
+----
++
+This avoids touching the disk, but removes the additional file. Your project
+may prefer to adopt a naming convention, such as all-lowercase names, to avoid
+this problem from occurring again; such a convention can be checked using a
+`pre-receive` hook or as part of a continuous integration (CI) system.
++
+It is also possible for perpetually modified files to occur on any platform if a
+smudge or clean filter is in use on your system but a file was previously
+committed without running the smudge or clean filter. To fix this, run the
+following on an otherwise clean working tree:
++
+----
+$ git add --renormalize .
+----
+
[[recommended-storage-settings]]
What's the recommended way to store files in Git?::
While Git can store and handle any file of any type, there are some
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index cf95d6d..6e461ac 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -335,6 +335,68 @@ The default 'update' hook, when enabled--and with
`hooks.allowunannotated` config option unset or set to false--prevents
unannotated tags to be pushed.
+[[proc-receive]]
+proc-receive
+~~~~~~~~~~~~
+
+This hook is invoked by linkgit:git-receive-pack[1]. If the server has
+set the multi-valued config variable `receive.procReceiveRefs`, and the
+commands sent to 'receive-pack' have matching reference names, these
+commands will be executed by this hook, instead of by the internal
+`execute_commands()` function. This hook is responsible for updating
+the relevant references and reporting the results back to 'receive-pack'.
+
+This hook executes once for the receive operation. It takes no
+arguments, but uses a pkt-line format protocol to communicate with
+'receive-pack' to read commands, push-options and send results. In the
+following example for the protocol, the letter 'S' stands for
+'receive-pack' and the letter 'H' stands for this hook.
+
+ # Version and features negotiation.
+ S: PKT-LINE(version=1\0push-options atomic...)
+ S: flush-pkt
+ H: PKT-LINE(version=1\0push-options...)
+ H: flush-pkt
+
+ # Send commands from server to the hook.
+ S: PKT-LINE(<old-oid> <new-oid> <ref>)
+ S: ... ...
+ S: flush-pkt
+ # Send push-options only if the 'push-options' feature is enabled.
+ S: PKT-LINE(push-option)
+ S: ... ...
+ S: flush-pkt
+
+ # Receive result from the hook.
+ # OK, run this command successfully.
+ H: PKT-LINE(ok <ref>)
+ # NO, I reject it.
+ H: PKT-LINE(ng <ref> <reason>)
+ # Fall through, let 'receive-pack' to execute it.
+ H: PKT-LINE(ok <ref>)
+ H: PKT-LINE(option fall-through)
+ # OK, but has an alternate reference. The alternate reference name
+ # and other status can be given in option directives.
+ H: PKT-LINE(ok <ref>)
+ H: PKT-LINE(option refname <refname>)
+ H: PKT-LINE(option old-oid <old-oid>)
+ H: PKT-LINE(option new-oid <new-oid>)
+ H: PKT-LINE(option forced-update)
+ H: ... ...
+ H: flush-pkt
+
+Each command for the 'proc-receive' hook may point to a pseudo-reference
+and always has a zero-old as its old-oid, while the 'proc-receive' hook
+may update an alternate reference and the alternate reference may exist
+already with a non-zero old-oid. For this case, this hook will use
+"option" directives to report extended attributes for the reference given
+by the leading "ok" directive.
+
+The report of the commands of this hook should have the same order as
+the input. The exit status of the 'proc-receive' hook only determines
+the success or failure of the group of commands sent to it, unless
+atomic push is in use.
+
[[post-receive]]
post-receive
~~~~~~~~~~~~
diff --git a/Documentation/technical/commit-graph-format.txt b/Documentation/technical/commit-graph-format.txt
index 1f86031..b3b5888 100644
--- a/Documentation/technical/commit-graph-format.txt
+++ b/Documentation/technical/commit-graph-format.txt
@@ -125,7 +125,7 @@ CHUNK DATA:
* The rest of the chunk is the concatenation of all the computed Bloom
filters for the commits in lexicographic order.
* Note: Commits with no changes or more than 512 changes have Bloom filters
- of length zero.
+ of length one, with either all bits set to zero or one respectively.
* The BDAT chunk is present if and only if BIDX is present.
Base Graphs List (ID: {'B', 'A', 'S', 'E'}) [Optional]
diff --git a/Documentation/technical/pack-protocol.txt b/Documentation/technical/pack-protocol.txt
index a4573d1..e13a2c0 100644
--- a/Documentation/technical/pack-protocol.txt
+++ b/Documentation/technical/pack-protocol.txt
@@ -503,8 +503,8 @@ The reference discovery phase is done nearly the same way as it is in the
fetching protocol. Each reference obj-id and name on the server is sent
in packet-line format to the client, followed by a flush-pkt. The only
real difference is that the capability listing is different - the only
-possible values are 'report-status', 'delete-refs', 'ofs-delta' and
-'push-options'.
+possible values are 'report-status', 'report-status-v2', 'delete-refs',
+'ofs-delta', 'atomic' and 'push-options'.
Reference Update Request and Packfile Transfer
----------------------------------------------
@@ -625,7 +625,7 @@ Report Status
-------------
After receiving the pack data from the sender, the receiver sends a
-report if 'report-status' capability is in effect.
+report if 'report-status' or 'report-status-v2' capability is in effect.
It is a short listing of what happened in that update. It will first
list the status of the packfile unpacking as either 'unpack ok' or
'unpack [error]'. Then it will list the status for each of the references
@@ -647,6 +647,41 @@ update was successful, or 'ng [refname] [error]' if the update was not.
error-msg = 1*(OCTET) ; where not "ok"
----
+The 'report-status-v2' capability extends the protocol by adding new option
+lines in order to support reporting of reference rewritten by the
+'proc-receive' hook. The 'proc-receive' hook may handle a command for a
+pseudo-reference which may create or update one or more references, and each
+reference may have different name, different new-oid, and different old-oid.
+
+----
+ report-status-v2 = unpack-status
+ 1*(command-status-v2)
+ flush-pkt
+
+ unpack-status = PKT-LINE("unpack" SP unpack-result)
+ unpack-result = "ok" / error-msg
+
+ command-status-v2 = command-ok-v2 / command-fail
+ command-ok-v2 = command-ok
+ *option-line
+
+ command-ok = PKT-LINE("ok" SP refname)
+ command-fail = PKT-LINE("ng" SP refname SP error-msg)
+
+ error-msg = 1*(OCTET) ; where not "ok"
+
+ option-line = *1(option-refname)
+ *1(option-old-oid)
+ *1(option-new-oid)
+ *1(option-forced-update)
+
+ option-refname = PKT-LINE("option" SP "refname" SP refname)
+ option-old-oid = PKT-LINE("option" SP "old-oid" SP obj-id)
+ option-new-oid = PKT-LINE("option" SP "new-oid" SP obj-id)
+ option-force = PKT-LINE("option" SP "forced-update")
+
+----
+
Updates can be unsuccessful for a number of reasons. The reference can have
changed since the reference discovery phase was originally sent, meaning
someone pushed in the meantime. The reference being pushed could be a
diff --git a/Documentation/technical/protocol-capabilities.txt b/Documentation/technical/protocol-capabilities.txt
index 124d716..ba869a7 100644
--- a/Documentation/technical/protocol-capabilities.txt
+++ b/Documentation/technical/protocol-capabilities.txt
@@ -22,9 +22,9 @@ was sent. Server MUST NOT ignore capabilities that client requested
and server advertised. As a consequence of these rules, server MUST
NOT advertise capabilities it does not understand.
-The 'atomic', 'report-status', 'delete-refs', 'quiet', and 'push-cert'
-capabilities are sent and recognized by the receive-pack (push to server)
-process.
+The 'atomic', 'report-status', 'report-status-v2', 'delete-refs', 'quiet',
+and 'push-cert' capabilities are sent and recognized by the receive-pack
+(push to server) process.
The 'ofs-delta' and 'side-band-64k' capabilities are sent and recognized
by both upload-pack and receive-pack protocols. The 'agent' capability
@@ -284,6 +284,17 @@ each reference was updated successfully. If any of those were not
successful, it will send back an error message. See pack-protocol.txt
for example messages.
+report-status-v2
+----------------
+
+Capability 'report-status-v2' extends capability 'report-status' by
+adding new "option" directives in order to support reference rewritten by
+the "proc-receive" hook. The "proc-receive" hook may handle a command
+for a pseudo-reference which may create or update a reference with
+different name, new-oid, and old-oid. While the capability
+'report-status' cannot report for such case. See pack-protocol.txt
+for details.
+
delete-refs
-----------
diff --git a/Makefile b/Makefile
index 92d188f..fb521da 100644
--- a/Makefile
+++ b/Makefile
@@ -348,6 +348,9 @@ all::
# Define NO_INSTALL_HARDLINKS if you prefer to use either symbolic links or
# copies to install built-in git commands e.g. git-cat-file.
#
+# Define SKIP_DASHED_BUILT_INS if you do not need the dashed versions of the
+# built-ins to be linked/copied at all.
+#
# Define USE_NED_ALLOCATOR if you want to replace the platforms default
# memory allocators with the nedmalloc allocator written by Niall Douglas.
#
@@ -720,6 +723,7 @@ TEST_BUILTINS_OBJS += test-parse-pathspec-file.o
TEST_BUILTINS_OBJS += test-path-utils.o
TEST_BUILTINS_OBJS += test-pkt-line.o
TEST_BUILTINS_OBJS += test-prio-queue.o
+TEST_BUILTINS_OBJS += test-proc-receive.o
TEST_BUILTINS_OBJS += test-progress.o
TEST_BUILTINS_OBJS += test-reach.o
TEST_BUILTINS_OBJS += test-read-cache.o
@@ -774,6 +778,16 @@ BUILT_INS += git-whatchanged$X
# what 'all' will build and 'install' will install in gitexecdir,
# excluding programs for built-in commands
ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
+ALL_COMMANDS_TO_INSTALL = $(ALL_PROGRAMS)
+ifeq (,$(SKIP_DASHED_BUILT_INS))
+ALL_COMMANDS_TO_INSTALL += $(BUILT_INS)
+else
+# git-upload-pack, git-receive-pack and git-upload-archive are special: they
+# are _expected_ to be present in the `bin/` directory in their dashed form.
+ALL_COMMANDS_TO_INSTALL += git-receive-pack$(X)
+ALL_COMMANDS_TO_INSTALL += git-upload-archive$(X)
+ALL_COMMANDS_TO_INSTALL += git-upload-pack$(X)
+endif
# what 'all' will build but not install in gitexecdir
OTHER_PROGRAMS = git$X
@@ -1218,7 +1232,6 @@ SANITIZERS := $(foreach flag,$(subst $(comma),$(space),$(SANITIZE)),$(flag))
BASIC_CFLAGS += -fsanitize=$(SANITIZE) -fno-sanitize-recover=$(SANITIZE)
BASIC_CFLAGS += -fno-omit-frame-pointer
ifneq ($(filter undefined,$(SANITIZERS)),)
-BASIC_CFLAGS += -DNO_UNALIGNED_LOADS
BASIC_CFLAGS += -DSHA1DC_FORCE_ALIGNED_ACCESS
endif
ifneq ($(filter leak,$(SANITIZERS)),)
@@ -2088,9 +2101,9 @@ profile-fast: profile-clean
$(MAKE) PROFILE=USE all
-all:: $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS
+all:: $(ALL_COMMANDS_TO_INSTALL) $(SCRIPT_LIB) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS
ifneq (,$X)
- $(QUIET_BUILT_IN)$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test -d '$p' -o '$p' -ef '$p$X' || $(RM) '$p';)
+ $(QUIET_BUILT_IN)$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_COMMANDS_TO_INSTALL) git$X)), test -d '$p' -o '$p' -ef '$p$X' || $(RM) '$p';)
endif
all::
@@ -2921,15 +2934,8 @@ ifdef MSVC
# have already been rolled up into the exe's pdb file.
# We DO NOT have pdb files for the builtin commands (like git-status.exe)
# because it is just a copy/hardlink of git.exe, rather than a unique binary.
- $(INSTALL) git.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
- $(INSTALL) git-shell.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
- $(INSTALL) git-daemon.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
- $(INSTALL) git-http-backend.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
- $(INSTALL) git-http-fetch.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
- $(INSTALL) git-http-push.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
- $(INSTALL) git-imap-send.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
- $(INSTALL) git-remote-http.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
- $(INSTALL) git-sh-i18n--envsubst.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
+ $(INSTALL) $(patsubst %.exe,%.pdb,$(filter-out $(BUILT_INS),$(patsubst %,%$X,$(BINDIR_PROGRAMS_NEED_X)))) '$(DESTDIR_SQ)$(bindir_SQ)'
+ $(INSTALL) $(patsubst %.exe,%.pdb,$(filter-out $(BUILT_INS) $(REMOTE_CURL_ALIASES),$(PROGRAMS))) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
ifndef DEBUG
$(INSTALL) $(vcpkg_rel_bin)/*.dll '$(DESTDIR_SQ)$(bindir_SQ)'
$(INSTALL) $(vcpkg_rel_bin)/*.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
@@ -2957,7 +2963,7 @@ ifndef NO_TCLTK
$(MAKE) -C git-gui gitexecdir='$(gitexec_instdir_SQ)' install
endif
ifneq (,$X)
- $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p' -ef '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p$X' || $(RM) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p';)
+ $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_COMMANDS_TO_INSTALL) git$X)), test '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p' -ef '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p$X' || $(RM) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p';)
endif
bindir=$$(cd '$(DESTDIR_SQ)$(bindir_SQ)' && pwd) && \
@@ -2975,21 +2981,27 @@ endif
} && \
for p in $(filter $(install_bindir_programs),$(BUILT_INS)); do \
$(RM) "$$bindir/$$p" && \
- test -n "$(INSTALL_SYMLINKS)" && \
- ln -s "git$X" "$$bindir/$$p" || \
- { test -z "$(NO_INSTALL_HARDLINKS)" && \
- ln "$$bindir/git$X" "$$bindir/$$p" 2>/dev/null || \
- ln -s "git$X" "$$bindir/$$p" 2>/dev/null || \
- cp "$$bindir/git$X" "$$bindir/$$p" || exit; } \
+ if test -z "$(SKIP_DASHED_BUILT_INS)"; \
+ then \
+ test -n "$(INSTALL_SYMLINKS)" && \
+ ln -s "git$X" "$$bindir/$$p" || \
+ { test -z "$(NO_INSTALL_HARDLINKS)" && \
+ ln "$$bindir/git$X" "$$bindir/$$p" 2>/dev/null || \
+ ln -s "git$X" "$$bindir/$$p" 2>/dev/null || \
+ cp "$$bindir/git$X" "$$bindir/$$p" || exit; }; \
+ fi \
done && \
for p in $(BUILT_INS); do \
$(RM) "$$execdir/$$p" && \
- test -n "$(INSTALL_SYMLINKS)" && \
- ln -s "$$destdir_from_execdir_SQ/$(bindir_relative_SQ)/git$X" "$$execdir/$$p" || \
- { test -z "$(NO_INSTALL_HARDLINKS)" && \
- ln "$$execdir/git$X" "$$execdir/$$p" 2>/dev/null || \
- ln -s "git$X" "$$execdir/$$p" 2>/dev/null || \
- cp "$$execdir/git$X" "$$execdir/$$p" || exit; } \
+ if test -z "$(SKIP_DASHED_BUILT_INS)"; \
+ then \
+ test -n "$(INSTALL_SYMLINKS)" && \
+ ln -s "$$destdir_from_execdir_SQ/$(bindir_relative_SQ)/git$X" "$$execdir/$$p" || \
+ { test -z "$(NO_INSTALL_HARDLINKS)" && \
+ ln "$$execdir/git$X" "$$execdir/$$p" 2>/dev/null || \
+ ln -s "git$X" "$$execdir/$$p" 2>/dev/null || \
+ cp "$$execdir/git$X" "$$execdir/$$p" || exit; }; \
+ fi \
done && \
remote_curl_aliases="$(REMOTE_CURL_ALIASES)" && \
for p in $$remote_curl_aliases; do \
@@ -3083,7 +3095,7 @@ ifneq ($(INCLUDE_DLLS_IN_ARTIFACTS),)
OTHER_PROGRAMS += $(shell echo *.dll t/helper/*.dll)
endif
-artifacts-tar:: $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) $(OTHER_PROGRAMS) \
+artifacts-tar:: $(ALL_COMMANDS_TO_INSTALL) $(SCRIPT_LIB) $(OTHER_PROGRAMS) \
GIT-BUILD-OPTIONS $(TEST_PROGRAMS) $(test_bindir_programs) \
$(MOFILES)
$(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1) \
@@ -3178,7 +3190,7 @@ endif
### Check documentation
#
-ALL_COMMANDS = $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS)
+ALL_COMMANDS = $(ALL_COMMANDS_TO_INSTALL) $(SCRIPT_LIB)
ALL_COMMANDS += git
ALL_COMMANDS += git-citool
ALL_COMMANDS += git-gui
@@ -3218,7 +3230,7 @@ check-docs::
-e 's/\.txt//'; \
) | while read how cmd; \
do \
- case " $(patsubst %$X,%,$(ALL_COMMANDS) $(EXCLUDED_PROGRAMS)) " in \
+ case " $(patsubst %$X,%,$(ALL_COMMANDS) $(BUILT_INS) $(EXCLUDED_PROGRAMS)) " in \
*" $$cmd "*) ;; \
*) echo "removed but $$how: $$cmd" ;; \
esac; \
diff --git a/bisect.c b/bisect.c
index d42a3a3..f5b1368 100644
--- a/bisect.c
+++ b/bisect.c
@@ -988,8 +988,11 @@ void read_bisect_terms(const char **read_bad, const char **read_good)
* the bisection process finished successfully.
* In this case the calling function or command should not turn a
* BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND return code into an error or a non zero exit code.
- * If no_checkout is non-zero, the bisection process does not
- * checkout the trial commit but instead simply updates BISECT_HEAD.
+ *
+ * Checking BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND
+ * in bisect_helper::bisect_next() and only transforming it to 0 at
+ * the end of bisect_helper::cmd_bisect__helper() helps bypassing
+ * all the code related to finding a commit to test.
*/
enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
{
@@ -999,6 +1002,10 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
enum bisect_error res = BISECT_OK;
struct object_id *bisect_rev;
char *steps_msg;
+ /*
+ * If no_checkout is non-zero, the bisection process does not
+ * checkout the trial commit but instead simply updates BISECT_HEAD.
+ */
int no_checkout = ref_exists("BISECT_HEAD");
unsigned bisect_flags = 0;
@@ -1082,6 +1089,8 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
"Bisecting: %d revisions left to test after this %s\n",
nr), nr, steps_msg);
free(steps_msg);
+ /* Clean up objects used, as they will be reused. */
+ clear_commit_marks_all(ALL_REV_FLAGS);
return bisect_checkout(bisect_rev, no_checkout);
}
diff --git a/blame.c b/blame.c
index b475bfa..686845b 100644
--- a/blame.c
+++ b/blame.c
@@ -1276,7 +1276,7 @@ static int maybe_changed_path(struct repository *r,
if (commit_graph_generation(origin->commit) == GENERATION_NUMBER_INFINITY)
return 1;
- filter = get_bloom_filter(r, origin->commit, 0);
+ filter = get_bloom_filter(r, origin->commit);
if (!filter)
return 1;
@@ -2892,16 +2892,18 @@ void setup_blame_bloom_data(struct blame_scoreboard *sb,
const char *path)
{
struct blame_bloom_data *bd;
+ struct bloom_filter_settings *bs;
if (!sb->repo->objects->commit_graph)
return;
- if (!sb->repo->objects->commit_graph->bloom_filter_settings)
+ bs = get_bloom_filter_settings(sb->repo);
+ if (!bs)
return;
bd = xmalloc(sizeof(struct blame_bloom_data));
- bd->settings = sb->repo->objects->commit_graph->bloom_filter_settings;
+ bd->settings = bs;
bd->alloc = 4;
bd->nr = 0;
diff --git a/bloom.c b/bloom.c
index 1a57322..68c7320 100644
--- a/bloom.c
+++ b/bloom.c
@@ -38,7 +38,7 @@ static int load_bloom_filter_from_graph(struct commit_graph *g,
while (graph_pos < g->num_commits_in_base)
g = g->base_graph;
- /* The commit graph commit 'c' lives in doesn't carry bloom filters. */
+ /* The commit graph commit 'c' lives in doesn't carry Bloom filters. */
if (!g->chunk_bloom_indexes)
return 0;
@@ -177,15 +177,25 @@ static int pathmap_cmp(const void *hashmap_cmp_fn_data,
return strcmp(e1->path, e2->path);
}
-struct bloom_filter *get_bloom_filter(struct repository *r,
- struct commit *c,
- int compute_if_not_present)
+static void init_truncated_large_filter(struct bloom_filter *filter)
+{
+ filter->data = xmalloc(1);
+ filter->data[0] = 0xFF;
+ filter->len = 1;
+}
+
+struct bloom_filter *get_or_compute_bloom_filter(struct repository *r,
+ struct commit *c,
+ int compute_if_not_present,
+ const struct bloom_filter_settings *settings,
+ enum bloom_filter_computed *computed)
{
struct bloom_filter *filter;
- struct bloom_filter_settings settings = DEFAULT_BLOOM_FILTER_SETTINGS;
int i;
struct diff_options diffopt;
- int max_changes = 512;
+
+ if (computed)
+ *computed = BLOOM_NOT_COMPUTED;
if (!bloom_filters.slab_size)
return NULL;
@@ -194,12 +204,11 @@ struct bloom_filter *get_bloom_filter(struct repository *r,
if (!filter->data) {
load_commit_graph_info(r, c);
- if (commit_graph_position(c) != COMMIT_NOT_FROM_GRAPH &&
- r->objects->commit_graph->chunk_bloom_indexes)
+ if (commit_graph_position(c) != COMMIT_NOT_FROM_GRAPH)
load_bloom_filter_from_graph(r->objects->commit_graph, filter, c);
}
- if (filter->data)
+ if (filter->data && filter->len)
return filter;
if (!compute_if_not_present)
return NULL;
@@ -207,7 +216,7 @@ struct bloom_filter *get_bloom_filter(struct repository *r,
repo_diff_setup(r, &diffopt);
diffopt.flags.recursive = 1;
diffopt.detect_rename = 0;
- diffopt.max_changes = max_changes;
+ diffopt.max_changes = settings->max_changed_paths;
diff_setup_done(&diffopt);
/* ensure commit is parsed so we have parent information */
@@ -219,7 +228,7 @@ struct bloom_filter *get_bloom_filter(struct repository *r,
diff_tree_oid(NULL, &c->object.oid, "", &diffopt);
diffcore_std(&diffopt);
- if (diffopt.num_changes <= max_changes) {
+ if (diff_queued_diff.nr <= settings->max_changed_paths) {
struct hashmap pathmap;
struct pathmap_hash_entry *e;
struct hashmap_iter iter;
@@ -256,23 +265,41 @@ struct bloom_filter *get_bloom_filter(struct repository *r,
diff_free_filepair(diff_queued_diff.queue[i]);
}
- filter->len = (hashmap_get_size(&pathmap) * settings.bits_per_entry + BITS_PER_WORD - 1) / BITS_PER_WORD;
+ if (hashmap_get_size(&pathmap) > settings->max_changed_paths) {
+ init_truncated_large_filter(filter);
+ if (computed)
+ *computed |= BLOOM_TRUNC_LARGE;
+ goto cleanup;
+ }
+
+ filter->len = (hashmap_get_size(&pathmap) * settings->bits_per_entry + BITS_PER_WORD - 1) / BITS_PER_WORD;
+ if (!filter->len) {
+ if (computed)
+ *computed |= BLOOM_TRUNC_EMPTY;
+ filter->len = 1;
+ }
filter->data = xcalloc(filter->len, sizeof(unsigned char));
hashmap_for_each_entry(&pathmap, &iter, e, entry) {
struct bloom_key key;
- fill_bloom_key(e->path, strlen(e->path), &key, &settings);
- add_key_to_filter(&key, filter, &settings);
+ fill_bloom_key(e->path, strlen(e->path), &key, settings);
+ add_key_to_filter(&key, filter, settings);
}
+ cleanup:
hashmap_free_entries(&pathmap, struct pathmap_hash_entry, entry);
} else {
for (i = 0; i < diff_queued_diff.nr; i++)
diff_free_filepair(diff_queued_diff.queue[i]);
- filter->data = NULL;
- filter->len = 0;
+ init_truncated_large_filter(filter);
+
+ if (computed)
+ *computed |= BLOOM_TRUNC_LARGE;
}
+ if (computed)
+ *computed |= BLOOM_COMPUTED;
+
free(diff_queued_diff.queue);
DIFF_QUEUE_CLEAR(&diff_queued_diff);
diff --git a/bloom.h b/bloom.h
index d8fbb0f..adde6df 100644
--- a/bloom.h
+++ b/bloom.h
@@ -28,9 +28,18 @@ struct bloom_filter_settings {
* that contain n*b bits.
*/
uint32_t bits_per_entry;
+
+ /*
+ * The maximum number of changed paths per commit
+ * before declaring a Bloom filter to be too-large.
+ *
+ * Not written to the commit-graph file.
+ */
+ uint32_t max_changed_paths;
};
-#define DEFAULT_BLOOM_FILTER_SETTINGS { 1, 7, 10 }
+#define DEFAULT_BLOOM_MAX_CHANGES 512
+#define DEFAULT_BLOOM_FILTER_SETTINGS { 1, 7, 10, DEFAULT_BLOOM_MAX_CHANGES }
#define BITS_PER_WORD 8
#define BLOOMDATA_CHUNK_HEADER_SIZE 3 * sizeof(uint32_t)
@@ -80,9 +89,21 @@ void add_key_to_filter(const struct bloom_key *key,
void init_bloom_filters(void);
-struct bloom_filter *get_bloom_filter(struct repository *r,
- struct commit *c,
- int compute_if_not_present);
+enum bloom_filter_computed {
+ BLOOM_NOT_COMPUTED = (1 << 0),
+ BLOOM_COMPUTED = (1 << 1),
+ BLOOM_TRUNC_LARGE = (1 << 2),
+ BLOOM_TRUNC_EMPTY = (1 << 3),
+};
+
+struct bloom_filter *get_or_compute_bloom_filter(struct repository *r,
+ struct commit *c,
+ int compute_if_not_present,
+ const struct bloom_filter_settings *settings,
+ enum bloom_filter_computed *computed);
+
+#define get_bloom_filter(r, c) get_or_compute_bloom_filter( \
+ (r), (c), 0, NULL, NULL)
int bloom_filter_contains(const struct bloom_filter *filter,
const struct bloom_key *key,
diff --git a/builtin.h b/builtin.h
index ba954e1..53fb290 100644
--- a/builtin.h
+++ b/builtin.h
@@ -172,6 +172,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix);
int cmd_ls_remote(int argc, const char **argv, const char *prefix);
int cmd_mailinfo(int argc, const char **argv, const char *prefix);
int cmd_mailsplit(int argc, const char **argv, const char *prefix);
+int cmd_maintenance(int argc, const char **argv, const char *prefix);
int cmd_merge(int argc, const char **argv, const char *prefix);
int cmd_merge_base(int argc, const char **argv, const char *prefix);
int cmd_merge_index(int argc, const char **argv, const char *prefix);
diff --git a/builtin/am.c b/builtin/am.c
index b5c63dd..7259186 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -1813,7 +1813,7 @@ next:
if (!state->rebasing) {
am_destroy(state);
close_object_store(the_repository->objects);
- run_auto_gc(state->quiet);
+ run_auto_maintenance(state->quiet);
}
}
diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 7dcc1b5..7512b88 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -8,6 +8,7 @@
#include "run-command.h"
#include "prompt.h"
#include "quote.h"
+#include "revision.h"
static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
@@ -29,9 +30,17 @@ static const char * const git_bisect_helper_usage[] = {
N_("git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]"),
N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
" [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
+ N_("git bisect--helper --bisect-next"),
+ N_("git bisect--helper --bisect-auto-next"),
+ N_("git bisect--helper --bisect-autostart"),
NULL
};
+struct add_bisect_ref_data {
+ struct rev_info *revs;
+ unsigned int object_flags;
+};
+
struct bisect_terms {
char *term_good;
char *term_bad;
@@ -55,6 +64,8 @@ static void set_terms(struct bisect_terms *terms, const char *bad,
static const char vocab_bad[] = "bad|new";
static const char vocab_good[] = "good|old";
+static int bisect_autostart(struct bisect_terms *terms);
+
/*
* Check whether the string `term` belongs to the set of strings
* included in the variable arguments.
@@ -74,6 +85,52 @@ static int one_of(const char *term, ...)
return res;
}
+static int write_in_file(const char *path, const char *mode, const char *format, va_list args)
+{
+ FILE *fp = NULL;
+ int res = 0;
+
+ if (strcmp(mode, "w") && strcmp(mode, "a"))
+ BUG("write-in-file does not support '%s' mode", mode);
+ fp = fopen(path, mode);
+ if (!fp)
+ return error_errno(_("cannot open file '%s' in mode '%s'"), path, mode);
+ res = vfprintf(fp, format, args);
+
+ if (res < 0) {
+ int saved_errno = errno;
+ fclose(fp);
+ errno = saved_errno;
+ return error_errno(_("could not write to file '%s'"), path);
+ }
+
+ return fclose(fp);
+}
+
+static int write_to_file(const char *path, const char *format, ...)
+{
+ int res;
+ va_list args;
+
+ va_start(args, format);
+ res = write_in_file(path, "w", format, args);
+ va_end(args);
+
+ return res;
+}
+
+static int append_to_file(const char *path, const char *format, ...)
+{
+ int res;
+ va_list args;
+
+ va_start(args, format);
+ res = write_in_file(path, "a", format, args);
+ va_end(args);
+
+ return res;
+}
+
static int check_term_format(const char *term, const char *orig_term)
{
int res;
@@ -104,7 +161,6 @@ static int check_term_format(const char *term, const char *orig_term)
static int write_terms(const char *bad, const char *good)
{
- FILE *fp = NULL;
int res;
if (!strcmp(bad, good))
@@ -113,13 +169,9 @@ static int write_terms(const char *bad, const char *good)
if (check_term_format(bad, "bad") || check_term_format(good, "good"))
return -1;
- fp = fopen(git_path_bisect_terms(), "w");
- if (!fp)
- return error_errno(_("could not open the file BISECT_TERMS"));
+ res = write_to_file(git_path_bisect_terms(), "%s\n%s\n", bad, good);
- res = fprintf(fp, "%s\n%s\n", bad, good);
- res |= fclose(fp);
- return (res < 0) ? -1 : 0;
+ return res;
}
static int is_expected_rev(const char *expected_hex)
@@ -421,6 +473,142 @@ finish:
return res;
}
+static int add_bisect_ref(const char *refname, const struct object_id *oid,
+ int flags, void *cb)
+{
+ struct add_bisect_ref_data *data = cb;
+
+ add_pending_oid(data->revs, refname, oid, data->object_flags);
+
+ return 0;
+}
+
+static int prepare_revs(struct bisect_terms *terms, struct rev_info *revs)
+{
+ int res = 0;
+ struct add_bisect_ref_data cb = { revs };
+ char *good = xstrfmt("%s-*", terms->term_good);
+
+ /*
+ * We cannot use terms->term_bad directly in
+ * for_each_glob_ref_in() and we have to append a '*' to it,
+ * otherwise for_each_glob_ref_in() will append '/' and '*'.
+ */
+ char *bad = xstrfmt("%s*", terms->term_bad);
+
+ /*
+ * It is important to reset the flags used by revision walks
+ * as the previous call to bisect_next_all() in turn
+ * sets up a revision walk.
+ */
+ reset_revision_walk();
+ init_revisions(revs, NULL);
+ setup_revisions(0, NULL, revs, NULL);
+ for_each_glob_ref_in(add_bisect_ref, bad, "refs/bisect/", &cb);
+ cb.object_flags = UNINTERESTING;
+ for_each_glob_ref_in(add_bisect_ref, good, "refs/bisect/", &cb);
+ if (prepare_revision_walk(revs))
+ res = error(_("revision walk setup failed\n"));
+
+ free(good);
+ free(bad);
+ return res;
+}
+
+static int bisect_skipped_commits(struct bisect_terms *terms)
+{
+ int res;
+ FILE *fp = NULL;
+ struct rev_info revs;
+ struct commit *commit;
+ struct pretty_print_context pp = {0};
+ struct strbuf commit_name = STRBUF_INIT;
+
+ res = prepare_revs(terms, &revs);
+ if (res)
+ return res;
+
+ fp = fopen(git_path_bisect_log(), "a");
+ if (!fp)
+ return error_errno(_("could not open '%s' for appending"),
+ git_path_bisect_log());
+
+ if (fprintf(fp, "# only skipped commits left to test\n") < 0)
+ return error_errno(_("failed to write to '%s'"), git_path_bisect_log());
+
+ while ((commit = get_revision(&revs)) != NULL) {
+ strbuf_reset(&commit_name);
+ format_commit_message(commit, "%s",
+ &commit_name, &pp);
+ fprintf(fp, "# possible first %s commit: [%s] %s\n",
+ terms->term_bad, oid_to_hex(&commit->object.oid),
+ commit_name.buf);
+ }
+
+ /*
+ * Reset the flags used by revision walks in case
+ * there is another revision walk after this one.
+ */
+ reset_revision_walk();
+
+ strbuf_release(&commit_name);
+ fclose(fp);
+ return 0;
+}
+
+static int bisect_successful(struct bisect_terms *terms)
+{
+ struct object_id oid;
+ struct commit *commit;
+ struct pretty_print_context pp = {0};
+ struct strbuf commit_name = STRBUF_INIT;
+ char *bad_ref = xstrfmt("refs/bisect/%s",terms->term_bad);
+ int res;
+
+ read_ref(bad_ref, &oid);
+ commit = lookup_commit_reference_by_name(bad_ref);
+ format_commit_message(commit, "%s", &commit_name, &pp);
+
+ res = append_to_file(git_path_bisect_log(), "# first %s commit: [%s] %s\n",
+ terms->term_bad, oid_to_hex(&commit->object.oid),
+ commit_name.buf);
+
+ strbuf_release(&commit_name);
+ free(bad_ref);
+ return res;
+}
+
+static enum bisect_error bisect_next(struct bisect_terms *terms, const char *prefix)
+{
+ enum bisect_error res;
+
+ if (bisect_autostart(terms))
+ return BISECT_FAILED;
+
+ if (bisect_next_check(terms, terms->term_good))
+ return BISECT_FAILED;
+
+ /* Perform all bisection computation */
+ res = bisect_next_all(the_repository, prefix);
+
+ if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
+ res = bisect_successful(terms);
+ return res ? res : BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND;
+ } else if (res == BISECT_ONLY_SKIPPED_LEFT) {
+ res = bisect_skipped_commits(terms);
+ return res ? res : BISECT_ONLY_SKIPPED_LEFT;
+ }
+ return res;
+}
+
+static enum bisect_error bisect_auto_next(struct bisect_terms *terms, const char *prefix)
+{
+ if (bisect_next_check(terms, NULL))
+ return BISECT_OK;
+
+ return bisect_next(terms, prefix);
+}
+
static int bisect_start(struct bisect_terms *terms, const char **argv, int argc)
{
int no_checkout = 0;
@@ -484,14 +672,13 @@ static int bisect_start(struct bisect_terms *terms, const char **argv, int argc)
terms->term_bad = xstrdup(arg);
} else if (starts_with(arg, "--")) {
return error(_("unrecognized option: '%s'"), arg);
- } else {
- char *commit_id = xstrfmt("%s^{commit}", arg);
- if (get_oid(commit_id, &oid) && has_double_dash)
- die(_("'%s' does not appear to be a valid "
- "revision"), arg);
-
+ } else if (!get_oidf(&oid, "%s^{commit}", arg)) {
string_list_append(&revs, oid_to_hex(&oid));
- free(commit_id);
+ } else if (has_double_dash) {
+ die(_("'%s' does not appear to be a valid "
+ "revision"), arg);
+ } else {
+ break;
}
}
pathspec_pos = i;
@@ -624,6 +811,38 @@ finish:
return res;
}
+static inline int file_is_not_empty(const char *path)
+{
+ return !is_empty_or_missing_file(path);
+}
+
+static int bisect_autostart(struct bisect_terms *terms)
+{
+ int res;
+ const char *yesno;
+
+ if (file_is_not_empty(git_path_bisect_start()))
+ return 0;
+
+ fprintf_ln(stderr, _("You need to start by \"git bisect "
+ "start\"\n"));
+
+ if (!isatty(STDIN_FILENO))
+ return -1;
+
+ /*
+ * TRANSLATORS: Make sure to include [Y] and [n] in your
+ * translation. The program will only accept English input
+ * at this point.
+ */
+ yesno = git_prompt(_("Do you want me to do it for you "
+ "[Y/n]? "), PROMPT_ECHO);
+ res = tolower(*yesno) == 'n' ?
+ -1 : bisect_start(terms, empty_strvec, 0);
+
+ return res;
+}
+
int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
{
enum {
@@ -636,7 +855,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
CHECK_AND_SET_TERMS,
BISECT_NEXT_CHECK,
BISECT_TERMS,
- BISECT_START
+ BISECT_START,
+ BISECT_AUTOSTART,
+ BISECT_NEXT,
+ BISECT_AUTO_NEXT
} cmdmode = 0;
int res = 0, nolog = 0;
struct option options[] = {
@@ -660,6 +882,12 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
N_("print out the bisect terms"), BISECT_TERMS),
OPT_CMDMODE(0, "bisect-start", &cmdmode,
N_("start the bisect session"), BISECT_START),
+ OPT_CMDMODE(0, "bisect-next", &cmdmode,
+ N_("find the next bisection commit"), BISECT_NEXT),
+ OPT_CMDMODE(0, "bisect-auto-next", &cmdmode,
+ N_("verify the next bisection state then checkout the next bisection commit"), BISECT_AUTO_NEXT),
+ OPT_CMDMODE(0, "bisect-autostart", &cmdmode,
+ N_("start the bisection if it has not yet been started"), BISECT_AUTOSTART),
OPT_BOOL(0, "no-log", &nolog,
N_("no log for BISECT_WRITE")),
OPT_END()
@@ -719,8 +947,26 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
set_terms(&terms, "bad", "good");
res = bisect_start(&terms, argv, argc);
break;
+ case BISECT_NEXT:
+ if (argc)
+ return error(_("--bisect-next requires 0 arguments"));
+ get_terms(&terms);
+ res = bisect_next(&terms, prefix);
+ break;
+ case BISECT_AUTO_NEXT:
+ if (argc)
+ return error(_("--bisect-auto-next requires 0 arguments"));
+ get_terms(&terms);
+ res = bisect_auto_next(&terms, prefix);
+ break;
+ case BISECT_AUTOSTART:
+ if (argc)
+ return error(_("--bisect-autostart does not accept arguments"));
+ set_terms(&terms, "bad", "good");
+ res = bisect_autostart(&terms);
+ break;
default:
- return error("BUG: unknown subcommand '%d'", cmdmode);
+ BUG("unknown subcommand %d", cmdmode);
}
free_terms(&terms);
@@ -728,8 +974,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
* Handle early success
* From check_merge_bases > check_good_are_ancestors_of_bad > bisect_next_all
*/
- if (res == BISECT_INTERNAL_SUCCESS_MERGE_BASE)
+ if ((res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) || (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND))
res = BISECT_OK;
- return abs(res);
+ return -res;
}
diff --git a/builtin/blame.c b/builtin/blame.c
index eb513fb..bb0f293 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -27,6 +27,7 @@
#include "object-store.h"
#include "blame.h"
#include "refs.h"
+#include "tag.h"
static char blame_usage[] = N_("git blame [<options>] [<rev-opts>] [<rev>] [--] <file>");
@@ -803,6 +804,26 @@ static int is_a_rev(const char *name)
return OBJ_NONE < oid_object_info(the_repository, &oid, NULL);
}
+static int peel_to_commit_oid(struct object_id *oid_ret, void *cbdata)
+{
+ struct repository *r = ((struct blame_scoreboard *)cbdata)->repo;
+ struct object_id oid;
+
+ oidcpy(&oid, oid_ret);
+ while (1) {
+ struct object *obj;
+ int kind = oid_object_info(r, &oid, NULL);
+ if (kind == OBJ_COMMIT) {
+ oidcpy(oid_ret, &oid);
+ return 0;
+ }
+ if (kind != OBJ_TAG)
+ return -1;
+ obj = deref_tag(r, parse_object(r, &oid), NULL, 0);
+ oidcpy(&oid, &obj->oid);
+ }
+}
+
static void build_ignorelist(struct blame_scoreboard *sb,
struct string_list *ignore_revs_file_list,
struct string_list *ignore_rev_list)
@@ -815,10 +836,12 @@ static void build_ignorelist(struct blame_scoreboard *sb,
if (!strcmp(i->string, ""))
oidset_clear(&sb->ignore_list);
else
- oidset_parse_file(&sb->ignore_list, i->string);
+ oidset_parse_file_carefully(&sb->ignore_list, i->string,
+ peel_to_commit_oid, sb);
}
for_each_string_list_item(i, ignore_rev_list) {
- if (get_oid_committish(i->string, &oid))
+ if (get_oid_committish(i->string, &oid) ||
+ peel_to_commit_oid(&oid, sb))
die(_("cannot find revision %s to ignore"), i->string);
oidset_insert(&sb->ignore_list, &oid);
}
diff --git a/builtin/clone.c b/builtin/clone.c
index fbfd656..391aa41 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -1233,7 +1233,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
* Now that we know what algorithm the remote side is using,
* let's set ours to the same thing.
*/
- initialize_repository_version(hash_algo);
+ initialize_repository_version(hash_algo, 1);
repo_set_hash_algo(the_repository, hash_algo);
mapped_refs = wanted_peer_refs(refs, &remote->fetch);
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index 523501f..988445a 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -13,7 +13,8 @@ static char const * const builtin_commit_graph_usage[] = {
N_("git commit-graph verify [--object-dir <objdir>] [--shallow] [--[no-]progress]"),
N_("git commit-graph write [--object-dir <objdir>] [--append] "
"[--split[=<strategy>]] [--reachable|--stdin-packs|--stdin-commits] "
- "[--changed-paths] [--[no-]progress] <split options>"),
+ "[--changed-paths] [--[no-]max-new-filters <n>] [--[no-]progress] "
+ "<split options>"),
NULL
};
@@ -25,7 +26,8 @@ static const char * const builtin_commit_graph_verify_usage[] = {
static const char * const builtin_commit_graph_write_usage[] = {
N_("git commit-graph write [--object-dir <objdir>] [--append] "
"[--split[=<strategy>]] [--reachable|--stdin-packs|--stdin-commits] "
- "[--changed-paths] [--[no-]progress] <split options>"),
+ "[--changed-paths] [--[no-]max-new-filters <n>] [--[no-]progress] "
+ "<split options>"),
NULL
};
@@ -106,7 +108,7 @@ static int graph_verify(int argc, const char **argv)
FREE_AND_NULL(graph_name);
if (open_ok)
- graph = load_commit_graph_one_fd_st(fd, &st, odb);
+ graph = load_commit_graph_one_fd_st(the_repository, fd, &st, odb);
else
graph = read_commit_graph_one(the_repository, odb);
@@ -119,7 +121,7 @@ static int graph_verify(int argc, const char **argv)
}
extern int read_replace_refs;
-static struct split_commit_graph_opts split_opts;
+static struct commit_graph_opts write_opts;
static int write_option_parse_split(const struct option *opt, const char *arg,
int unset)
@@ -162,6 +164,35 @@ static int read_one_commit(struct oidset *commits, struct progress *progress,
return 0;
}
+static int write_option_max_new_filters(const struct option *opt,
+ const char *arg,
+ int unset)
+{
+ int *to = opt->value;
+ if (unset)
+ *to = -1;
+ else {
+ const char *s;
+ *to = strtol(arg, (char **)&s, 10);
+ if (*s)
+ return error(_("%s expects a numerical value"),
+ optname(opt, opt->flags));
+ }
+ return 0;
+}
+
+static int git_commit_graph_write_config(const char *var, const char *value,
+ void *cb)
+{
+ if (!strcmp(var, "commitgraph.maxnewfilters"))
+ write_opts.max_new_filters = git_config_int(var, value);
+ /*
+ * No need to fall-back to 'git_default_config', since this was already
+ * called in 'cmd_commit_graph()'.
+ */
+ return 0;
+}
+
static int graph_write(int argc, const char **argv)
{
struct string_list pack_indexes = STRING_LIST_INIT_NODUP;
@@ -187,27 +218,33 @@ static int graph_write(int argc, const char **argv)
OPT_BOOL(0, "changed-paths", &opts.enable_changed_paths,
N_("enable computation for changed paths")),
OPT_BOOL(0, "progress", &opts.progress, N_("force progress reporting")),
- OPT_CALLBACK_F(0, "split", &split_opts.flags, NULL,
+ OPT_CALLBACK_F(0, "split", &write_opts.split_flags, NULL,
N_("allow writing an incremental commit-graph file"),
PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
write_option_parse_split),
- OPT_INTEGER(0, "max-commits", &split_opts.max_commits,
+ OPT_INTEGER(0, "max-commits", &write_opts.max_commits,
N_("maximum number of commits in a non-base split commit-graph")),
- OPT_INTEGER(0, "size-multiple", &split_opts.size_multiple,
+ OPT_INTEGER(0, "size-multiple", &write_opts.size_multiple,
N_("maximum ratio between two levels of a split commit-graph")),
- OPT_EXPIRY_DATE(0, "expire-time", &split_opts.expire_time,
+ OPT_EXPIRY_DATE(0, "expire-time", &write_opts.expire_time,
N_("only expire files older than a given date-time")),
+ OPT_CALLBACK_F(0, "max-new-filters", &write_opts.max_new_filters,
+ NULL, N_("maximum number of changed-path Bloom filters to compute"),
+ 0, write_option_max_new_filters),
OPT_END(),
};
opts.progress = isatty(2);
opts.enable_changed_paths = -1;
- split_opts.size_multiple = 2;
- split_opts.max_commits = 0;
- split_opts.expire_time = 0;
+ write_opts.size_multiple = 2;
+ write_opts.max_commits = 0;
+ write_opts.expire_time = 0;
+ write_opts.max_new_filters = -1;
trace2_cmd_mode("write");
+ git_config(git_commit_graph_write_config, &opts);
+
argc = parse_options(argc, argv, NULL,
builtin_commit_graph_write_options,
builtin_commit_graph_write_usage, 0);
@@ -232,7 +269,7 @@ static int graph_write(int argc, const char **argv)
odb = find_odb(the_repository, opts.obj_dir);
if (opts.reachable) {
- if (write_commit_graph_reachable(odb, flags, &split_opts))
+ if (write_commit_graph_reachable(odb, flags, &write_opts))
return 1;
return 0;
}
@@ -261,7 +298,7 @@ static int graph_write(int argc, const char **argv)
opts.stdin_packs ? &pack_indexes : NULL,
opts.stdin_commits ? &commits : NULL,
flags,
- &split_opts))
+ &write_opts))
result = 1;
cleanup:
diff --git a/builtin/commit.c b/builtin/commit.c
index 5d91b13..42b964e 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1700,7 +1700,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
git_test_write_commit_graph_or_die();
repo_rerere(the_repository, 0);
- run_auto_gc(quiet);
+ run_auto_maintenance(quiet);
run_commit_hook(use_editor, get_index_file(), "post-commit", NULL);
if (amend && !no_post_rewrite) {
commit_post_rewrite(the_repository, current_head, &oid);
diff --git a/builtin/diff.c b/builtin/diff.c
index cb98811..cd4083f 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -203,8 +203,7 @@ static int builtin_diff_combined(struct rev_info *revs,
revs->dense_combined_merges = revs->combine_merges = 1;
for (i = 1; i < ents; i++)
oid_array_append(&parents, &ent[i].item->oid);
- diff_tree_combined(&ent[0].item->oid, &parents,
- revs->dense_combined_merges, revs);
+ diff_tree_combined(&ent[0].item->oid, &parents, revs);
oid_array_clear(&parents);
return 0;
}
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 1b8fca3..d2e33f5 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -405,12 +405,12 @@ static char *generate_fake_oid(void *data)
{
static uint32_t counter = 1; /* avoid null oid */
const unsigned hashsz = the_hash_algo->rawsz;
- unsigned char out[GIT_MAX_RAWSZ];
+ struct object_id oid;
char *hex = xmallocz(GIT_MAX_HEXSZ);
- hashclr(out);
- put_be32(out + hashsz - 4, counter++);
- return hash_to_hex_algop_r(hex, out, the_hash_algo);
+ oidclr(&oid);
+ put_be32(oid.hash + hashsz - 4, counter++);
+ return oid_to_hex_r(hex, &oid);
}
static const char *anonymize_oid(const char *oid_hex)
@@ -1026,7 +1026,7 @@ static void handle_tags_and_duplicates(struct string_list *extras)
/*
* Getting here means we have a commit which
* was excluded by a negative refspec (e.g.
- * fast-export ^master master). If we are
+ * fast-export ^HEAD HEAD). If we are
* referencing excluded commits, set the ref
* to the exact commit. Otherwise, the user
* wants the branch exported but every commit
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 1b00c2b..d5bf526 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -200,8 +200,10 @@ static struct option builtin_fetch_options[] = {
OPT_STRING_LIST(0, "negotiation-tip", &negotiation_tip, N_("revision"),
N_("report that we have only objects reachable from this object")),
OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
+ OPT_BOOL(0, "auto-maintenance", &enable_auto_gc,
+ N_("run 'maintenance --auto' after fetching")),
OPT_BOOL(0, "auto-gc", &enable_auto_gc,
- N_("run 'gc --auto' after fetching")),
+ N_("run 'maintenance --auto' after fetching")),
OPT_BOOL(0, "show-forced-updates", &fetch_show_forced_updates,
N_("check for forced-updates on all updated branches")),
OPT_BOOL(0, "write-commit-graph", &fetch_write_commit_graph,
@@ -1925,7 +1927,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
close_object_store(the_repository->objects);
if (enable_auto_gc)
- run_auto_gc(verbosity < 0);
+ run_auto_maintenance(verbosity < 0);
return result;
}
diff --git a/builtin/gc.c b/builtin/gc.c
index aafa094..0909593 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -28,6 +28,7 @@
#include "blob.h"
#include "tree.h"
#include "promisor-remote.h"
+#include "refs.h"
#define FAILED_RUN "failed to run %s"
@@ -699,3 +700,339 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
return 0;
}
+
+static const char * const builtin_maintenance_run_usage[] = {
+ N_("git maintenance run [--auto] [--[no-]quiet] [--task=<task>]"),
+ NULL
+};
+
+struct maintenance_run_opts {
+ int auto_flag;
+ int quiet;
+};
+
+/* Remember to update object flag allocation in object.h */
+#define SEEN (1u<<0)
+
+struct cg_auto_data {
+ int num_not_in_graph;
+ int limit;
+};
+
+static int dfs_on_ref(const char *refname,
+ const struct object_id *oid, int flags,
+ void *cb_data)
+{
+ struct cg_auto_data *data = (struct cg_auto_data *)cb_data;
+ int result = 0;
+ struct object_id peeled;
+ struct commit_list *stack = NULL;
+ struct commit *commit;
+
+ if (!peel_ref(refname, &peeled))
+ oid = &peeled;
+ if (oid_object_info(the_repository, oid, NULL) != OBJ_COMMIT)
+ return 0;
+
+ commit = lookup_commit(the_repository, oid);
+ if (!commit)
+ return 0;
+ if (parse_commit(commit))
+ return 0;
+
+ commit_list_append(commit, &stack);
+
+ while (!result && stack) {
+ struct commit_list *parent;
+
+ commit = pop_commit(&stack);
+
+ for (parent = commit->parents; parent; parent = parent->next) {
+ if (parse_commit(parent->item) ||
+ commit_graph_position(parent->item) != COMMIT_NOT_FROM_GRAPH ||
+ parent->item->object.flags & SEEN)
+ continue;
+
+ parent->item->object.flags |= SEEN;
+ data->num_not_in_graph++;
+
+ if (data->num_not_in_graph >= data->limit) {
+ result = 1;
+ break;
+ }
+
+ commit_list_append(parent->item, &stack);
+ }
+ }
+
+ free_commit_list(stack);
+ return result;
+}
+
+static int should_write_commit_graph(void)
+{
+ int result;
+ struct cg_auto_data data;
+
+ data.num_not_in_graph = 0;
+ data.limit = 100;
+ git_config_get_int("maintenance.commit-graph.auto",
+ &data.limit);
+
+ if (!data.limit)
+ return 0;
+ if (data.limit < 0)
+ return 1;
+
+ result = for_each_ref(dfs_on_ref, &data);
+
+ clear_commit_marks_all(SEEN);
+
+ return result;
+}
+
+static int run_write_commit_graph(struct maintenance_run_opts *opts)
+{
+ struct child_process child = CHILD_PROCESS_INIT;
+
+ child.git_cmd = 1;
+ strvec_pushl(&child.args, "commit-graph", "write",
+ "--split", "--reachable", NULL);
+
+ if (opts->quiet)
+ strvec_push(&child.args, "--no-progress");
+
+ return !!run_command(&child);
+}
+
+static int maintenance_task_commit_graph(struct maintenance_run_opts *opts)
+{
+ close_object_store(the_repository->objects);
+ if (run_write_commit_graph(opts)) {
+ error(_("failed to write commit-graph"));
+ return 1;
+ }
+
+ return 0;
+}
+
+static int maintenance_task_gc(struct maintenance_run_opts *opts)
+{
+ struct child_process child = CHILD_PROCESS_INIT;
+
+ child.git_cmd = 1;
+ strvec_push(&child.args, "gc");
+
+ if (opts->auto_flag)
+ strvec_push(&child.args, "--auto");
+ if (opts->quiet)
+ strvec_push(&child.args, "--quiet");
+ else
+ strvec_push(&child.args, "--no-quiet");
+
+ close_object_store(the_repository->objects);
+ return run_command(&child);
+}
+
+typedef int maintenance_task_fn(struct maintenance_run_opts *opts);
+
+/*
+ * An auto condition function returns 1 if the task should run
+ * and 0 if the task should NOT run. See needs_to_gc() for an
+ * example.
+ */
+typedef int maintenance_auto_fn(void);
+
+struct maintenance_task {
+ const char *name;
+ maintenance_task_fn *fn;
+ maintenance_auto_fn *auto_condition;
+ unsigned enabled:1;
+
+ /* -1 if not selected. */
+ int selected_order;
+};
+
+enum maintenance_task_label {
+ TASK_GC,
+ TASK_COMMIT_GRAPH,
+
+ /* Leave as final value */
+ TASK__COUNT
+};
+
+static struct maintenance_task tasks[] = {
+ [TASK_GC] = {
+ "gc",
+ maintenance_task_gc,
+ need_to_gc,
+ 1,
+ },
+ [TASK_COMMIT_GRAPH] = {
+ "commit-graph",
+ maintenance_task_commit_graph,
+ should_write_commit_graph,
+ },
+};
+
+static int compare_tasks_by_selection(const void *a_, const void *b_)
+{
+ const struct maintenance_task *a, *b;
+
+ a = (const struct maintenance_task *)&a_;
+ b = (const struct maintenance_task *)&b_;
+
+ return b->selected_order - a->selected_order;
+}
+
+static int maintenance_run_tasks(struct maintenance_run_opts *opts)
+{
+ int i, found_selected = 0;
+ int result = 0;
+ struct lock_file lk;
+ struct repository *r = the_repository;
+ char *lock_path = xstrfmt("%s/maintenance", r->objects->odb->path);
+
+ if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0) {
+ /*
+ * Another maintenance command is running.
+ *
+ * If --auto was provided, then it is likely due to a
+ * recursive process stack. Do not report an error in
+ * that case.
+ */
+ if (!opts->auto_flag && !opts->quiet)
+ warning(_("lock file '%s' exists, skipping maintenance"),
+ lock_path);
+ free(lock_path);
+ return 0;
+ }
+ free(lock_path);
+
+ for (i = 0; !found_selected && i < TASK__COUNT; i++)
+ found_selected = tasks[i].selected_order >= 0;
+
+ if (found_selected)
+ QSORT(tasks, TASK__COUNT, compare_tasks_by_selection);
+
+ for (i = 0; i < TASK__COUNT; i++) {
+ if (found_selected && tasks[i].selected_order < 0)
+ continue;
+
+ if (!found_selected && !tasks[i].enabled)
+ continue;
+
+ if (opts->auto_flag &&
+ (!tasks[i].auto_condition ||
+ !tasks[i].auto_condition()))
+ continue;
+
+ trace2_region_enter("maintenance", tasks[i].name, r);
+ if (tasks[i].fn(opts)) {
+ error(_("task '%s' failed"), tasks[i].name);
+ result = 1;
+ }
+ trace2_region_leave("maintenance", tasks[i].name, r);
+ }
+
+ rollback_lock_file(&lk);
+ return result;
+}
+
+static void initialize_task_config(void)
+{
+ int i;
+ struct strbuf config_name = STRBUF_INIT;
+ gc_config();
+
+ for (i = 0; i < TASK__COUNT; i++) {
+ int config_value;
+
+ strbuf_setlen(&config_name, 0);
+ strbuf_addf(&config_name, "maintenance.%s.enabled",
+ tasks[i].name);
+
+ if (!git_config_get_bool(config_name.buf, &config_value))
+ tasks[i].enabled = config_value;
+ }
+
+ strbuf_release(&config_name);
+}
+
+static int task_option_parse(const struct option *opt,
+ const char *arg, int unset)
+{
+ int i, num_selected = 0;
+ struct maintenance_task *task = NULL;
+
+ BUG_ON_OPT_NEG(unset);
+
+ for (i = 0; i < TASK__COUNT; i++) {
+ if (tasks[i].selected_order >= 0)
+ num_selected++;
+ if (!strcasecmp(tasks[i].name, arg)) {
+ task = &tasks[i];
+ }
+ }
+
+ if (!task) {
+ error(_("'%s' is not a valid task"), arg);
+ return 1;
+ }
+
+ if (task->selected_order >= 0) {
+ error(_("task '%s' cannot be selected multiple times"), arg);
+ return 1;
+ }
+
+ task->selected_order = num_selected + 1;
+
+ return 0;
+}
+
+static int maintenance_run(int argc, const char **argv, const char *prefix)
+{
+ int i;
+ struct maintenance_run_opts opts;
+ struct option builtin_maintenance_run_options[] = {
+ OPT_BOOL(0, "auto", &opts.auto_flag,
+ N_("run tasks based on the state of the repository")),
+ OPT_BOOL(0, "quiet", &opts.quiet,
+ N_("do not report progress or other information over stderr")),
+ OPT_CALLBACK_F(0, "task", NULL, N_("task"),
+ N_("run a specific task"),
+ PARSE_OPT_NONEG, task_option_parse),
+ OPT_END()
+ };
+ memset(&opts, 0, sizeof(opts));
+
+ opts.quiet = !isatty(2);
+ initialize_task_config();
+
+ for (i = 0; i < TASK__COUNT; i++)
+ tasks[i].selected_order = -1;
+
+ argc = parse_options(argc, argv, prefix,
+ builtin_maintenance_run_options,
+ builtin_maintenance_run_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+
+ if (argc != 0)
+ usage_with_options(builtin_maintenance_run_usage,
+ builtin_maintenance_run_options);
+ return maintenance_run_tasks(&opts);
+}
+
+static const char builtin_maintenance_usage[] = N_("git maintenance run [<options>]");
+
+int cmd_maintenance(int argc, const char **argv, const char *prefix)
+{
+ if (argc < 2 ||
+ (argc == 2 && !strcmp(argv[1], "-h")))
+ usage(builtin_maintenance_usage);
+
+ if (!strcmp(argv[1], "run"))
+ return maintenance_run(argc - 1, argv + 1, prefix);
+
+ die(_("invalid subcommand: %s"), argv[1]);
+}
diff --git a/builtin/init-db.c b/builtin/init-db.c
index cd3e760..01bc648 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -179,7 +179,7 @@ static int needs_work_tree_config(const char *git_dir, const char *work_tree)
return 1;
}
-void initialize_repository_version(int hash_algo)
+void initialize_repository_version(int hash_algo, int reinit)
{
char repo_version_string[10];
int repo_version = GIT_REPO_VERSION;
@@ -195,6 +195,8 @@ void initialize_repository_version(int hash_algo)
if (hash_algo != GIT_HASH_SHA1)
git_config_set("extensions.objectformat",
hash_algos[hash_algo].name);
+ else if (reinit)
+ git_config_set_gently("extensions.objectformat", NULL);
}
static int create_default_files(const char *template_path,
@@ -277,7 +279,7 @@ static int create_default_files(const char *template_path,
free(ref);
}
- initialize_repository_version(fmt->hash_algo);
+ initialize_repository_version(fmt->hash_algo, 0);
/* Check filemode trustability */
path = git_path_buf(&buf, "config");
diff --git a/builtin/log.c b/builtin/log.c
index b8824d8..7f27e9e 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -1195,6 +1195,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
log.in1 = 2;
log.in2 = 4;
log.file = rev->diffopt.file;
+ log.groups = SHORTLOG_GROUP_AUTHOR;
for (i = 0; i < nr; i++)
shortlog_add_commit(&log, list[i]);
diff --git a/builtin/merge.c b/builtin/merge.c
index 032a8f5..9d5359e 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -456,7 +456,7 @@ static void finish(struct commit *head_commit,
* user should see them.
*/
close_object_store(the_repository->objects);
- run_auto_gc(verbosity < 0);
+ run_auto_maintenance(verbosity < 0);
}
}
if (new_head && show_diffstat) {
diff --git a/builtin/pull.c b/builtin/pull.c
index 015f6de..425950f 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -344,8 +344,7 @@ static enum rebase_type config_get_rebase(void)
if (!git_config_get_value("pull.rebase", &value))
return parse_config_rebase("pull.rebase", value, 1);
- if (opt_verbosity >= 0 &&
- (!opt_ff || strcmp(opt_ff, "--ff-only"))) {
+ if (opt_verbosity >= 0 && !opt_ff) {
warning(_("Pulling without specifying how to reconcile divergent branches is\n"
"discouraged. You can squelch this message by running one of the following\n"
"commands sometime before your next pull:\n"
diff --git a/builtin/rebase.c b/builtin/rebase.c
index c4ff203..eeca533 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -734,10 +734,10 @@ static int finish_rebase(struct rebase_options *opts)
apply_autostash(state_dir_path("autostash", opts));
close_object_store(the_repository->objects);
/*
- * We ignore errors in 'gc --auto', since the
+ * We ignore errors in 'git maintenance run --auto', since the
* user should see them.
*/
- run_auto_gc(!(opts->flags & (REBASE_NO_QUIET|REBASE_VERBOSE)));
+ run_auto_maintenance(!(opts->flags & (REBASE_NO_QUIET|REBASE_VERBOSE)));
if (opts->type == REBASE_MERGE) {
struct replay_opts replay = REPLAY_OPTS_INIT;
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 439f29d..bb9909c 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -57,6 +57,7 @@ static int advertise_push_options;
static int unpack_limit = 100;
static off_t max_input_size;
static int report_status;
+static int report_status_v2;
static int use_sideband;
static int use_atomic;
static int use_push_options;
@@ -97,6 +98,17 @@ static int keepalive_in_sec = 5;
static struct tmp_objdir *tmp_objdir;
+static struct proc_receive_ref {
+ unsigned int want_add:1,
+ want_delete:1,
+ want_modify:1,
+ negative_ref:1;
+ char *ref_prefix;
+ struct proc_receive_ref *next;
+} *proc_receive_ref;
+
+static void proc_receive_ref_append(const char *prefix);
+
static enum deny_action parse_deny_action(const char *var, const char *value)
{
if (value) {
@@ -229,6 +241,13 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
return 0;
}
+ if (strcmp(var, "receive.procreceiverefs") == 0) {
+ if (!value)
+ return config_error_nonbool(var);
+ proc_receive_ref_append(value);
+ return 0;
+ }
+
return git_default_config(var, value, cb);
}
@@ -240,7 +259,7 @@ static void show_ref(const char *path, const struct object_id *oid)
struct strbuf cap = STRBUF_INIT;
strbuf_addstr(&cap,
- "report-status delete-refs side-band-64k quiet");
+ "report-status report-status-v2 delete-refs side-band-64k quiet");
if (advertise_atomic_push)
strbuf_addstr(&cap, " atomic");
if (prefer_ofs_delta)
@@ -310,17 +329,94 @@ static void write_head_info(void)
packet_flush(1);
}
+#define RUN_PROC_RECEIVE_SCHEDULED 1
+#define RUN_PROC_RECEIVE_RETURNED 2
struct command {
struct command *next;
const char *error_string;
+ struct ref_push_report *report;
unsigned int skip_update:1,
- did_not_exist:1;
+ did_not_exist:1,
+ run_proc_receive:2;
int index;
struct object_id old_oid;
struct object_id new_oid;
char ref_name[FLEX_ARRAY]; /* more */
};
+static void proc_receive_ref_append(const char *prefix)
+{
+ struct proc_receive_ref *ref_pattern;
+ char *p;
+ int len;
+
+ ref_pattern = xcalloc(1, sizeof(struct proc_receive_ref));
+ p = strchr(prefix, ':');
+ if (p) {
+ while (prefix < p) {
+ if (*prefix == 'a')
+ ref_pattern->want_add = 1;
+ else if (*prefix == 'd')
+ ref_pattern->want_delete = 1;
+ else if (*prefix == 'm')
+ ref_pattern->want_modify = 1;
+ else if (*prefix == '!')
+ ref_pattern->negative_ref = 1;
+ prefix++;
+ }
+ prefix++;
+ } else {
+ ref_pattern->want_add = 1;
+ ref_pattern->want_delete = 1;
+ ref_pattern->want_modify = 1;
+ }
+ len = strlen(prefix);
+ while (len && prefix[len - 1] == '/')
+ len--;
+ ref_pattern->ref_prefix = xmemdupz(prefix, len);
+ if (!proc_receive_ref) {
+ proc_receive_ref = ref_pattern;
+ } else {
+ struct proc_receive_ref *end;
+
+ end = proc_receive_ref;
+ while (end->next)
+ end = end->next;
+ end->next = ref_pattern;
+ }
+}
+
+static int proc_receive_ref_matches(struct command *cmd)
+{
+ struct proc_receive_ref *p;
+
+ if (!proc_receive_ref)
+ return 0;
+
+ for (p = proc_receive_ref; p; p = p->next) {
+ const char *match = p->ref_prefix;
+ const char *remains;
+
+ if (!p->want_add && is_null_oid(&cmd->old_oid))
+ continue;
+ else if (!p->want_delete && is_null_oid(&cmd->new_oid))
+ continue;
+ else if (!p->want_modify &&
+ !is_null_oid(&cmd->old_oid) &&
+ !is_null_oid(&cmd->new_oid))
+ continue;
+
+ if (skip_prefix(cmd->ref_name, match, &remains) &&
+ (!*remains || *remains == '/')) {
+ if (!p->negative_ref)
+ return 1;
+ } else if (p->negative_ref) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
static void rp_error(const char *err, ...) __attribute__((format (printf, 1, 2)));
static void rp_warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
@@ -692,6 +788,7 @@ static void prepare_push_cert_sha1(struct child_process *proc)
struct receive_hook_feed_state {
struct command *cmd;
+ struct ref_push_report *report;
int skip_broken;
struct strbuf buf;
const struct string_list *push_options;
@@ -779,11 +876,31 @@ static int feed_receive_hook(void *state_, const char **bufp, size_t *sizep)
cmd = cmd->next;
if (!cmd)
return -1; /* EOF */
+ if (!bufp)
+ return 0; /* OK, can feed something. */
strbuf_reset(&state->buf);
- strbuf_addf(&state->buf, "%s %s %s\n",
- oid_to_hex(&cmd->old_oid), oid_to_hex(&cmd->new_oid),
- cmd->ref_name);
- state->cmd = cmd->next;
+ if (!state->report)
+ state->report = cmd->report;
+ if (state->report) {
+ struct object_id *old_oid;
+ struct object_id *new_oid;
+ const char *ref_name;
+
+ old_oid = state->report->old_oid ? state->report->old_oid : &cmd->old_oid;
+ new_oid = state->report->new_oid ? state->report->new_oid : &cmd->new_oid;
+ ref_name = state->report->ref_name ? state->report->ref_name : cmd->ref_name;
+ strbuf_addf(&state->buf, "%s %s %s\n",
+ oid_to_hex(old_oid), oid_to_hex(new_oid),
+ ref_name);
+ state->report = state->report->next;
+ if (!state->report)
+ state->cmd = cmd->next;
+ } else {
+ strbuf_addf(&state->buf, "%s %s %s\n",
+ oid_to_hex(&cmd->old_oid), oid_to_hex(&cmd->new_oid),
+ cmd->ref_name);
+ state->cmd = cmd->next;
+ }
if (bufp) {
*bufp = state->buf.buf;
*sizep = state->buf.len;
@@ -802,6 +919,7 @@ static int run_receive_hook(struct command *commands,
strbuf_init(&state.buf, 0);
state.cmd = commands;
state.skip_broken = skip_broken;
+ state.report = NULL;
if (feed_receive_hook(&state, NULL, NULL))
return 0;
state.cmd = commands;
@@ -840,6 +958,268 @@ static int run_update_hook(struct command *cmd)
return finish_command(&proc);
}
+static struct command *find_command_by_refname(struct command *list,
+ const char *refname)
+{
+ for (; list; list = list->next)
+ if (!strcmp(list->ref_name, refname))
+ return list;
+ return NULL;
+}
+
+static int read_proc_receive_report(struct packet_reader *reader,
+ struct command *commands,
+ struct strbuf *errmsg)
+{
+ struct command *cmd;
+ struct command *hint = NULL;
+ struct ref_push_report *report = NULL;
+ int new_report = 0;
+ int code = 0;
+ int once = 0;
+
+ for (;;) {
+ struct object_id old_oid, new_oid;
+ const char *head;
+ const char *refname;
+ char *p;
+
+ if (packet_reader_read(reader) != PACKET_READ_NORMAL)
+ break;
+
+ head = reader->line;
+ p = strchr(head, ' ');
+ if (!p) {
+ strbuf_addf(errmsg, "proc-receive reported incomplete status line: '%s'\n", head);
+ code = -1;
+ continue;
+ }
+ *p++ = '\0';
+ if (!strcmp(head, "option")) {
+ const char *key, *val;
+
+ if (!hint || !(report || new_report)) {
+ if (!once++)
+ strbuf_addstr(errmsg, "proc-receive reported 'option' without a matching 'ok/ng' directive\n");
+ code = -1;
+ continue;
+ }
+ if (new_report) {
+ if (!hint->report) {
+ hint->report = xcalloc(1, sizeof(struct ref_push_report));
+ report = hint->report;
+ } else {
+ report = hint->report;
+ while (report->next)
+ report = report->next;
+ report->next = xcalloc(1, sizeof(struct ref_push_report));
+ report = report->next;
+ }
+ new_report = 0;
+ }
+ key = p;
+ p = strchr(key, ' ');
+ if (p)
+ *p++ = '\0';
+ val = p;
+ if (!strcmp(key, "refname"))
+ report->ref_name = xstrdup_or_null(val);
+ else if (!strcmp(key, "old-oid") && val &&
+ !parse_oid_hex(val, &old_oid, &val))
+ report->old_oid = oiddup(&old_oid);
+ else if (!strcmp(key, "new-oid") && val &&
+ !parse_oid_hex(val, &new_oid, &val))
+ report->new_oid = oiddup(&new_oid);
+ else if (!strcmp(key, "forced-update"))
+ report->forced_update = 1;
+ else if (!strcmp(key, "fall-through"))
+ /* Fall through, let 'receive-pack' to execute it. */
+ hint->run_proc_receive = 0;
+ continue;
+ }
+
+ report = NULL;
+ new_report = 0;
+ refname = p;
+ p = strchr(refname, ' ');
+ if (p)
+ *p++ = '\0';
+ if (strcmp(head, "ok") && strcmp(head, "ng")) {
+ strbuf_addf(errmsg, "proc-receive reported bad status '%s' on ref '%s'\n",
+ head, refname);
+ code = -1;
+ continue;
+ }
+
+ /* first try searching at our hint, falling back to all refs */
+ if (hint)
+ hint = find_command_by_refname(hint, refname);
+ if (!hint)
+ hint = find_command_by_refname(commands, refname);
+ if (!hint) {
+ strbuf_addf(errmsg, "proc-receive reported status on unknown ref: %s\n",
+ refname);
+ code = -1;
+ continue;
+ }
+ if (!hint->run_proc_receive) {
+ strbuf_addf(errmsg, "proc-receive reported status on unexpected ref: %s\n",
+ refname);
+ code = -1;
+ continue;
+ }
+ hint->run_proc_receive |= RUN_PROC_RECEIVE_RETURNED;
+ if (!strcmp(head, "ng")) {
+ if (p)
+ hint->error_string = xstrdup(p);
+ else
+ hint->error_string = "failed";
+ code = -1;
+ continue;
+ }
+ new_report = 1;
+ }
+
+ for (cmd = commands; cmd; cmd = cmd->next)
+ if (cmd->run_proc_receive && !cmd->error_string &&
+ !(cmd->run_proc_receive & RUN_PROC_RECEIVE_RETURNED)) {
+ cmd->error_string = "proc-receive failed to report status";
+ code = -1;
+ }
+ return code;
+}
+
+static int run_proc_receive_hook(struct command *commands,
+ const struct string_list *push_options)
+{
+ struct child_process proc = CHILD_PROCESS_INIT;
+ struct async muxer;
+ struct command *cmd;
+ const char *argv[2];
+ struct packet_reader reader;
+ struct strbuf cap = STRBUF_INIT;
+ struct strbuf errmsg = STRBUF_INIT;
+ int hook_use_push_options = 0;
+ int version = 0;
+ int code;
+
+ argv[0] = find_hook("proc-receive");
+ if (!argv[0]) {
+ rp_error("cannot find hook 'proc-receive'");
+ return -1;
+ }
+ argv[1] = NULL;
+
+ proc.argv = argv;
+ proc.in = -1;
+ proc.out = -1;
+ proc.trace2_hook_name = "proc-receive";
+
+ if (use_sideband) {
+ memset(&muxer, 0, sizeof(muxer));
+ muxer.proc = copy_to_sideband;
+ muxer.in = -1;
+ code = start_async(&muxer);
+ if (code)
+ return code;
+ proc.err = muxer.in;
+ } else {
+ proc.err = 0;
+ }
+
+ code = start_command(&proc);
+ if (code) {
+ if (use_sideband)
+ finish_async(&muxer);
+ return code;
+ }
+
+ sigchain_push(SIGPIPE, SIG_IGN);
+
+ /* Version negotiaton */
+ packet_reader_init(&reader, proc.out, NULL, 0,
+ PACKET_READ_CHOMP_NEWLINE |
+ PACKET_READ_GENTLE_ON_EOF);
+ if (use_atomic)
+ strbuf_addstr(&cap, " atomic");
+ if (use_push_options)
+ strbuf_addstr(&cap, " push-options");
+ if (cap.len) {
+ packet_write_fmt(proc.in, "version=1%c%s\n", '\0', cap.buf + 1);
+ strbuf_release(&cap);
+ } else {
+ packet_write_fmt(proc.in, "version=1\n");
+ }
+ packet_flush(proc.in);
+
+ for (;;) {
+ int linelen;
+
+ if (packet_reader_read(&reader) != PACKET_READ_NORMAL)
+ break;
+
+ if (reader.pktlen > 8 && starts_with(reader.line, "version=")) {
+ version = atoi(reader.line + 8);
+ linelen = strlen(reader.line);
+ if (linelen < reader.pktlen) {
+ const char *feature_list = reader.line + linelen + 1;
+ if (parse_feature_request(feature_list, "push-options"))
+ hook_use_push_options = 1;
+ }
+ }
+ }
+
+ if (version != 1) {
+ strbuf_addf(&errmsg, "proc-receive version '%d' is not supported",
+ version);
+ code = -1;
+ goto cleanup;
+ }
+
+ /* Send commands */
+ for (cmd = commands; cmd; cmd = cmd->next) {
+ if (!cmd->run_proc_receive || cmd->skip_update || cmd->error_string)
+ continue;
+ packet_write_fmt(proc.in, "%s %s %s",
+ oid_to_hex(&cmd->old_oid),
+ oid_to_hex(&cmd->new_oid),
+ cmd->ref_name);
+ }
+ packet_flush(proc.in);
+
+ /* Send push options */
+ if (hook_use_push_options) {
+ struct string_list_item *item;
+
+ for_each_string_list_item(item, push_options)
+ packet_write_fmt(proc.in, "%s", item->string);
+ packet_flush(proc.in);
+ }
+
+ /* Read result from proc-receive */
+ code = read_proc_receive_report(&reader, commands, &errmsg);
+
+cleanup:
+ close(proc.in);
+ close(proc.out);
+ if (use_sideband)
+ finish_async(&muxer);
+ if (finish_command(&proc))
+ code = -1;
+ if (errmsg.len >0) {
+ char *p = errmsg.buf;
+
+ p += errmsg.len - 1;
+ if (*p == '\n')
+ *p = '\0';
+ rp_error("%s", errmsg.buf);
+ strbuf_release(&errmsg);
+ }
+ sigchain_pop(SIGPIPE);
+
+ return code;
+}
+
static char *refuse_unconfigured_deny_msg =
N_("By default, updating the current branch in a non-bare repository\n"
"is denied, because it will make the index and work tree inconsistent\n"
@@ -1415,7 +1795,7 @@ static void execute_commands_non_atomic(struct command *commands,
struct strbuf err = STRBUF_INIT;
for (cmd = commands; cmd; cmd = cmd->next) {
- if (!should_process_cmd(cmd))
+ if (!should_process_cmd(cmd) || cmd->run_proc_receive)
continue;
transaction = ref_transaction_begin(&err);
@@ -1455,7 +1835,7 @@ static void execute_commands_atomic(struct command *commands,
}
for (cmd = commands; cmd; cmd = cmd->next) {
- if (!should_process_cmd(cmd))
+ if (!should_process_cmd(cmd) || cmd->run_proc_receive)
continue;
cmd->error_string = update(cmd, si);
@@ -1491,6 +1871,7 @@ static void execute_commands(struct command *commands,
struct iterate_data data;
struct async muxer;
int err_fd = 0;
+ int run_proc_receive = 0;
if (unpacker_error) {
for (cmd = commands; cmd; cmd = cmd->next)
@@ -1520,6 +1901,22 @@ static void execute_commands(struct command *commands,
reject_updates_to_hidden(commands);
+ /*
+ * Try to find commands that have special prefix in their reference names,
+ * and mark them to run an external "proc-receive" hook later.
+ */
+ if (proc_receive_ref) {
+ for (cmd = commands; cmd; cmd = cmd->next) {
+ if (!should_process_cmd(cmd))
+ continue;
+
+ if (proc_receive_ref_matches(cmd)) {
+ cmd->run_proc_receive = RUN_PROC_RECEIVE_SCHEDULED;
+ run_proc_receive = 1;
+ }
+ }
+ }
+
if (run_receive_hook(commands, "pre-receive", 0, push_options)) {
for (cmd = commands; cmd; cmd = cmd->next) {
if (!cmd->error_string)
@@ -1546,6 +1943,14 @@ static void execute_commands(struct command *commands,
free(head_name_to_free);
head_name = head_name_to_free = resolve_refdup("HEAD", 0, NULL, NULL);
+ if (run_proc_receive &&
+ run_proc_receive_hook(commands, push_options))
+ for (cmd = commands; cmd; cmd = cmd->next)
+ if (!cmd->error_string &&
+ !(cmd->run_proc_receive & RUN_PROC_RECEIVE_RETURNED) &&
+ (cmd->run_proc_receive || use_atomic))
+ cmd->error_string = "fail to run proc-receive hook";
+
if (use_atomic)
execute_commands_atomic(commands, si);
else
@@ -1629,6 +2034,8 @@ static struct command *read_head_info(struct packet_reader *reader,
int len = 0;
if (parse_feature_request(feature_list, "report-status"))
report_status = 1;
+ if (parse_feature_request(feature_list, "report-status-v2"))
+ report_status_v2 = 1;
if (parse_feature_request(feature_list, "side-band-64k"))
use_sideband = LARGE_PACKET_MAX;
if (parse_feature_request(feature_list, "quiet"))
@@ -1947,6 +2354,51 @@ static void report(struct command *commands, const char *unpack_status)
strbuf_release(&buf);
}
+static void report_v2(struct command *commands, const char *unpack_status)
+{
+ struct command *cmd;
+ struct strbuf buf = STRBUF_INIT;
+ struct ref_push_report *report;
+
+ packet_buf_write(&buf, "unpack %s\n",
+ unpack_status ? unpack_status : "ok");
+ for (cmd = commands; cmd; cmd = cmd->next) {
+ int count = 0;
+
+ if (cmd->error_string) {
+ packet_buf_write(&buf, "ng %s %s\n",
+ cmd->ref_name,
+ cmd->error_string);
+ continue;
+ }
+ packet_buf_write(&buf, "ok %s\n",
+ cmd->ref_name);
+ for (report = cmd->report; report; report = report->next) {
+ if (count++ > 0)
+ packet_buf_write(&buf, "ok %s\n",
+ cmd->ref_name);
+ if (report->ref_name)
+ packet_buf_write(&buf, "option refname %s\n",
+ report->ref_name);
+ if (report->old_oid)
+ packet_buf_write(&buf, "option old-oid %s\n",
+ oid_to_hex(report->old_oid));
+ if (report->new_oid)
+ packet_buf_write(&buf, "option new-oid %s\n",
+ oid_to_hex(report->new_oid));
+ if (report->forced_update)
+ packet_buf_write(&buf, "option forced-update\n");
+ }
+ }
+ packet_buf_flush(&buf);
+
+ if (use_sideband)
+ send_sideband(1, 1, buf.buf, buf.len, use_sideband);
+ else
+ write_or_die(1, buf.buf, buf.len);
+ strbuf_release(&buf);
+}
+
static int delete_only(struct command *commands)
{
struct command *cmd;
@@ -2055,7 +2507,9 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
&push_options);
if (pack_lockfile)
unlink_or_warn(pack_lockfile);
- if (report_status)
+ if (report_status_v2)
+ report_v2(commands, unpack_status);
+ else if (report_status)
report(commands, unpack_status);
run_receive_hook(commands, "post-receive", 1,
&push_options);
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index 2b9610f..7af148d 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -29,10 +29,12 @@ static struct send_pack_args args;
static void print_helper_status(struct ref *ref)
{
struct strbuf buf = STRBUF_INIT;
+ struct ref_push_report *report;
for (; ref; ref = ref->next) {
const char *msg = NULL;
const char *res;
+ int count = 0;
switch(ref->status) {
case REF_STATUS_NONE:
@@ -94,6 +96,23 @@ static void print_helper_status(struct ref *ref)
}
strbuf_addch(&buf, '\n');
+ if (ref->status == REF_STATUS_OK) {
+ for (report = ref->report; report; report = report->next) {
+ if (count++ > 0)
+ strbuf_addf(&buf, "ok %s\n", ref->name);
+ if (report->ref_name)
+ strbuf_addf(&buf, "option refname %s\n",
+ report->ref_name);
+ if (report->old_oid)
+ strbuf_addf(&buf, "option old-oid %s\n",
+ oid_to_hex(report->old_oid));
+ if (report->new_oid)
+ strbuf_addf(&buf, "option new-oid %s\n",
+ oid_to_hex(report->new_oid));
+ if (report->forced_update)
+ strbuf_addstr(&buf, "option forced-update\n");
+ }
+ }
write_or_die(1, buf.buf, buf.len);
}
strbuf_release(&buf);
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index c856c58..0a5c496 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -9,6 +9,7 @@
#include "mailmap.h"
#include "shortlog.h"
#include "parse-options.h"
+#include "trailer.h"
static char const * const shortlog_usage[] = {
N_("git shortlog [<options>] [<revision-range>] [[--] <path>...]"),
@@ -49,12 +50,12 @@ static int compare_by_list(const void *a1, const void *a2)
}
static void insert_one_record(struct shortlog *log,
- const char *author,
+ const char *ident,
const char *oneline)
{
struct string_list_item *item;
- item = string_list_insert(&log->list, author);
+ item = string_list_insert(&log->list, ident);
if (log->summary)
item->util = (void *)(UTIL_TO_INT(item) + 1);
@@ -97,8 +98,8 @@ static void insert_one_record(struct shortlog *log,
}
}
-static int parse_stdin_author(struct shortlog *log,
- struct strbuf *out, const char *in)
+static int parse_ident(struct shortlog *log,
+ struct strbuf *out, const char *in)
{
const char *mailbuf, *namebuf;
size_t namelen, maillen;
@@ -122,18 +123,33 @@ static int parse_stdin_author(struct shortlog *log,
static void read_from_stdin(struct shortlog *log)
{
- struct strbuf author = STRBUF_INIT;
- struct strbuf mapped_author = STRBUF_INIT;
+ struct strbuf ident = STRBUF_INIT;
+ struct strbuf mapped_ident = STRBUF_INIT;
struct strbuf oneline = STRBUF_INIT;
static const char *author_match[2] = { "Author: ", "author " };
static const char *committer_match[2] = { "Commit: ", "committer " };
const char **match;
- match = log->committer ? committer_match : author_match;
- while (strbuf_getline_lf(&author, stdin) != EOF) {
+ if (HAS_MULTI_BITS(log->groups))
+ die(_("using multiple --group options with stdin is not supported"));
+
+ switch (log->groups) {
+ case SHORTLOG_GROUP_AUTHOR:
+ match = author_match;
+ break;
+ case SHORTLOG_GROUP_COMMITTER:
+ match = committer_match;
+ break;
+ case SHORTLOG_GROUP_TRAILER:
+ die(_("using --group=trailer with stdin is not supported"));
+ default:
+ BUG("unhandled shortlog group");
+ }
+
+ while (strbuf_getline_lf(&ident, stdin) != EOF) {
const char *v;
- if (!skip_prefix(author.buf, match[0], &v) &&
- !skip_prefix(author.buf, match[1], &v))
+ if (!skip_prefix(ident.buf, match[0], &v) &&
+ !skip_prefix(ident.buf, match[1], &v))
continue;
while (strbuf_getline_lf(&oneline, stdin) != EOF &&
oneline.len)
@@ -142,23 +158,118 @@ static void read_from_stdin(struct shortlog *log)
!oneline.len)
; /* discard blanks */
- strbuf_reset(&mapped_author);
- if (parse_stdin_author(log, &mapped_author, v) < 0)
+ strbuf_reset(&mapped_ident);
+ if (parse_ident(log, &mapped_ident, v) < 0)
continue;
- insert_one_record(log, mapped_author.buf, oneline.buf);
+ insert_one_record(log, mapped_ident.buf, oneline.buf);
}
- strbuf_release(&author);
- strbuf_release(&mapped_author);
+ strbuf_release(&ident);
+ strbuf_release(&mapped_ident);
strbuf_release(&oneline);
}
+struct strset_item {
+ struct hashmap_entry ent;
+ char value[FLEX_ARRAY];
+};
+
+struct strset {
+ struct hashmap map;
+};
+
+#define STRSET_INIT { { NULL } }
+
+static int strset_item_hashcmp(const void *hash_data,
+ const struct hashmap_entry *entry,
+ const struct hashmap_entry *entry_or_key,
+ const void *keydata)
+{
+ const struct strset_item *a, *b;
+
+ a = container_of(entry, const struct strset_item, ent);
+ if (keydata)
+ return strcmp(a->value, keydata);
+
+ b = container_of(entry_or_key, const struct strset_item, ent);
+ return strcmp(a->value, b->value);
+}
+
+/*
+ * Adds "str" to the set if it was not already present; returns true if it was
+ * already there.
+ */
+static int strset_check_and_add(struct strset *ss, const char *str)
+{
+ unsigned int hash = strhash(str);
+ struct strset_item *item;
+
+ if (!ss->map.table)
+ hashmap_init(&ss->map, strset_item_hashcmp, NULL, 0);
+
+ if (hashmap_get_from_hash(&ss->map, hash, str))
+ return 1;
+
+ FLEX_ALLOC_STR(item, value, str);
+ hashmap_entry_init(&item->ent, hash);
+ hashmap_add(&ss->map, &item->ent);
+ return 0;
+}
+
+static void strset_clear(struct strset *ss)
+{
+ if (!ss->map.table)
+ return;
+ hashmap_free_entries(&ss->map, struct strset_item, ent);
+}
+
+static void insert_records_from_trailers(struct shortlog *log,
+ struct strset *dups,
+ struct commit *commit,
+ struct pretty_print_context *ctx,
+ const char *oneline)
+{
+ struct trailer_iterator iter;
+ const char *commit_buffer, *body;
+ struct strbuf ident = STRBUF_INIT;
+
+ /*
+ * Using format_commit_message("%B") would be simpler here, but
+ * this saves us copying the message.
+ */
+ commit_buffer = logmsg_reencode(commit, NULL, ctx->output_encoding);
+ body = strstr(commit_buffer, "\n\n");
+ if (!body)
+ return;
+
+ trailer_iterator_init(&iter, body);
+ while (trailer_iterator_advance(&iter)) {
+ const char *value = iter.val.buf;
+
+ if (!string_list_has_string(&log->trailers, iter.key.buf))
+ continue;
+
+ strbuf_reset(&ident);
+ if (!parse_ident(log, &ident, value))
+ value = ident.buf;
+
+ if (strset_check_and_add(dups, value))
+ continue;
+ insert_one_record(log, value, oneline);
+ }
+ trailer_iterator_release(&iter);
+
+ strbuf_release(&ident);
+ unuse_commit_buffer(commit, commit_buffer);
+}
+
void shortlog_add_commit(struct shortlog *log, struct commit *commit)
{
- struct strbuf author = STRBUF_INIT;
+ struct strbuf ident = STRBUF_INIT;
struct strbuf oneline = STRBUF_INIT;
+ struct strset dups = STRSET_INIT;
struct pretty_print_context ctx = {0};
- const char *fmt;
+ const char *oneline_str;
ctx.fmt = CMIT_FMT_USERFORMAT;
ctx.abbrev = log->abbrev;
@@ -166,21 +277,38 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
ctx.date_mode.type = DATE_NORMAL;
ctx.output_encoding = get_log_output_encoding();
- fmt = log->committer ?
- (log->email ? "%cN <%cE>" : "%cN") :
- (log->email ? "%aN <%aE>" : "%aN");
-
- format_commit_message(commit, fmt, &author, &ctx);
if (!log->summary) {
if (log->user_format)
pretty_print_commit(&ctx, commit, &oneline);
else
format_commit_message(commit, "%s", &oneline, &ctx);
}
+ oneline_str = oneline.len ? oneline.buf : "<none>";
+
+ if (log->groups & SHORTLOG_GROUP_AUTHOR) {
+ strbuf_reset(&ident);
+ format_commit_message(commit,
+ log->email ? "%aN <%aE>" : "%aN",
+ &ident, &ctx);
+ if (!HAS_MULTI_BITS(log->groups) ||
+ !strset_check_and_add(&dups, ident.buf))
+ insert_one_record(log, ident.buf, oneline_str);
+ }
+ if (log->groups & SHORTLOG_GROUP_COMMITTER) {
+ strbuf_reset(&ident);
+ format_commit_message(commit,
+ log->email ? "%cN <%cE>" : "%cN",
+ &ident, &ctx);
+ if (!HAS_MULTI_BITS(log->groups) ||
+ !strset_check_and_add(&dups, ident.buf))
+ insert_one_record(log, ident.buf, oneline_str);
+ }
+ if (log->groups & SHORTLOG_GROUP_TRAILER) {
+ insert_records_from_trailers(log, &dups, commit, &ctx, oneline_str);
+ }
- insert_one_record(log, author.buf, oneline.len ? oneline.buf : "<none>");
-
- strbuf_release(&author);
+ strset_clear(&dups);
+ strbuf_release(&ident);
strbuf_release(&oneline);
}
@@ -241,6 +369,28 @@ static int parse_wrap_args(const struct option *opt, const char *arg, int unset)
return 0;
}
+static int parse_group_option(const struct option *opt, const char *arg, int unset)
+{
+ struct shortlog *log = opt->value;
+ const char *field;
+
+ if (unset) {
+ log->groups = 0;
+ string_list_clear(&log->trailers, 0);
+ } else if (!strcasecmp(arg, "author"))
+ log->groups |= SHORTLOG_GROUP_AUTHOR;
+ else if (!strcasecmp(arg, "committer"))
+ log->groups |= SHORTLOG_GROUP_COMMITTER;
+ else if (skip_prefix(arg, "trailer:", &field)) {
+ log->groups |= SHORTLOG_GROUP_TRAILER;
+ string_list_append(&log->trailers, field);
+ } else
+ return error(_("unknown group type: %s"), arg);
+
+ return 0;
+}
+
+
void shortlog_init(struct shortlog *log)
{
memset(log, 0, sizeof(*log));
@@ -251,6 +401,8 @@ void shortlog_init(struct shortlog *log)
log->wrap = DEFAULT_WRAPLEN;
log->in1 = DEFAULT_INDENT1;
log->in2 = DEFAULT_INDENT2;
+ log->trailers.strdup_strings = 1;
+ log->trailers.cmp = strcasecmp;
}
int cmd_shortlog(int argc, const char **argv, const char *prefix)
@@ -260,8 +412,9 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
int nongit = !startup_info->have_repository;
const struct option options[] = {
- OPT_BOOL('c', "committer", &log.committer,
- N_("Group by committer rather than author")),
+ OPT_BIT('c', "committer", &log.groups,
+ N_("Group by committer rather than author"),
+ SHORTLOG_GROUP_COMMITTER),
OPT_BOOL('n', "numbered", &log.sort_by_number,
N_("sort output according to the number of commits per author")),
OPT_BOOL('s', "summary", &log.summary,
@@ -271,6 +424,8 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
OPT_CALLBACK_F('w', NULL, &log, N_("<w>[,<i1>[,<i2>]]"),
N_("Linewrap output"), PARSE_OPT_OPTARG,
&parse_wrap_args),
+ OPT_CALLBACK(0, "group", &log, N_("field"),
+ N_("Group by field"), parse_group_option),
OPT_END(),
};
@@ -311,6 +466,10 @@ parse_done:
log.abbrev = rev.abbrev;
log.file = rev.diffopt.file;
+ if (!log.groups)
+ log.groups = SHORTLOG_GROUP_AUTHOR;
+ string_list_sort(&log.trailers);
+
/* assume HEAD if from a tty */
if (!nongit && !rev.pending.nr && isatty(0))
add_head_to_pending(&rev);
diff --git a/cache.h b/cache.h
index cee8aa5..c0072d4 100644
--- a/cache.h
+++ b/cache.h
@@ -629,7 +629,7 @@ int path_inside_repo(const char *prefix, const char *path);
int init_db(const char *git_dir, const char *real_git_dir,
const char *template_dir, int hash_algo,
const char *initial_branch, unsigned int flags);
-void initialize_repository_version(int hash_algo);
+void initialize_repository_version(int hash_algo, int reinit);
void sanitize_stdfds(void);
int daemonize(void);
diff --git a/ci/lib.sh b/ci/lib.sh
index 3eefec5..821e366 100755
--- a/ci/lib.sh
+++ b/ci/lib.sh
@@ -178,6 +178,7 @@ fi
export DEVELOPER=1
export DEFAULT_TEST_TARGET=prove
export GIT_TEST_CLONE_2GB=true
+export SKIP_DASHED_BUILT_INS=YesPlease
case "$jobname" in
linux-clang|linux-gcc)
diff --git a/combine-diff.c b/combine-diff.c
index 002e0e5..555b812 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -923,7 +923,6 @@ static void dump_quoted_path(const char *head,
static void show_combined_header(struct combine_diff_path *elem,
int num_parent,
- int dense,
struct rev_info *rev,
const char *line_prefix,
int mode_differs,
@@ -939,6 +938,7 @@ static void show_combined_header(struct combine_diff_path *elem,
int added = 0;
int deleted = 0;
int i;
+ int dense = rev->dense_combined_merges;
if (rev->loginfo && !rev->no_commit_id)
show_log(rev);
@@ -1012,7 +1012,7 @@ static void show_combined_header(struct combine_diff_path *elem,
}
static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
- int dense, int working_tree_file,
+ int working_tree_file,
struct rev_info *rev)
{
struct diff_options *opt = &rev->diffopt;
@@ -1145,7 +1145,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
}
}
if (is_binary) {
- show_combined_header(elem, num_parent, dense, rev,
+ show_combined_header(elem, num_parent, rev,
line_prefix, mode_differs, 0);
printf("Binary files differ\n");
free(result);
@@ -1200,10 +1200,10 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
textconv, elem->path, opt->xdl_opts);
}
- show_hunks = make_hunks(sline, cnt, num_parent, dense);
+ show_hunks = make_hunks(sline, cnt, num_parent, rev->dense_combined_merges);
if (show_hunks || mode_differs || working_tree_file) {
- show_combined_header(elem, num_parent, dense, rev,
+ show_combined_header(elem, num_parent, rev,
line_prefix, mode_differs, 1);
dump_sline(sline, line_prefix, cnt, num_parent,
opt->use_color, result_deleted);
@@ -1284,7 +1284,6 @@ static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct re
*/
void show_combined_diff(struct combine_diff_path *p,
int num_parent,
- int dense,
struct rev_info *rev)
{
struct diff_options *opt = &rev->diffopt;
@@ -1294,7 +1293,7 @@ void show_combined_diff(struct combine_diff_path *p,
DIFF_FORMAT_NAME_STATUS))
show_raw_diff(p, num_parent, rev);
else if (opt->output_format & DIFF_FORMAT_PATCH)
- show_patch_diff(p, num_parent, dense, 1, rev);
+ show_patch_diff(p, num_parent, 1, rev);
}
static void free_combined_pair(struct diff_filepair *pair)
@@ -1454,7 +1453,6 @@ static struct combine_diff_path *find_paths_multitree(
void diff_tree_combined(const struct object_id *oid,
const struct oid_array *parents,
- int dense,
struct rev_info *rev)
{
struct diff_options *opt = &rev->diffopt;
@@ -1581,8 +1579,7 @@ void diff_tree_combined(const struct object_id *oid,
printf("%s%c", diff_line_prefix(opt),
opt->line_termination);
for (p = paths; p; p = p->next)
- show_patch_diff(p, num_parent, dense,
- 0, rev);
+ show_patch_diff(p, num_parent, 0, rev);
}
}
@@ -1600,7 +1597,7 @@ void diff_tree_combined(const struct object_id *oid,
clear_pathspec(&diffopts.pathspec);
}
-void diff_tree_combined_merge(const struct commit *commit, int dense,
+void diff_tree_combined_merge(const struct commit *commit,
struct rev_info *rev)
{
struct commit_list *parent = get_saved_parents(rev, commit);
@@ -1610,6 +1607,6 @@ void diff_tree_combined_merge(const struct commit *commit, int dense,
oid_array_append(&parents, &parent->item->object.oid);
parent = parent->next;
}
- diff_tree_combined(&commit->object.oid, &parents, dense, rev);
+ diff_tree_combined(&commit->object.oid, &parents, rev);
oid_array_clear(&parents);
}
diff --git a/command-list.txt b/command-list.txt
index e5901f2..0e3204e 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -117,6 +117,7 @@ git-ls-remote plumbinginterrogators
git-ls-tree plumbinginterrogators
git-mailinfo purehelpers
git-mailsplit purehelpers
+git-maintenance mainporcelain
git-merge mainporcelain history
git-merge-base plumbinginterrogators
git-merge-file plumbingmanipulators
diff --git a/commit-graph.c b/commit-graph.c
index 0ed003e..cb042bd 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -172,7 +172,7 @@ static char *get_split_graph_filename(struct object_directory *odb,
oid_hex);
}
-static char *get_chain_filename(struct object_directory *odb)
+char *get_commit_graph_chain_filename(struct object_directory *odb)
{
return xstrfmt("%s/info/commit-graphs/commit-graph-chain", odb->path);
}
@@ -231,7 +231,8 @@ int open_commit_graph(const char *graph_file, int *fd, struct stat *st)
return 1;
}
-struct commit_graph *load_commit_graph_one_fd_st(int fd, struct stat *st,
+struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,
+ int fd, struct stat *st,
struct object_directory *odb)
{
void *graph_map;
@@ -247,7 +248,7 @@ struct commit_graph *load_commit_graph_one_fd_st(int fd, struct stat *st,
}
graph_map = xmmap(NULL, graph_size, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
- ret = parse_commit_graph(graph_map, graph_size);
+ ret = parse_commit_graph(r, graph_map, graph_size);
if (ret)
ret->odb = odb;
@@ -287,7 +288,8 @@ static int verify_commit_graph_lite(struct commit_graph *g)
return 0;
}
-struct commit_graph *parse_commit_graph(void *graph_map, size_t graph_size)
+struct commit_graph *parse_commit_graph(struct repository *r,
+ void *graph_map, size_t graph_size)
{
const unsigned char *data, *chunk_lookup;
uint32_t i;
@@ -325,6 +327,8 @@ struct commit_graph *parse_commit_graph(void *graph_map, size_t graph_size)
return NULL;
}
+ prepare_repo_settings(r);
+
graph = alloc_commit_graph();
graph->hash_len = the_hash_algo->rawsz;
@@ -401,14 +405,14 @@ struct commit_graph *parse_commit_graph(void *graph_map, size_t graph_size)
case GRAPH_CHUNKID_BLOOMINDEXES:
if (graph->chunk_bloom_indexes)
chunk_repeated = 1;
- else
+ else if (r->settings.commit_graph_read_changed_paths)
graph->chunk_bloom_indexes = data + chunk_offset;
break;
case GRAPH_CHUNKID_BLOOMDATA:
if (graph->chunk_bloom_data)
chunk_repeated = 1;
- else {
+ else if (r->settings.commit_graph_read_changed_paths) {
uint32_t hash_version;
graph->chunk_bloom_data = data + chunk_offset;
hash_version = get_be32(data + chunk_offset);
@@ -420,6 +424,7 @@ struct commit_graph *parse_commit_graph(void *graph_map, size_t graph_size)
graph->bloom_filter_settings->hash_version = hash_version;
graph->bloom_filter_settings->num_hashes = get_be32(data + chunk_offset + 4);
graph->bloom_filter_settings->bits_per_entry = get_be32(data + chunk_offset + 8);
+ graph->bloom_filter_settings->max_changed_paths = DEFAULT_BLOOM_MAX_CHANGES;
}
break;
}
@@ -452,7 +457,8 @@ free_and_return:
return NULL;
}
-static struct commit_graph *load_commit_graph_one(const char *graph_file,
+static struct commit_graph *load_commit_graph_one(struct repository *r,
+ const char *graph_file,
struct object_directory *odb)
{
@@ -464,7 +470,7 @@ static struct commit_graph *load_commit_graph_one(const char *graph_file,
if (!open_ok)
return NULL;
- g = load_commit_graph_one_fd_st(fd, &st, odb);
+ g = load_commit_graph_one_fd_st(r, fd, &st, odb);
if (g)
g->filename = xstrdup(graph_file);
@@ -476,7 +482,7 @@ static struct commit_graph *load_commit_graph_v1(struct repository *r,
struct object_directory *odb)
{
char *graph_name = get_commit_graph_filename(odb);
- struct commit_graph *g = load_commit_graph_one(graph_name, odb);
+ struct commit_graph *g = load_commit_graph_one(r, graph_name, odb);
free(graph_name);
return g;
@@ -523,7 +529,7 @@ static struct commit_graph *load_commit_graph_chain(struct repository *r,
struct stat st;
struct object_id *oids;
int i = 0, valid = 1, count;
- char *chain_name = get_chain_filename(odb);
+ char *chain_name = get_commit_graph_chain_filename(odb);
FILE *fp;
int stat_res;
@@ -557,7 +563,7 @@ static struct commit_graph *load_commit_graph_chain(struct repository *r,
valid = 0;
for (odb = r->objects->odb; odb; odb = odb->next) {
char *graph_name = get_split_graph_filename(odb, line.buf);
- struct commit_graph *g = load_commit_graph_one(graph_name, odb);
+ struct commit_graph *g = load_commit_graph_one(r, graph_name, odb);
free(graph_name);
@@ -667,6 +673,17 @@ int generation_numbers_enabled(struct repository *r)
return !!first_generation;
}
+struct bloom_filter_settings *get_bloom_filter_settings(struct repository *r)
+{
+ struct commit_graph *g = r->objects->commit_graph;
+ while (g) {
+ if (g->bloom_filter_settings)
+ return g->bloom_filter_settings;
+ g = g->base_graph;
+ }
+ return NULL;
+}
+
static void close_commit_graph_one(struct commit_graph *g)
{
if (!g)
@@ -952,9 +969,14 @@ struct write_commit_graph_context {
changed_paths:1,
order_by_pack:1;
- const struct split_commit_graph_opts *split_opts;
+ const struct commit_graph_opts *opts;
size_t total_bloom_filter_data_size;
const struct bloom_filter_settings *bloom_settings;
+
+ int count_bloom_filter_computed;
+ int count_bloom_filter_not_computed;
+ int count_bloom_filter_trunc_empty;
+ int count_bloom_filter_trunc_large;
};
static int write_graph_chunk_fanout(struct hashfile *f,
@@ -1166,7 +1188,7 @@ static int write_graph_chunk_bloom_indexes(struct hashfile *f,
uint32_t cur_pos = 0;
while (list < last) {
- struct bloom_filter *filter = get_bloom_filter(ctx->r, *list, 0);
+ struct bloom_filter *filter = get_bloom_filter(ctx->r, *list);
size_t len = filter ? filter->len : 0;
cur_pos += len;
display_progress(ctx->progress, ++ctx->progress_cnt);
@@ -1185,6 +1207,7 @@ static void trace2_bloom_filter_settings(struct write_commit_graph_context *ctx)
jw_object_intmax(&jw, "hash_version", ctx->bloom_settings->hash_version);
jw_object_intmax(&jw, "num_hashes", ctx->bloom_settings->num_hashes);
jw_object_intmax(&jw, "bits_per_entry", ctx->bloom_settings->bits_per_entry);
+ jw_object_intmax(&jw, "max_changed_paths", ctx->bloom_settings->max_changed_paths);
jw_end(&jw);
trace2_data_json("bloom", ctx->r, "settings", &jw);
@@ -1205,7 +1228,7 @@ static int write_graph_chunk_bloom_data(struct hashfile *f,
hashwrite_be32(f, ctx->bloom_settings->bits_per_entry);
while (list < last) {
- struct bloom_filter *filter = get_bloom_filter(ctx->r, *list, 0);
+ struct bloom_filter *filter = get_bloom_filter(ctx->r, *list);
size_t len = filter ? filter->len : 0;
display_progress(ctx->progress, ++ctx->progress_cnt);
@@ -1270,8 +1293,8 @@ static void close_reachable(struct write_commit_graph_context *ctx)
{
int i;
struct commit *commit;
- enum commit_graph_split_flags flags = ctx->split_opts ?
- ctx->split_opts->flags : COMMIT_GRAPH_SPLIT_UNSPECIFIED;
+ enum commit_graph_split_flags flags = ctx->opts ?
+ ctx->opts->split_flags : COMMIT_GRAPH_SPLIT_UNSPECIFIED;
if (ctx->report_progress)
ctx->progress = start_delayed_progress(
@@ -1375,11 +1398,24 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
stop_progress(&ctx->progress);
}
+static void trace2_bloom_filter_write_statistics(struct write_commit_graph_context *ctx)
+{
+ trace2_data_intmax("commit-graph", ctx->r, "filter-computed",
+ ctx->count_bloom_filter_computed);
+ trace2_data_intmax("commit-graph", ctx->r, "filter-not-computed",
+ ctx->count_bloom_filter_not_computed);
+ trace2_data_intmax("commit-graph", ctx->r, "filter-trunc-empty",
+ ctx->count_bloom_filter_trunc_empty);
+ trace2_data_intmax("commit-graph", ctx->r, "filter-trunc-large",
+ ctx->count_bloom_filter_trunc_large);
+}
+
static void compute_bloom_filters(struct write_commit_graph_context *ctx)
{
int i;
struct progress *progress = NULL;
struct commit **sorted_commits;
+ int max_new_filters;
init_bloom_filters();
@@ -1396,13 +1432,34 @@ static void compute_bloom_filters(struct write_commit_graph_context *ctx)
else
QSORT(sorted_commits, ctx->commits.nr, commit_gen_cmp);
+ max_new_filters = ctx->opts && ctx->opts->max_new_filters >= 0 ?
+ ctx->opts->max_new_filters : ctx->commits.nr;
+
for (i = 0; i < ctx->commits.nr; i++) {
+ enum bloom_filter_computed computed = 0;
struct commit *c = sorted_commits[i];
- struct bloom_filter *filter = get_bloom_filter(ctx->r, c, 1);
- ctx->total_bloom_filter_data_size += sizeof(unsigned char) * filter->len;
+ struct bloom_filter *filter = get_or_compute_bloom_filter(
+ ctx->r,
+ c,
+ ctx->count_bloom_filter_computed < max_new_filters,
+ ctx->bloom_settings,
+ &computed);
+ if (computed & BLOOM_COMPUTED) {
+ ctx->count_bloom_filter_computed++;
+ if (computed & BLOOM_TRUNC_EMPTY)
+ ctx->count_bloom_filter_trunc_empty++;
+ if (computed & BLOOM_TRUNC_LARGE)
+ ctx->count_bloom_filter_trunc_large++;
+ } else if (computed & BLOOM_NOT_COMPUTED)
+ ctx->count_bloom_filter_not_computed++;
+ ctx->total_bloom_filter_data_size += filter
+ ? sizeof(unsigned char) * filter->len : 0;
display_progress(progress, i + 1);
}
+ if (trace2_is_enabled())
+ trace2_bloom_filter_write_statistics(ctx);
+
free(sorted_commits);
stop_progress(&progress);
}
@@ -1431,7 +1488,7 @@ static int add_ref_to_set(const char *refname,
int write_commit_graph_reachable(struct object_directory *odb,
enum commit_graph_write_flags flags,
- const struct split_commit_graph_opts *split_opts)
+ const struct commit_graph_opts *opts)
{
struct oidset commits = OIDSET_INIT;
struct refs_cb_data data;
@@ -1448,7 +1505,7 @@ int write_commit_graph_reachable(struct object_directory *odb,
stop_progress(&data.progress);
result = write_commit_graph(odb, NULL, &commits,
- flags, split_opts);
+ flags, opts);
oidset_clear(&commits);
return result;
@@ -1563,8 +1620,8 @@ static uint32_t count_distinct_commits(struct write_commit_graph_context *ctx)
static void copy_oids_to_commits(struct write_commit_graph_context *ctx)
{
uint32_t i;
- enum commit_graph_split_flags flags = ctx->split_opts ?
- ctx->split_opts->flags : COMMIT_GRAPH_SPLIT_UNSPECIFIED;
+ enum commit_graph_split_flags flags = ctx->opts ?
+ ctx->opts->split_flags : COMMIT_GRAPH_SPLIT_UNSPECIFIED;
ctx->num_extra_edges = 0;
if (ctx->report_progress)
@@ -1646,15 +1703,6 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
int num_chunks = 3;
uint64_t chunk_offset;
struct object_id file_hash;
- struct bloom_filter_settings bloom_settings = DEFAULT_BLOOM_FILTER_SETTINGS;
-
- if (!ctx->bloom_settings) {
- bloom_settings.bits_per_entry = git_env_ulong("GIT_TEST_BLOOM_SETTINGS_BITS_PER_ENTRY",
- bloom_settings.bits_per_entry);
- bloom_settings.num_hashes = git_env_ulong("GIT_TEST_BLOOM_SETTINGS_NUM_HASHES",
- bloom_settings.num_hashes);
- ctx->bloom_settings = &bloom_settings;
- }
if (ctx->split) {
struct strbuf tmp_file = STRBUF_INIT;
@@ -1675,7 +1723,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
}
if (ctx->split) {
- char *lock_name = get_chain_filename(ctx->odb);
+ char *lock_name = get_commit_graph_chain_filename(ctx->odb);
hold_lock_file_for_update_mode(&lk, lock_name,
LOCK_DIE_ON_ERROR, 0444);
@@ -1858,13 +1906,13 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)
int max_commits = 0;
int size_mult = 2;
- if (ctx->split_opts) {
- max_commits = ctx->split_opts->max_commits;
+ if (ctx->opts) {
+ max_commits = ctx->opts->max_commits;
- if (ctx->split_opts->size_multiple)
- size_mult = ctx->split_opts->size_multiple;
+ if (ctx->opts->size_multiple)
+ size_mult = ctx->opts->size_multiple;
- flags = ctx->split_opts->flags;
+ flags = ctx->opts->split_flags;
}
g = ctx->r->objects->commit_graph;
@@ -2042,10 +2090,10 @@ static void expire_commit_graphs(struct write_commit_graph_context *ctx)
size_t dirnamelen;
timestamp_t expire_time = time(NULL);
- if (ctx->split_opts && ctx->split_opts->expire_time)
- expire_time = ctx->split_opts->expire_time;
+ if (ctx->opts && ctx->opts->expire_time)
+ expire_time = ctx->opts->expire_time;
if (!ctx->split) {
- char *chain_file_name = get_chain_filename(ctx->odb);
+ char *chain_file_name = get_commit_graph_chain_filename(ctx->odb);
unlink(chain_file_name);
free(chain_file_name);
ctx->num_commit_graphs_after = 0;
@@ -2094,12 +2142,13 @@ int write_commit_graph(struct object_directory *odb,
struct string_list *pack_indexes,
struct oidset *commits,
enum commit_graph_write_flags flags,
- const struct split_commit_graph_opts *split_opts)
+ const struct commit_graph_opts *opts)
{
struct write_commit_graph_context *ctx;
uint32_t i, count_distinct = 0;
int res = 0;
int replace = 0;
+ struct bloom_filter_settings bloom_settings = DEFAULT_BLOOM_FILTER_SETTINGS;
if (!commit_graph_compatible(the_repository))
return 0;
@@ -2110,9 +2159,17 @@ int write_commit_graph(struct object_directory *odb,
ctx->append = flags & COMMIT_GRAPH_WRITE_APPEND ? 1 : 0;
ctx->report_progress = flags & COMMIT_GRAPH_WRITE_PROGRESS ? 1 : 0;
ctx->split = flags & COMMIT_GRAPH_WRITE_SPLIT ? 1 : 0;
- ctx->split_opts = split_opts;
+ ctx->opts = opts;
ctx->total_bloom_filter_data_size = 0;
+ bloom_settings.bits_per_entry = git_env_ulong("GIT_TEST_BLOOM_SETTINGS_BITS_PER_ENTRY",
+ bloom_settings.bits_per_entry);
+ bloom_settings.num_hashes = git_env_ulong("GIT_TEST_BLOOM_SETTINGS_NUM_HASHES",
+ bloom_settings.num_hashes);
+ bloom_settings.max_changed_paths = git_env_ulong("GIT_TEST_BLOOM_SETTINGS_MAX_CHANGED_PATHS",
+ bloom_settings.max_changed_paths);
+ ctx->bloom_settings = &bloom_settings;
+
if (flags & COMMIT_GRAPH_WRITE_BLOOM_FILTERS)
ctx->changed_paths = 1;
if (!(flags & COMMIT_GRAPH_NO_WRITE_BLOOM_FILTERS)) {
@@ -2150,15 +2207,15 @@ int write_commit_graph(struct object_directory *odb,
}
}
- if (ctx->split_opts)
- replace = ctx->split_opts->flags & COMMIT_GRAPH_SPLIT_REPLACE;
+ if (ctx->opts)
+ replace = ctx->opts->split_flags & COMMIT_GRAPH_SPLIT_REPLACE;
}
ctx->approx_nr_objects = approximate_object_count();
ctx->oids.alloc = ctx->approx_nr_objects / 32;
- if (ctx->split && split_opts && ctx->oids.alloc > split_opts->max_commits)
- ctx->oids.alloc = split_opts->max_commits;
+ if (ctx->split && opts && ctx->oids.alloc > opts->max_commits)
+ ctx->oids.alloc = opts->max_commits;
if (ctx->append) {
prepare_commit_graph_one(ctx->r, ctx->odb);
diff --git a/commit-graph.h b/commit-graph.h
index 09a9703..f8e9250 100644
--- a/commit-graph.h
+++ b/commit-graph.h
@@ -25,6 +25,7 @@ struct raw_object_store;
struct string_list;
char *get_commit_graph_filename(struct object_directory *odb);
+char *get_commit_graph_chain_filename(struct object_directory *odb);
int open_commit_graph(const char *graph_file, int *fd, struct stat *st);
/*
@@ -75,11 +76,13 @@ struct commit_graph {
struct bloom_filter_settings *bloom_filter_settings;
};
-struct commit_graph *load_commit_graph_one_fd_st(int fd, struct stat *st,
+struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,
+ int fd, struct stat *st,
struct object_directory *odb);
struct commit_graph *read_commit_graph_one(struct repository *r,
struct object_directory *odb);
-struct commit_graph *parse_commit_graph(void *graph_map, size_t graph_size);
+struct commit_graph *parse_commit_graph(struct repository *r,
+ void *graph_map, size_t graph_size);
/*
* Return 1 if and only if the repository has a commit-graph
@@ -87,6 +90,8 @@ struct commit_graph *parse_commit_graph(void *graph_map, size_t graph_size);
*/
int generation_numbers_enabled(struct repository *r);
+struct bloom_filter_settings *get_bloom_filter_settings(struct repository *r);
+
enum commit_graph_write_flags {
COMMIT_GRAPH_WRITE_APPEND = (1 << 0),
COMMIT_GRAPH_WRITE_PROGRESS = (1 << 1),
@@ -101,11 +106,12 @@ enum commit_graph_split_flags {
COMMIT_GRAPH_SPLIT_REPLACE = 2
};
-struct split_commit_graph_opts {
+struct commit_graph_opts {
int size_multiple;
int max_commits;
timestamp_t expire_time;
- enum commit_graph_split_flags flags;
+ enum commit_graph_split_flags split_flags;
+ int max_new_filters;
};
/*
@@ -116,12 +122,12 @@ struct split_commit_graph_opts {
*/
int write_commit_graph_reachable(struct object_directory *odb,
enum commit_graph_write_flags flags,
- const struct split_commit_graph_opts *split_opts);
+ const struct commit_graph_opts *opts);
int write_commit_graph(struct object_directory *odb,
struct string_list *pack_indexes,
struct oidset *commits,
enum commit_graph_write_flags flags,
- const struct split_commit_graph_opts *split_opts);
+ const struct commit_graph_opts *opts);
#define COMMIT_GRAPH_VERIFY_SHALLOW (1 << 0)
diff --git a/commit-reach.c b/commit-reach.c
index efd5925..50175b1 100644
--- a/commit-reach.c
+++ b/commit-reach.c
@@ -321,7 +321,7 @@ int repo_in_merge_bases_many(struct repository *r, struct commit *commit,
{
struct commit_list *bases;
int ret = 0, i;
- uint32_t generation, min_generation = GENERATION_NUMBER_INFINITY;
+ uint32_t generation, max_generation = GENERATION_NUMBER_ZERO;
if (repo_parse_commit(r, commit))
return ret;
@@ -330,12 +330,12 @@ int repo_in_merge_bases_many(struct repository *r, struct commit *commit,
return ret;
generation = commit_graph_generation(reference[i]);
- if (generation < min_generation)
- min_generation = generation;
+ if (generation > max_generation)
+ max_generation = generation;
}
generation = commit_graph_generation(commit);
- if (generation > min_generation)
+ if (generation > max_generation)
return ret;
bases = paint_down_to_common(r, commit,
diff --git a/compat/bswap.h b/compat/bswap.h
index e4e2573..c0bb744 100644
--- a/compat/bswap.h
+++ b/compat/bswap.h
@@ -145,28 +145,6 @@ static inline uint64_t git_bswap64(uint64_t x)
#endif
-/*
- * Performance might be improved if the CPU architecture is OK with
- * unaligned 32-bit loads and a fast ntohl() is available.
- * Otherwise fall back to byte loads and shifts which is portable,
- * and is faster on architectures with memory alignment issues.
- */
-
-#if !defined(NO_UNALIGNED_LOADS) && ( \
- defined(__i386__) || defined(__x86_64__) || \
- defined(_M_IX86) || defined(_M_X64) || \
- defined(__ppc__) || defined(__ppc64__) || \
- defined(__powerpc__) || defined(__powerpc64__) || \
- defined(__s390__) || defined(__s390x__))
-
-#define get_be16(p) ntohs(*(unsigned short *)(p))
-#define get_be32(p) ntohl(*(unsigned int *)(p))
-#define get_be64(p) ntohll(*(uint64_t *)(p))
-#define put_be32(p, v) do { *(unsigned int *)(p) = htonl(v); } while (0)
-#define put_be64(p, v) do { *(uint64_t *)(p) = htonll(v); } while (0)
-
-#else
-
static inline uint16_t get_be16(const void *ptr)
{
const unsigned char *p = ptr;
@@ -212,6 +190,4 @@ static inline void put_be64(void *ptr, uint64_t value)
p[7] = value >> 0;
}
-#endif
-
#endif /* COMPAT_BSWAP_H */
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 8be4a03..0a96ad8 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -1508,6 +1508,22 @@ _git_checkout ()
{
__git_has_doubledash && return
+ local dwim_opt="$(__git_checkout_default_dwim_mode)"
+
+ case "$prev" in
+ -b|-B|--orphan)
+ # Complete local branches (and DWIM branch
+ # remote branch names) for an option argument
+ # specifying a new branch name. This is for
+ # convenience, assuming new branches are
+ # possibly based on pre-existing branch names.
+ __git_complete_refs $dwim_opt --mode="heads"
+ return
+ ;;
+ *)
+ ;;
+ esac
+
case "$cur" in
--conflict=*)
__gitcomp "diff3 merge" "" "${cur##--conflict=}"
@@ -1516,23 +1532,6 @@ _git_checkout ()
__gitcomp_builtin checkout
;;
*)
- local dwim_opt="$(__git_checkout_default_dwim_mode)"
- local prevword prevword="${words[cword-1]}"
-
- case "$prevword" in
- -b|-B|--orphan)
- # Complete local branches (and DWIM branch
- # remote branch names) for an option argument
- # specifying a new branch name. This is for
- # convenience, assuming new branches are
- # possibly based on pre-existing branch names.
- __git_complete_refs $dwim_opt --mode="heads"
- return
- ;;
- *)
- ;;
- esac
-
# At this point, we've already handled special completion for
# the arguments to -b/-B, and --orphan. There are 3 main
# things left we can possibly complete:
@@ -2392,6 +2391,22 @@ _git_status ()
_git_switch ()
{
+ local dwim_opt="$(__git_checkout_default_dwim_mode)"
+
+ case "$prev" in
+ -c|-C|--orphan)
+ # Complete local branches (and DWIM branch
+ # remote branch names) for an option argument
+ # specifying a new branch name. This is for
+ # convenience, assuming new branches are
+ # possibly based on pre-existing branch names.
+ __git_complete_refs $dwim_opt --mode="heads"
+ return
+ ;;
+ *)
+ ;;
+ esac
+
case "$cur" in
--conflict=*)
__gitcomp "diff3 merge" "" "${cur##--conflict=}"
@@ -2400,23 +2415,6 @@ _git_switch ()
__gitcomp_builtin switch
;;
*)
- local dwim_opt="$(__git_checkout_default_dwim_mode)"
- local prevword prevword="${words[cword-1]}"
-
- case "$prevword" in
- -c|-C|--orphan)
- # Complete local branches (and DWIM branch
- # remote branch names) for an option argument
- # specifying a new branch name. This is for
- # convenience, assuming new branches are
- # possibly based on pre-existing branch names.
- __git_complete_refs $dwim_opt --mode="heads"
- return
- ;;
- *)
- ;;
- esac
-
# Unlike in git checkout, git switch --orphan does not take
# a start point. Thus we really have nothing to complete after
# the branch name.
@@ -2843,6 +2841,13 @@ _git_reset ()
_git_restore ()
{
+ case "$prev" in
+ -s)
+ __git_complete_refs
+ return
+ ;;
+ esac
+
case "$cur" in
--conflict=*)
__gitcomp "diff3 merge" "" "${cur##--conflict=}"
diff --git a/contrib/diff-highlight/DiffHighlight.pm b/contrib/diff-highlight/DiffHighlight.pm
index e258992..376f577 100644
--- a/contrib/diff-highlight/DiffHighlight.pm
+++ b/contrib/diff-highlight/DiffHighlight.pm
@@ -112,7 +112,7 @@ sub handle_line {
# Since we can receive arbitrary input, there's no optimal
# place to flush. Flushing on a blank line is a heuristic that
# happens to match git-log output.
- if (!length) {
+ if (/^$/) {
$flush_cb->();
}
}
diff --git a/contrib/mw-to-git/git-mw.perl b/contrib/mw-to-git/git-mw.perl
index 28df3ee..eb52a53 100755
--- a/contrib/mw-to-git/git-mw.perl
+++ b/contrib/mw-to-git/git-mw.perl
@@ -6,7 +6,7 @@
# License: GPL v2 or later
# Set of tools for git repo with a mediawiki remote.
-# Documentation & bugtracker: https://github.com/moy/Git-Mediawiki/
+# Documentation & bugtracker: https://github.com/Git-Mediawiki/Git-Mediawiki
use strict;
use warnings;
diff --git a/contrib/mw-to-git/git-remote-mediawiki.perl b/contrib/mw-to-git/git-remote-mediawiki.perl
index d8ff2e6..a562441 100755
--- a/contrib/mw-to-git/git-remote-mediawiki.perl
+++ b/contrib/mw-to-git/git-remote-mediawiki.perl
@@ -9,7 +9,7 @@
# License: GPL v2 or later
# Gateway between Git and MediaWiki.
-# Documentation & bugtracker: https://github.com/moy/Git-Mediawiki/
+# Documentation & bugtracker: https://github.com/Git-Mediawiki/Git-Mediawiki
use strict;
use MediaWiki::API;
@@ -56,38 +56,38 @@ my $url = $ARGV[1];
# Accept both space-separated and multiple keys in config file.
# Spaces should be written as _ anyway because we'll use chomp.
-my @tracked_pages = split(/[ \n]/, run_git("config --get-all remote.${remotename}.pages"));
+my @tracked_pages = split(/[ \n]/, run_git_quoted(["config", "--get-all", "remote.${remotename}.pages"]));
chomp(@tracked_pages);
# Just like @tracked_pages, but for MediaWiki categories.
-my @tracked_categories = split(/[ \n]/, run_git("config --get-all remote.${remotename}.categories"));
+my @tracked_categories = split(/[ \n]/, run_git_quoted(["config", "--get-all", "remote.${remotename}.categories"]));
chomp(@tracked_categories);
# Just like @tracked_categories, but for MediaWiki namespaces.
-my @tracked_namespaces = split(/[ \n]/, run_git("config --get-all remote.${remotename}.namespaces"));
+my @tracked_namespaces = split(/[ \n]/, run_git_quoted(["config", "--get-all", "remote.${remotename}.namespaces"]));
for (@tracked_namespaces) { s/_/ /g; }
chomp(@tracked_namespaces);
# Import media files on pull
-my $import_media = run_git("config --get --bool remote.${remotename}.mediaimport");
+my $import_media = run_git_quoted(["config", "--get", "--bool", "remote.${remotename}.mediaimport"]);
chomp($import_media);
$import_media = ($import_media eq 'true');
# Export media files on push
-my $export_media = run_git("config --get --bool remote.${remotename}.mediaexport");
+my $export_media = run_git_quoted(["config", "--get", "--bool", "remote.${remotename}.mediaexport"]);
chomp($export_media);
$export_media = !($export_media eq 'false');
-my $wiki_login = run_git("config --get remote.${remotename}.mwLogin");
+my $wiki_login = run_git_quoted(["config", "--get", "remote.${remotename}.mwLogin"]);
# Note: mwPassword is discouraged. Use the credential system instead.
-my $wiki_passwd = run_git("config --get remote.${remotename}.mwPassword");
-my $wiki_domain = run_git("config --get remote.${remotename}.mwDomain");
+my $wiki_passwd = run_git_quoted(["config", "--get", "remote.${remotename}.mwPassword"]);
+my $wiki_domain = run_git_quoted(["config", "--get", "remote.${remotename}.mwDomain"]);
chomp($wiki_login);
chomp($wiki_passwd);
chomp($wiki_domain);
# Import only last revisions (both for clone and fetch)
-my $shallow_import = run_git("config --get --bool remote.${remotename}.shallow");
+my $shallow_import = run_git_quoted(["config", "--get", "--bool", "remote.${remotename}.shallow"]);
chomp($shallow_import);
$shallow_import = ($shallow_import eq 'true');
@@ -97,9 +97,9 @@ $shallow_import = ($shallow_import eq 'true');
# Possible values:
# - by_rev: perform one query per new revision on the remote wiki
# - by_page: query each tracked page for new revision
-my $fetch_strategy = run_git("config --get remote.${remotename}.fetchStrategy");
+my $fetch_strategy = run_git_quoted(["config", "--get", "remote.${remotename}.fetchStrategy"]);
if (!$fetch_strategy) {
- $fetch_strategy = run_git('config --get mediawiki.fetchStrategy');
+ $fetch_strategy = run_git_quoted(["config", "--get", "mediawiki.fetchStrategy"]);
}
chomp($fetch_strategy);
if (!$fetch_strategy) {
@@ -123,9 +123,9 @@ my %basetimestamps;
# will get the history with information lost). If the import is
# deterministic, this means everybody gets the same sha1 for each
# MediaWiki revision.
-my $dumb_push = run_git("config --get --bool remote.${remotename}.dumbPush");
+my $dumb_push = run_git_quoted(["config", "--get", "--bool", "remote.${remotename}.dumbPush"]);
if (!$dumb_push) {
- $dumb_push = run_git('config --get --bool mediawiki.dumbPush');
+ $dumb_push = run_git_quoted(["config", "--get", "--bool", "mediawiki.dumbPush"]);
}
chomp($dumb_push);
$dumb_push = ($dumb_push eq 'true');
@@ -369,12 +369,14 @@ sub get_mw_pages {
return %pages;
}
-# usage: $out = run_git("command args");
-# $out = run_git("command args", "raw"); # don't interpret output as UTF-8.
-sub run_git {
+# usage: $out = run_git_quoted(["command", "args", ...]);
+# $out = run_git_quoted(["command", "args", ...], "raw"); # don't interpret output as UTF-8.
+# $out = run_git_quoted_nostderr(["command", "args", ...]); # discard stderr
+# $out = run_git_quoted_nostderr(["command", "args", ...], "raw"); # ditto but raw instead of UTF-8 as above
+sub _run_git {
my $args = shift;
my $encoding = (shift || 'encoding(UTF-8)');
- open(my $git, "-|:${encoding}", "git ${args}")
+ open(my $git, "-|:${encoding}", @$args)
or die "Unable to fork: $!\n";
my $res = do {
local $/ = undef;
@@ -385,6 +387,13 @@ sub run_git {
return $res;
}
+sub run_git_quoted {
+ _run_git(["git", @{$_[0]}], $_[1]);
+}
+
+sub run_git_quoted_nostderr {
+ _run_git(['sh', '-c', 'git "$@" 2>/dev/null', '--', @{$_[0]}], $_[1]);
+}
sub get_all_mediafiles {
my $pages = shift;
@@ -511,8 +520,9 @@ sub download_mw_mediafile {
}
sub get_last_local_revision {
- # Get note regarding last mediawiki revision
- my $note = run_git("notes --ref=${remotename}/mediawiki show refs/mediawiki/${remotename}/master 2>/dev/null");
+ # Get note regarding last mediawiki revision.
+ my $note = run_git_quoted_nostderr(["notes", "--ref=${remotename}/mediawiki",
+ "show", "refs/mediawiki/${remotename}/master"]);
my @note_info = split(/ /, $note);
my $lastrevision_number;
@@ -807,7 +817,10 @@ sub get_more_refs {
sub mw_import {
# multiple import commands can follow each other.
my @refs = (shift, get_more_refs('import'));
+ my $processedRefs;
foreach my $ref (@refs) {
+ next if $processedRefs->{$ref}; # skip duplicates: "import refs/heads/master" being issued twice; TODO: why?
+ $processedRefs->{$ref} = 1;
mw_import_ref($ref);
}
print {*STDOUT} "done\n";
@@ -970,7 +983,7 @@ sub mw_import_revids {
}
sub error_non_fast_forward {
- my $advice = run_git('config --bool advice.pushNonFastForward');
+ my $advice = run_git_quoted(["config", "--bool", "advice.pushNonFastForward"]);
chomp($advice);
if ($advice ne 'false') {
# Native git-push would show this after the summary.
@@ -1014,7 +1027,7 @@ sub mw_upload_file {
}
} else {
# Don't let perl try to interpret file content as UTF-8 => use "raw"
- my $content = run_git("cat-file blob ${new_sha1}", 'raw');
+ my $content = run_git_quoted(["cat-file", "blob", $new_sha1], 'raw');
if ($content ne EMPTY) {
$mediawiki = connect_maybe($mediawiki, $remotename, $url);
$mediawiki->{config}->{upload_url} =
@@ -1084,7 +1097,7 @@ sub mw_push_file {
# with this content instead:
$file_content = DELETED_CONTENT;
} else {
- $file_content = run_git("cat-file blob ${new_sha1}");
+ $file_content = run_git_quoted(["cat-file", "blob", $new_sha1]);
}
$mediawiki = connect_maybe($mediawiki, $remotename, $url);
@@ -1174,10 +1187,10 @@ sub mw_push_revision {
my $mw_revision = $last_remote_revid;
# Get sha1 of commit pointed by local HEAD
- my $HEAD_sha1 = run_git("rev-parse ${local} 2>/dev/null");
+ my $HEAD_sha1 = run_git_quoted_nostderr(["rev-parse", $local]);
chomp($HEAD_sha1);
# Get sha1 of commit pointed by remotes/$remotename/master
- my $remoteorigin_sha1 = run_git("rev-parse refs/remotes/${remotename}/master 2>/dev/null");
+ my $remoteorigin_sha1 = run_git_quoted_nostderr(["rev-parse", "refs/remotes/${remotename}/master"]);
chomp($remoteorigin_sha1);
if ($last_local_revid > 0 &&
@@ -1197,7 +1210,7 @@ sub mw_push_revision {
my $parsed_sha1 = $remoteorigin_sha1;
# Find a path from last MediaWiki commit to pushed commit
print {*STDERR} "Computing path from local to remote ...\n";
- my @local_ancestry = split(/\n/, run_git("rev-list --boundary --parents ${local} ^${parsed_sha1}"));
+ my @local_ancestry = split(/\n/, run_git_quoted(["rev-list", "--boundary", "--parents", $local, "^${parsed_sha1}"]));
my %local_ancestry;
foreach my $line (@local_ancestry) {
if (my ($child, $parents) = $line =~ /^-?([a-f0-9]+) ([a-f0-9 ]+)/) {
@@ -1221,7 +1234,7 @@ sub mw_push_revision {
# No remote mediawiki revision. Export the whole
# history (linearized with --first-parent)
print {*STDERR} "Warning: no common ancestor, pushing complete history\n";
- my $history = run_git("rev-list --first-parent --children ${local}");
+ my $history = run_git_quoted(["rev-list", "--first-parent", "--children", $local]);
my @history = split(/\n/, $history);
@history = @history[1..$#history];
foreach my $line (reverse @history) {
@@ -1233,12 +1246,12 @@ sub mw_push_revision {
foreach my $commit_info_split (@commit_pairs) {
my $sha1_child = @{$commit_info_split}[0];
my $sha1_commit = @{$commit_info_split}[1];
- my $diff_infos = run_git("diff-tree -r --raw -z ${sha1_child} ${sha1_commit}");
+ my $diff_infos = run_git_quoted(["diff-tree", "-r", "--raw", "-z", $sha1_child, $sha1_commit]);
# TODO: we could detect rename, and encode them with a #redirect on the wiki.
# TODO: for now, it's just a delete+add
my @diff_info_list = split(/\0/, $diff_infos);
# Keep the subject line of the commit message as mediawiki comment for the revision
- my $commit_msg = run_git(qq(log --no-walk --format="%s" ${sha1_commit}));
+ my $commit_msg = run_git_quoted(["log", "--no-walk", '--format="%s"', $sha1_commit]);
chomp($commit_msg);
# Push every blob
while (@diff_info_list) {
@@ -1263,7 +1276,10 @@ sub mw_push_revision {
}
}
if (!$dumb_push) {
- run_git(qq(notes --ref=${remotename}/mediawiki add -f -m "mediawiki_revision: ${mw_revision}" ${sha1_commit}));
+ run_git_quoted(["notes", "--ref=${remotename}/mediawiki",
+ "add", "-f", "-m",
+ "mediawiki_revision: ${mw_revision}",
+ $sha1_commit]);
}
}
@@ -1304,7 +1320,7 @@ sub get_mw_namespace_id {
# already cached. Namespaces are stored in form:
# "Name_of_namespace:Id_namespace", ex.: "File:6".
my @temp = split(/\n/,
- run_git("config --get-all remote.${remotename}.namespaceCache"));
+ run_git_quoted(["config", "--get-all", "remote.${remotename}.namespaceCache"]));
chomp(@temp);
foreach my $ns (@temp) {
my ($n, $id) = split(/:/, $ns);
@@ -1358,7 +1374,7 @@ sub get_mw_namespace_id {
# Store explicitly requested namespaces on disk
if (!exists $cached_mw_namespace_id{$name}) {
- run_git(qq(config --add remote.${remotename}.namespaceCache "${name}:${store_id}"));
+ run_git_quoted(["config", "--add", "remote.${remotename}.namespaceCache", "${name}:${store_id}"]);
$cached_mw_namespace_id{$name} = 1;
}
return $id;
diff --git a/contrib/mw-to-git/git-remote-mediawiki.txt b/contrib/mw-to-git/git-remote-mediawiki.txt
index 23b7ef9..5da825f 100644
--- a/contrib/mw-to-git/git-remote-mediawiki.txt
+++ b/contrib/mw-to-git/git-remote-mediawiki.txt
@@ -4,4 +4,4 @@ objects from mediawiki just as one would do with a classic git
repository thanks to remote-helpers.
For more information, visit the wiki at
-https://github.com/moy/Git-Mediawiki/wiki
+https://github.com/Git-Mediawiki/Git-Mediawiki
diff --git a/contrib/mw-to-git/t/.gitignore b/contrib/mw-to-git/t/.gitignore
index a7a40b4..2b8dc30 100644
--- a/contrib/mw-to-git/t/.gitignore
+++ b/contrib/mw-to-git/t/.gitignore
@@ -1,4 +1,4 @@
WEB/
-wiki/
+mediawiki/
trash directory.t*/
test-results/
diff --git a/contrib/mw-to-git/t/README b/contrib/mw-to-git/t/README
index 2ee34be..72c4889 100644
--- a/contrib/mw-to-git/t/README
+++ b/contrib/mw-to-git/t/README
@@ -14,11 +14,11 @@ install the following packages (Debian/Ubuntu names, may need to be
adapted for another distribution):
* lighttpd
-* php5
-* php5-cgi
-* php5-cli
-* php5-curl
-* php5-sqlite
+* php
+* php-cgi
+* php-cli
+* php-curl
+* php-sqlite
Principles and Technical Choices
--------------------------------
diff --git a/contrib/mw-to-git/t/install-wiki/.gitignore b/contrib/mw-to-git/t/install-wiki/.gitignore
deleted file mode 100644
index b5a2a44..0000000
--- a/contrib/mw-to-git/t/install-wiki/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-wikidb.sqlite
diff --git a/contrib/mw-to-git/t/install-wiki/LocalSettings.php b/contrib/mw-to-git/t/install-wiki/LocalSettings.php
deleted file mode 100644
index 745e47e..0000000
--- a/contrib/mw-to-git/t/install-wiki/LocalSettings.php
+++ /dev/null
@@ -1,129 +0,0 @@
-<?php
-# This file was automatically generated by the MediaWiki 1.19.0
-# installer. If you make manual changes, please keep track in case you
-# need to recreate them later.
-#
-# See includes/DefaultSettings.php for all configurable settings
-# and their default values, but don't forget to make changes in _this_
-# file, not there.
-#
-# Further documentation for configuration settings may be found at:
-# http://www.mediawiki.org/wiki/Manual:Configuration_settings
-
-# Protect against web entry
-if ( !defined( 'MEDIAWIKI' ) ) {
- exit;
-}
-
-## Uncomment this to disable output compression
-# $wgDisableOutputCompression = true;
-
-$wgSitename = "Git-MediaWiki-Test";
-$wgMetaNamespace = "Git-MediaWiki-Test";
-
-## The URL base path to the directory containing the wiki;
-## defaults for all runtime URL paths are based off of this.
-## For more information on customizing the URLs please see:
-## http://www.mediawiki.org/wiki/Manual:Short_URL
-$wgScriptPath = "@WG_SCRIPT_PATH@";
-$wgScriptExtension = ".php";
-
-## The protocol and server name to use in fully-qualified URLs
-$wgServer = "@WG_SERVER@";
-
-## The relative URL path to the skins directory
-$wgStylePath = "$wgScriptPath/skins";
-
-## The relative URL path to the logo. Make sure you change this from the default,
-## or else you'll overwrite your logo when you upgrade!
-$wgLogo = "$wgStylePath/common/images/wiki.png";
-
-## UPO means: this is also a user preference option
-
-$wgEnableEmail = true;
-$wgEnableUserEmail = true; # UPO
-
-$wgEmergencyContact = "apache@localhost";
-$wgPasswordSender = "apache@localhost";
-
-$wgEnotifUserTalk = false; # UPO
-$wgEnotifWatchlist = false; # UPO
-$wgEmailAuthentication = true;
-
-## Database settings
-$wgDBtype = "sqlite";
-$wgDBserver = "";
-$wgDBname = "@WG_SQLITE_DATAFILE@";
-$wgDBuser = "";
-$wgDBpassword = "";
-
-# SQLite-specific settings
-$wgSQLiteDataDir = "@WG_SQLITE_DATADIR@";
-
-
-## Shared memory settings
-$wgMainCacheType = CACHE_NONE;
-$wgMemCachedServers = array();
-
-## To enable image uploads, make sure the 'images' directory
-## is writable, then set this to true:
-$wgEnableUploads = true;
-$wgUseImageMagick = true;
-$wgImageMagickConvertCommand ="@CONVERT@";
-$wgFileExtensions[] = 'txt';
-
-# InstantCommons allows wiki to use images from http://commons.wikimedia.org
-$wgUseInstantCommons = false;
-
-## If you use ImageMagick (or any other shell command) on a
-## Linux server, this will need to be set to the name of an
-## available UTF-8 locale
-$wgShellLocale = "en_US.utf8";
-
-## If you want to use image uploads under safe mode,
-## create the directories images/archive, images/thumb and
-## images/temp, and make them all writable. Then uncomment
-## this, if it's not already uncommented:
-#$wgHashedUploadDirectory = false;
-
-## Set $wgCacheDirectory to a writable directory on the web server
-## to make your wiki go slightly faster. The directory should not
-## be publicly accessible from the web.
-#$wgCacheDirectory = "$IP/cache";
-
-# Site language code, should be one of the list in ./languages/Names.php
-$wgLanguageCode = "en";
-
-$wgSecretKey = "1c912bfe3519fb70f5dc523ecc698111cd43d81a11c585b3eefb28f29c2699b7";
-#$wgSecretKey = "@SECRETKEY@";
-
-
-# Site upgrade key. Must be set to a string (default provided) to turn on the
-# web installer while LocalSettings.php is in place
-$wgUpgradeKey = "ddae7dc87cd0a645";
-
-## Default skin: you can change the default skin. Use the internal symbolic
-## names, ie 'standard', 'nostalgia', 'cologneblue', 'monobook', 'vector':
-$wgDefaultSkin = "vector";
-
-## For attaching licensing metadata to pages, and displaying an
-## appropriate copyright notice / icon. GNU Free Documentation
-## License and Creative Commons licenses are supported so far.
-$wgRightsPage = ""; # Set to the title of a wiki page that describes your license/copyright
-$wgRightsUrl = "";
-$wgRightsText = "";
-$wgRightsIcon = "";
-
-# Path to the GNU diff3 utility. Used for conflict resolution.
-$wgDiff3 = "/usr/bin/diff3";
-
-# Query string length limit for ResourceLoader. You should only set this if
-# your web server has a query string length limit (then set it to that limit),
-# or if you have suhosin.get.max_value_length set in php.ini (then set it to
-# that value)
-$wgResourceLoaderMaxQueryLength = -1;
-
-
-
-# End of automatically generated settings.
-# Add more configuration options below.
diff --git a/contrib/mw-to-git/t/install-wiki/db_install.php b/contrib/mw-to-git/t/install-wiki/db_install.php
deleted file mode 100644
index b033849..0000000
--- a/contrib/mw-to-git/t/install-wiki/db_install.php
+++ /dev/null
@@ -1,120 +0,0 @@
-<?php
-/**
- * This script generates a SQLite database for a MediaWiki version 1.19.0
- * You must specify the login of the admin (argument 1) and its
- * password (argument 2) and the folder where the database file
- * is located (absolute path in argument 3).
- * It is used by the script install-wiki.sh in order to make easy the
- * installation of a MediaWiki.
- *
- * In order to generate a SQLite database file, MediaWiki ask the user
- * to submit some forms in its web browser. This script simulates this
- * behavior though the functions <get> and <submit>
- *
- */
-$argc = $_SERVER['argc'];
-$argv = $_SERVER['argv'];
-
-$login = $argv[2];
-$pass = $argv[3];
-$tmp = $argv[4];
-$port = $argv[5];
-
-$url = 'http://localhost:'.$port.'/wiki/mw-config/index.php';
-$db_dir = urlencode($tmp);
-$tmp_cookie = tempnam($tmp, "COOKIE_");
-/*
- * Fetches a page with cURL.
- */
-function get($page_name = "") {
- $curl = curl_init();
- $page_name_add = "";
- if ($page_name != "") {
- $page_name_add = '?page='.$page_name;
- }
- $url = $GLOBALS['url'].$page_name_add;
- $tmp_cookie = $GLOBALS['tmp_cookie'];
- curl_setopt($curl, CURLOPT_COOKIEJAR, $tmp_cookie);
- curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
- curl_setopt($curl, CURLOPT_COOKIEFILE, $tmp_cookie);
- curl_setopt($curl, CURLOPT_HEADER, true);
- curl_setopt($curl, CURLOPT_URL, $url);
-
- $page = curl_exec($curl);
- if (!$page) {
- die("Could not get page: $url\n");
- }
- curl_close($curl);
- return $page;
-}
-
-/*
- * Submits a form with cURL.
- */
-function submit($page_name, $option = "") {
- $curl = curl_init();
- $datapost = 'submit-continue=Continue+%E2%86%92';
- if ($option != "") {
- $datapost = $option.'&'.$datapost;
- }
- $url = $GLOBALS['url'].'?page='.$page_name;
- $tmp_cookie = $GLOBALS['tmp_cookie'];
- curl_setopt($curl, CURLOPT_URL, $url);
- curl_setopt($curl, CURLOPT_POST, true);
- curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
- curl_setopt($curl, CURLOPT_POSTFIELDS, $datapost);
- curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($curl, CURLOPT_COOKIEJAR, $tmp_cookie);
- curl_setopt($curl, CURLOPT_COOKIEFILE, $tmp_cookie);
-
- $page = curl_exec($curl);
- if (!$page) {
- die("Could not get page: $url\n");
- }
- curl_close($curl);
- return "$page";
-}
-
-/*
- * Here starts this script: simulates the behavior of the user
- * submitting forms to generates the database file.
- * Note this simulation was made for the MediaWiki version 1.19.0,
- * we can't assume it works with other versions.
- *
- */
-
-$page = get();
-if (!preg_match('/input type="hidden" value="([0-9]+)" name="LanguageRequestTime"/',
- $page, $matches)) {
- echo "Unexpected content for page downloaded:\n";
- echo "$page";
- die;
-};
-$timestamp = $matches[1];
-$language = "LanguageRequestTime=$timestamp&uselang=en&ContLang=en";
-$page = submit('Language', $language);
-
-submit('Welcome');
-
-$db_config = 'DBType=sqlite';
-$db_config = $db_config.'&sqlite_wgSQLiteDataDir='.$db_dir;
-$db_config = $db_config.'&sqlite_wgDBname='.$argv[1];
-submit('DBConnect', $db_config);
-
-$wiki_config = 'config_wgSitename=TEST';
-$wiki_config = $wiki_config.'&config__NamespaceType=site-name';
-$wiki_config = $wiki_config.'&config_wgMetaNamespace=MyWiki';
-$wiki_config = $wiki_config.'&config__AdminName='.$login;
-
-$wiki_config = $wiki_config.'&config__AdminPassword='.$pass;
-$wiki_config = $wiki_config.'&config__AdminPassword2='.$pass;
-
-$wiki_config = $wiki_config.'&wiki__configEmail=email%40email.org';
-$wiki_config = $wiki_config.'&config__SkipOptional=skip';
-submit('Name', $wiki_config);
-submit('Install');
-submit('Install');
-
-unlink($tmp_cookie);
-?>
diff --git a/contrib/mw-to-git/t/t9360-mw-to-git-clone.sh b/contrib/mw-to-git/t/t9360-mw-to-git-clone.sh
index 9106833..4c39bda 100755
--- a/contrib/mw-to-git/t/t9360-mw-to-git-clone.sh
+++ b/contrib/mw-to-git/t/t9360-mw-to-git-clone.sh
@@ -28,7 +28,7 @@ test_expect_success 'Git clone creates the expected git log with one file' '
git log --format=%s HEAD^..HEAD >log.tmp
) &&
echo "this must be the same" >msg.tmp &&
- diff -b mw_dir_1/log.tmp msg.tmp
+ test_cmp msg.tmp mw_dir_1/log.tmp
'
@@ -50,8 +50,8 @@ test_expect_success 'Git clone creates the expected git log with multiple files'
echo "this must be the same" >>msgDaddy.tmp &&
echo "identical too" >msgDj.tmp &&
echo "identical" >>msgDj.tmp &&
- diff -b mw_dir_2/logDaddy.tmp msgDaddy.tmp &&
- diff -b mw_dir_2/logDj.tmp msgDj.tmp
+ test_cmp msgDaddy.tmp mw_dir_2/logDaddy.tmp &&
+ test_cmp msgDj.tmp mw_dir_2/logDj.tmp
'
@@ -135,7 +135,7 @@ test_expect_success 'Git clone works with one specific page cloned ' '
cd mw_dir_8 &&
echo "this log must stay" >msg.tmp &&
git log --format=%s >log.tmp &&
- diff -b msg.tmp log.tmp
+ test_cmp msg.tmp log.tmp
) &&
wiki_check_content mw_dir_8/Namnam.mw Namnam
'
diff --git a/contrib/mw-to-git/t/t9363-mw-to-git-export-import.sh b/contrib/mw-to-git/t/t9363-mw-to-git-export-import.sh
index 3ff3a09..6187ec6 100755
--- a/contrib/mw-to-git/t/t9363-mw-to-git-export-import.sh
+++ b/contrib/mw-to-git/t/t9363-mw-to-git-export-import.sh
@@ -27,12 +27,12 @@ test_git_reimport () {
# Don't bother with permissions, be administrator by default
test_expect_success 'setup config' '
- git config --global remote.origin.mwLogin WikiAdmin &&
- git config --global remote.origin.mwPassword AdminPass &&
+ git config --global remote.origin.mwLogin "$WIKI_ADMIN" &&
+ git config --global remote.origin.mwPassword "$WIKI_PASSW" &&
test_might_fail git config --global --unset remote.origin.mediaImport
'
-test_expect_success 'git push can upload media (File:) files' '
+test_expect_failure 'git push can upload media (File:) files' '
wiki_reset &&
git clone mediawiki::'"$WIKI_URL"' mw_dir &&
(
@@ -48,13 +48,14 @@ test_expect_success 'git push can upload media (File:) files' '
)
'
-test_expect_success 'git clone works on previously created wiki with media files' '
+test_expect_failure 'git clone works on previously created wiki with media files' '
test_when_finished "rm -rf mw_dir mw_dir_clone" &&
git clone -c remote.origin.mediaimport=true \
mediawiki::'"$WIKI_URL"' mw_dir_clone &&
test_cmp mw_dir_clone/Foo.txt mw_dir/Foo.txt &&
(cd mw_dir_clone && git checkout HEAD^) &&
(cd mw_dir && git checkout HEAD^) &&
+ test_path_is_file mw_dir_clone/Foo.txt &&
test_cmp mw_dir_clone/Foo.txt mw_dir/Foo.txt
'
diff --git a/contrib/mw-to-git/t/test-gitmw-lib.sh b/contrib/mw-to-git/t/test-gitmw-lib.sh
index 3948a00..64e46c1 100755
--- a/contrib/mw-to-git/t/test-gitmw-lib.sh
+++ b/contrib/mw-to-git/t/test-gitmw-lib.sh
@@ -13,7 +13,8 @@
. ./test.config
-WIKI_URL=http://"$SERVER_ADDR:$PORT/$WIKI_DIR_NAME"
+WIKI_BASE_URL=http://$SERVER_ADDR:$PORT
+WIKI_URL=$WIKI_BASE_URL/$WIKI_DIR_NAME
CURR_DIR=$(pwd)
TEST_OUTPUT_DIRECTORY=$(pwd)
TEST_DIRECTORY="$CURR_DIR"/../../../t
@@ -65,7 +66,7 @@ test_check_precond () {
GIT_EXEC_PATH=$(cd "$(dirname "$0")" && cd "../.." && pwd)
PATH="$GIT_EXEC_PATH"'/bin-wrapper:'"$PATH"
- if [ ! -d "$WIKI_DIR_INST/$WIKI_DIR_NAME" ];
+ if ! test -d "$WIKI_DIR_INST/$WIKI_DIR_NAME"
then
skip_all='skipping gateway git-mw tests, no mediawiki found'
test_done
@@ -291,27 +292,59 @@ stop_lighttpd () {
test -f "$WEB_TMP/pid" && kill $(cat "$WEB_TMP/pid")
}
-# Create the SQLite database of the MediaWiki. If the database file already
-# exists, it will be deleted.
-# This script should be runned from the directory where $FILES_FOLDER is
-# located.
-create_db () {
- rm -f "$TMP/$DB_FILE"
-
- echo "Generating the SQLite database file. It can take some time ..."
- # Run the php script to generate the SQLite database file
- # with cURL calls.
- php "$FILES_FOLDER/$DB_INSTALL_SCRIPT" $(basename "$DB_FILE" .sqlite) \
- "$WIKI_ADMIN" "$WIKI_PASSW" "$TMP" "$PORT"
-
- if [ ! -f "$TMP/$DB_FILE" ] ; then
- error "Can't create database file $TMP/$DB_FILE. Try to run ./install-wiki.sh delete first."
+wiki_delete_db () {
+ rm -rf \
+ "$FILES_FOLDER_DB"/* || error "Couldn't delete $FILES_FOLDER_DB/"
+}
+
+wiki_delete_db_backup () {
+ rm -rf \
+ "$FILES_FOLDER_POST_INSTALL_DB"/* || error "Couldn't delete $FILES_FOLDER_POST_INSTALL_DB/"
+}
+
+# Install MediaWiki using its install.php script. If the database file
+# already exists, it will be deleted.
+install_mediawiki () {
+
+ localsettings="$WIKI_DIR_INST/$WIKI_DIR_NAME/LocalSettings.php"
+ if test -f "$localsettings"
+ then
+ error "We already installed the wiki, since $localsettings exists" \
+ "perhaps you wanted to run 'delete' first?"
fi
- # Copy the generated database file into the directory the
- # user indicated.
- cp "$TMP/$DB_FILE" "$FILES_FOLDER" ||
- error "Unable to copy $TMP/$DB_FILE to $FILES_FOLDER"
+ wiki_delete_db
+ wiki_delete_db_backup
+ mkdir \
+ "$FILES_FOLDER_DB/" \
+ "$FILES_FOLDER_POST_INSTALL_DB/"
+
+ install_script="$WIKI_DIR_INST/$WIKI_DIR_NAME/maintenance/install.php"
+ echo "Installing MediaWiki using $install_script. This may take some time ..."
+
+ php "$WIKI_DIR_INST/$WIKI_DIR_NAME/maintenance/install.php" \
+ --server $WIKI_BASE_URL \
+ --scriptpath /wiki \
+ --lang en \
+ --dbtype sqlite \
+ --dbpath $PWD/$FILES_FOLDER_DB/ \
+ --pass "$WIKI_PASSW" \
+ Git-MediaWiki-Test \
+ "$WIKI_ADMIN" ||
+ error "Couldn't run $install_script, see errors above. Try to run ./install-wiki.sh delete first."
+ cat <<-'EOF' >>$localsettings
+# Custom settings added by test-gitmw-lib.sh
+#
+# Uploading text files is needed for
+# t9363-mw-to-git-export-import.sh
+$wgEnableUploads = true;
+$wgFileExtensions[] = 'txt';
+EOF
+
+ # Copy the initially generated database file into our backup
+ # folder
+ cp -R "$FILES_FOLDER_DB/"* "$FILES_FOLDER_POST_INSTALL_DB/" ||
+ error "Unable to copy $FILES_FOLDER_DB/* to $FILES_FOLDER_POST_INSTALL_DB/*"
}
# Install a wiki in your web server directory.
@@ -320,30 +353,33 @@ wiki_install () {
start_lighttpd
fi
- SERVER_ADDR=$SERVER_ADDR:$PORT
# In this part, we change directory to $TMP in order to download,
# unpack and copy the files of MediaWiki
(
mkdir -p "$WIKI_DIR_INST/$WIKI_DIR_NAME"
- if [ ! -d "$WIKI_DIR_INST/$WIKI_DIR_NAME" ] ; then
+ if ! test -d "$WIKI_DIR_INST/$WIKI_DIR_NAME"
+ then
error "Folder $WIKI_DIR_INST/$WIKI_DIR_NAME doesn't exist.
Please create it and launch the script again."
fi
- # Fetch MediaWiki's archive if not already present in the TMP directory
+ # Fetch MediaWiki's archive if not already present in the
+ # download directory
+ mkdir -p "$FILES_FOLDER_DOWNLOAD"
MW_FILENAME="mediawiki-$MW_VERSION_MAJOR.$MW_VERSION_MINOR.tar.gz"
- cd "$TMP"
- if [ ! -f $MW_FILENAME ] ; then
+ cd "$FILES_FOLDER_DOWNLOAD"
+ if ! test -f $MW_FILENAME
+ then
echo "Downloading $MW_VERSION_MAJOR.$MW_VERSION_MINOR sources ..."
wget "http://download.wikimedia.org/mediawiki/$MW_VERSION_MAJOR/$MW_FILENAME" ||
error "Unable to download "\
"http://download.wikimedia.org/mediawiki/$MW_VERSION_MAJOR/"\
"$MW_FILENAME. "\
"Please fix your connection and launch the script again."
- echo "$MW_FILENAME downloaded in $(pwd). "\
- "You can delete it later if you want."
+ echo "$MW_FILENAME downloaded in $(pwd)/;" \
+ "you can delete it later if you want."
else
- echo "Reusing existing $MW_FILENAME downloaded in $(pwd)."
+ echo "Reusing existing $MW_FILENAME downloaded in $(pwd)/"
fi
archive_abs_path=$(pwd)/$MW_FILENAME
cd "$WIKI_DIR_INST/$WIKI_DIR_NAME/" ||
@@ -352,48 +388,12 @@ wiki_install () {
error "Unable to extract WikiMedia's files from $archive_abs_path to "\
"$WIKI_DIR_INST/$WIKI_DIR_NAME"
) || exit 1
+ echo Extracted in "$WIKI_DIR_INST/$WIKI_DIR_NAME"
- create_db
-
- # Copy the generic LocalSettings.php in the web server's directory
- # And modify parameters according to the ones set at the top
- # of this script.
- # Note that LocalSettings.php is never modified.
- if [ ! -f "$FILES_FOLDER/LocalSettings.php" ] ; then
- error "Can't find $FILES_FOLDER/LocalSettings.php " \
- "in the current folder. "\
- "Please run the script inside its folder."
- fi
- cp "$FILES_FOLDER/LocalSettings.php" \
- "$FILES_FOLDER/LocalSettings-tmp.php" ||
- error "Unable to copy $FILES_FOLDER/LocalSettings.php " \
- "to $FILES_FOLDER/LocalSettings-tmp.php"
-
- # Parse and set the LocalSettings file of the user according to the
- # CONFIGURATION VARIABLES section at the beginning of this script
- file_swap="$FILES_FOLDER/LocalSettings-swap.php"
- sed "s,@WG_SCRIPT_PATH@,/$WIKI_DIR_NAME," \
- "$FILES_FOLDER/LocalSettings-tmp.php" > "$file_swap"
- mv "$file_swap" "$FILES_FOLDER/LocalSettings-tmp.php"
- sed "s,@WG_SERVER@,http://$SERVER_ADDR," \
- "$FILES_FOLDER/LocalSettings-tmp.php" > "$file_swap"
- mv "$file_swap" "$FILES_FOLDER/LocalSettings-tmp.php"
- sed "s,@WG_SQLITE_DATADIR@,$TMP," \
- "$FILES_FOLDER/LocalSettings-tmp.php" > "$file_swap"
- mv "$file_swap" "$FILES_FOLDER/LocalSettings-tmp.php"
- sed "s,@WG_SQLITE_DATAFILE@,$( basename $DB_FILE .sqlite)," \
- "$FILES_FOLDER/LocalSettings-tmp.php" > "$file_swap"
- mv "$file_swap" "$FILES_FOLDER/LocalSettings-tmp.php"
-
- mv "$FILES_FOLDER/LocalSettings-tmp.php" \
- "$WIKI_DIR_INST/$WIKI_DIR_NAME/LocalSettings.php" ||
- error "Unable to move $FILES_FOLDER/LocalSettings-tmp.php" \
- "in $WIKI_DIR_INST/$WIKI_DIR_NAME"
- echo "File $FILES_FOLDER/LocalSettings.php is set in" \
- " $WIKI_DIR_INST/$WIKI_DIR_NAME"
+ install_mediawiki
echo "Your wiki has been installed. You can check it at
- http://$SERVER_ADDR/$WIKI_DIR_NAME"
+ $WIKI_URL"
}
# Reset the database of the wiki and the password of the admin
@@ -401,12 +401,18 @@ wiki_install () {
# Warning: This function must be called only in a subdirectory of t/ directory
wiki_reset () {
# Copy initial database of the wiki
- if [ ! -f "../$FILES_FOLDER/$DB_FILE" ] ; then
- error "Can't find ../$FILES_FOLDER/$DB_FILE in the current folder."
+ if ! test -d "../$FILES_FOLDER_DB"
+ then
+ error "No wiki database at ../$FILES_FOLDER_DB, not installed yet?"
+ fi
+ if ! test -d "../$FILES_FOLDER_POST_INSTALL_DB"
+ then
+ error "No wiki backup database at ../$FILES_FOLDER_POST_INSTALL_DB, failed installation?"
fi
- cp "../$FILES_FOLDER/$DB_FILE" "$TMP" ||
- error "Can't copy ../$FILES_FOLDER/$DB_FILE in $TMP"
- echo "File $FILES_FOLDER/$DB_FILE is set in $TMP"
+ wiki_delete_db
+ cp -R "../$FILES_FOLDER_POST_INSTALL_DB/"* "../$FILES_FOLDER_DB/" ||
+ error "Can't copy ../$FILES_FOLDER_POST_INSTALL_DB/* to ../$FILES_FOLDER_DB/*"
+ echo "File $FILES_FOLDER_DB/* has been reset"
}
# Delete the wiki created in the web server's directory and all its content
@@ -420,13 +426,7 @@ wiki_delete () {
rm -rf "$WIKI_DIR_INST/$WIKI_DIR_NAME" ||
error "Wiki's directory $WIKI_DIR_INST/" \
"$WIKI_DIR_NAME could not be deleted"
- # Delete the wiki's SQLite database.
- rm -f "$TMP/$DB_FILE" ||
- error "Database $TMP/$DB_FILE could not be deleted."
fi
-
- # Delete the wiki's SQLite database
- rm -f "$TMP/$DB_FILE" || error "Database $TMP/$DB_FILE could not be deleted."
- rm -f "$FILES_FOLDER/$DB_FILE"
- rm -rf "$TMP/mediawiki-$MW_VERSION_MAJOR.$MW_VERSION_MINOR.tar.gz"
+ wiki_delete_db
+ wiki_delete_db_backup
}
diff --git a/contrib/mw-to-git/t/test-gitmw.pl b/contrib/mw-to-git/t/test-gitmw.pl
index 0ff7625..c5d687f 100755
--- a/contrib/mw-to-git/t/test-gitmw.pl
+++ b/contrib/mw-to-git/t/test-gitmw.pl
@@ -24,9 +24,7 @@
use MediaWiki::API;
use Getopt::Long;
-use encoding 'utf8';
use DateTime::Format::ISO8601;
-use open ':encoding(utf8)';
use constant SLASH_REPLACEMENT => "%2F";
#Parsing of the config file
@@ -87,7 +85,7 @@ sub wiki_getpage {
# Replace spaces by underscore in the page name
$pagename =~ s/ /_/g;
$pagename =~ s/\//%2F/g;
- open(my $file, ">$destdir/$pagename.mw");
+ open(my $file, ">:encoding(UTF-8)", "$destdir/$pagename.mw");
print $file "$content";
close ($file);
@@ -172,7 +170,7 @@ sub wiki_getallpagename {
cmlimit => 500 },
)
|| die $mw->{error}->{code}.": ".$mw->{error}->{details};
- open(my $file, ">all.txt");
+ open(my $file, ">:encoding(UTF-8)", "all.txt");
foreach my $page (@{$mw_pages}) {
print $file "$page->{title}\n";
}
@@ -185,7 +183,7 @@ sub wiki_getallpagename {
aplimit => 500,
})
|| die $mw->{error}->{code}.": ".$mw->{error}->{details};
- open(my $file, ">all.txt");
+ open(my $file, ">:encoding(UTF-8)", "all.txt");
foreach my $page (@{$mw_pages}) {
print $file "$page->{title}\n";
}
@@ -214,12 +212,12 @@ my $fct_to_call = shift;
wiki_login($wiki_admin, $wiki_admin_pass);
-my %functions_to_call = qw(
- upload_file wiki_upload_file
- get_page wiki_getpage
- delete_page wiki_delete_page
- edit_page wiki_editpage
- getallpagename wiki_getallpagename
+my %functions_to_call = (
+ upload_file => \&wiki_upload_file,
+ get_page => \&wiki_getpage,
+ delete_page => \&wiki_delete_page,
+ edit_page => \&wiki_editpage,
+ getallpagename => \&wiki_getallpagename,
);
die "$0 ERROR: wrong argument" unless exists $functions_to_call{$fct_to_call};
-&{$functions_to_call{$fct_to_call}}(@ARGV);
+$functions_to_call{$fct_to_call}->(map { utf8::decode($_); $_ } @ARGV);
diff --git a/contrib/mw-to-git/t/test.config b/contrib/mw-to-git/t/test.config
index 5ba0684..ed10b3e 100644
--- a/contrib/mw-to-git/t/test.config
+++ b/contrib/mw-to-git/t/test.config
@@ -3,15 +3,11 @@ WIKI_DIR_NAME=wiki
# Login and password of the wiki's admin
WIKI_ADMIN=WikiAdmin
-WIKI_PASSW=AdminPass
+WIKI_PASSW=AdminPass1
# Address of the web server
SERVER_ADDR=localhost
-# SQLite database of the wiki, named DB_FILE, is located in TMP
-TMP=/tmp
-DB_FILE=wikidb.sqlite
-
# If LIGHTTPD is not set to true, the script will use the default
# web server running in WIKI_DIR_INST.
WIKI_DIR_INST=/var/www
@@ -28,10 +24,17 @@ WEB=WEB
WEB_TMP=$WEB/tmp
WEB_WWW=$WEB/www
+# Where our configuration for the wiki is located
+FILES_FOLDER=mediawiki
+FILES_FOLDER_DOWNLOAD=$FILES_FOLDER/download
+FILES_FOLDER_DB=$FILES_FOLDER/db
+FILES_FOLDER_POST_INSTALL_DB=$FILES_FOLDER/post-install-db
+
# The variables below are used by the script to install a wiki.
# You should not modify these unless you are modifying the script itself.
-# tested versions: 1.19.X -> 1.21.1
-MW_VERSION_MAJOR=1.21
-MW_VERSION_MINOR=1
-FILES_FOLDER=install-wiki
-DB_INSTALL_SCRIPT=db_install.php
+# tested versions: 1.19.X -> 1.21.1 -> 1.34.2
+#
+# See https://www.mediawiki.org/wiki/Download for what the latest
+# version is.
+MW_VERSION_MAJOR=1.34
+MW_VERSION_MINOR=2
diff --git a/diff-lib.c b/diff-lib.c
index 346fdcf..f95c6de 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -177,9 +177,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
i--;
if (revs->combine_merges && num_compare_stages == 2) {
- show_combined_diff(dpath, 2,
- revs->dense_combined_merges,
- revs);
+ show_combined_diff(dpath, 2, revs);
free(dpath);
continue;
}
@@ -361,7 +359,7 @@ static int show_modified(struct rev_info *revs,
p->parent[1].status = DIFF_STATUS_MODIFIED;
p->parent[1].mode = old_entry->ce_mode;
oidcpy(&p->parent[1].oid, &old_entry->oid);
- show_combined_diff(p, 2, revs->dense_combined_merges, revs);
+ show_combined_diff(p, 2, revs);
free(p);
return 0;
}
diff --git a/diff.c b/diff.c
index ee8e818..2bb2f8f 100644
--- a/diff.c
+++ b/diff.c
@@ -3663,7 +3663,7 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
{
mmfile_t mf1, mf2;
struct diffstat_file *data;
- int same_contents;
+ int may_differ;
int complete_rewrite = 0;
if (!DIFF_PAIR_UNMERGED(p)) {
@@ -3681,12 +3681,14 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
return;
}
- same_contents = oideq(&one->oid, &two->oid);
+ /* saves some reads if true, not a guarantee of diff outcome */
+ may_differ = !(one->oid_valid && two->oid_valid &&
+ oideq(&one->oid, &two->oid));
if (diff_filespec_is_binary(o->repo, one) ||
diff_filespec_is_binary(o->repo, two)) {
data->is_binary = 1;
- if (same_contents) {
+ if (!may_differ) {
data->added = 0;
data->deleted = 0;
} else {
@@ -3702,7 +3704,7 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
data->added = count_lines(two->data, two->size);
}
- else if (!same_contents) {
+ else if (may_differ) {
/* Crazy xdl interfaces.. */
xpparam_t xpp;
xdemitconf_t xecfg;
@@ -3727,7 +3729,7 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
diffstat->files[diffstat->nr - 1];
/*
* Omit diffstats of modified files where nothing changed.
- * Even if !same_contents, this might be the case due to
+ * Even if may_differ, this might be the case due to
* ignoring whitespace changes, etc.
*
* But note that we special-case additions, deletions,
diff --git a/diff.h b/diff.h
index 49242d2..11de52e 100644
--- a/diff.h
+++ b/diff.h
@@ -287,8 +287,6 @@ struct diff_options {
/* If non-zero, then stop computing after this many changes. */
int max_changes;
- /* For internal use only. */
- int num_changes;
int ita_invisible_in_index;
/* white-space error highlighting */
@@ -454,11 +452,11 @@ struct combine_diff_path {
st_mult(sizeof(struct combine_diff_parent), (n)))
void show_combined_diff(struct combine_diff_path *elem, int num_parent,
- int dense, struct rev_info *);
+ struct rev_info *);
-void diff_tree_combined(const struct object_id *oid, const struct oid_array *parents, int dense, struct rev_info *rev);
+void diff_tree_combined(const struct object_id *oid, const struct oid_array *parents, struct rev_info *rev);
-void diff_tree_combined_merge(const struct commit *commit, int dense, struct rev_info *rev);
+void diff_tree_combined_merge(const struct commit *commit, struct rev_info *rev);
void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const char *b);
diff --git a/fuzz-commit-graph.c b/fuzz-commit-graph.c
index 4308172..e7cf6d5 100644
--- a/fuzz-commit-graph.c
+++ b/fuzz-commit-graph.c
@@ -1,7 +1,8 @@
#include "commit-graph.h"
#include "repository.h"
-struct commit_graph *parse_commit_graph(void *graph_map, size_t graph_size);
+struct commit_graph *parse_commit_graph(struct repository *r,
+ void *graph_map, size_t graph_size);
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
@@ -10,7 +11,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
struct commit_graph *g;
initialize_the_repository();
- g = parse_commit_graph((void *)data, size);
+ g = parse_commit_graph(the_repository, (void *)data, size);
repo_clear(the_repository);
free_commit_graph(g);
diff --git a/git-bisect.sh b/git-bisect.sh
index 2f60fef..ea7e684 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -49,27 +49,6 @@ bisect_head()
fi
}
-bisect_autostart() {
- test -s "$GIT_DIR/BISECT_START" || {
- gettextln "You need to start by \"git bisect start\"" >&2
- if test -t 0
- then
- # TRANSLATORS: Make sure to include [Y] and [n] in your
- # translation. The program will only accept English input
- # at this point.
- gettext "Do you want me to do it for you [Y/n]? " >&2
- read yesno
- case "$yesno" in
- [Nn]*)
- exit ;;
- esac
- bisect_start
- else
- exit 1
- fi
- }
-}
-
bisect_start() {
git bisect--helper --bisect-start $@ || exit
@@ -86,8 +65,7 @@ bisect_start() {
#
# Check if we can proceed to the next bisect state.
#
- get_terms
- bisect_auto_next
+ git bisect--helper --bisect-auto-next || exit
trap '-' 0
}
@@ -108,7 +86,7 @@ bisect_skip() {
}
bisect_state() {
- bisect_autostart
+ git bisect--helper --bisect-autostart || exit
state=$1
git bisect--helper --check-and-set-terms $state $TERM_GOOD $TERM_BAD || exit
get_terms
@@ -140,45 +118,7 @@ bisect_state() {
*)
usage ;;
esac
- bisect_auto_next
-}
-
-bisect_auto_next() {
- git bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD && bisect_next || :
-}
-
-bisect_next() {
- case "$#" in 0) ;; *) usage ;; esac
- bisect_autostart
- git bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD $TERM_GOOD|| exit
-
- # Perform all bisection computation, display and checkout
- git bisect--helper --next-all
- res=$?
-
- # Check if we should exit because bisection is finished
- if test $res -eq 10
- then
- bad_rev=$(git show-ref --hash --verify refs/bisect/$TERM_BAD)
- bad_commit=$(git show-branch $bad_rev)
- echo "# first $TERM_BAD commit: $bad_commit" >>"$GIT_DIR/BISECT_LOG"
- exit 0
- elif test $res -eq 2
- then
- echo "# only skipped commits left to test" >>"$GIT_DIR/BISECT_LOG"
- good_revs=$(git for-each-ref --format="%(objectname)" "refs/bisect/$TERM_GOOD-*")
- for skipped in $(git rev-list refs/bisect/$TERM_BAD --not $good_revs)
- do
- skipped_commit=$(git show-branch $skipped)
- echo "# possible first $TERM_BAD commit: $skipped_commit" >>"$GIT_DIR/BISECT_LOG"
- done
- exit $res
- fi
-
- # Check for an error in the bisection process
- test $res -ne 0 && exit $res
-
- return 0
+ git bisect--helper --bisect-auto-next
}
bisect_visualize() {
@@ -234,7 +174,7 @@ bisect_replay () {
esac
done <"$file"
IFS="$oIFS"
- bisect_auto_next
+ git bisect--helper --bisect-auto-next || exit
}
bisect_run () {
@@ -331,7 +271,7 @@ case "$#" in
bisect_skip "$@" ;;
next)
# Not sure we want "next" at the UI level anymore.
- bisect_next "$@" ;;
+ git bisect--helper --bisect-next "$@" || exit ;;
visualize|view)
bisect_visualize "$@" ;;
reset)
diff --git a/git-p4.py b/git-p4.py
index ca79dc0..4433ca5 100755
--- a/git-p4.py
+++ b/git-p4.py
@@ -4237,7 +4237,7 @@ class P4Unshelve(Command):
"""
for parent in (range(65535)):
- log = extractLogMessageFromGitCommit("{0}^{1}".format(starting_point, parent))
+ log = extractLogMessageFromGitCommit("{0}~{1}".format(starting_point, parent))
settings = extractSettingsGitLog(log)
if 'change' in settings:
return settings
diff --git a/git.c b/git.c
index 01c456e..f1e8b56 100644
--- a/git.c
+++ b/git.c
@@ -534,6 +534,7 @@ static struct cmd_struct commands[] = {
{ "ls-tree", cmd_ls_tree, RUN_SETUP },
{ "mailinfo", cmd_mailinfo, RUN_SETUP_GENTLY | NO_PARSEOPT },
{ "mailsplit", cmd_mailsplit, NO_PARSEOPT },
+ { "maintenance", cmd_maintenance, RUN_SETUP_GENTLY | NO_PARSEOPT },
{ "merge", cmd_merge, RUN_SETUP | NEED_WORK_TREE },
{ "merge-base", cmd_merge_base, RUN_SETUP },
{ "merge-file", cmd_merge_file, RUN_SETUP_GENTLY },
diff --git a/gitk-git/gitk b/gitk-git/gitk
index abe4805..23d9dd1 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -11,14 +11,14 @@ package require Tk
proc hasworktree {} {
return [expr {[exec git rev-parse --is-bare-repository] == "false" &&
- [exec git rev-parse --is-inside-git-dir] == "false"}]
+ [exec git rev-parse --is-inside-git-dir] == "false"}]
}
proc reponame {} {
global gitdir
set n [file normalize $gitdir]
if {[string match "*/.git" $n]} {
- set n [string range $n 0 end-5]
+ set n [string range $n 0 end-5]
}
return [file tail $n]
}
@@ -26,7 +26,7 @@ proc reponame {} {
proc gitworktree {} {
variable _gitworktree
if {[info exists _gitworktree]} {
- return $_gitworktree
+ return $_gitworktree
}
# v1.7.0 introduced --show-toplevel to return the canonical work-tree
if {[catch {set _gitworktree [exec git rev-parse --show-toplevel]}]} {
@@ -34,10 +34,9 @@ proc gitworktree {} {
# cdup to obtain a relative path to the top of the worktree. If
# run from the top, the ./ prefix ensures normalize expands pwd.
if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} {
- catch {set _gitworktree [exec git config --get core.worktree]}
- if {$_gitworktree eq ""} {
- set _gitworktree [file normalize ./[exec git rev-parse --show-cdup]]
- }
+ if {[catch {set _gitworktree [exec git config --get core.worktree]}]} {
+ set _gitworktree [file normalize ./[exec git rev-parse --show-cdup]]
+ }
}
}
return $_gitworktree
@@ -54,7 +53,7 @@ proc run args {
set script $args
if {[info exists isonrunq($script)]} return
if {$runq eq {} && ![info exists currunq]} {
- after idle dorunq
+ after idle dorunq
}
lappend runq [list {} $script]
set isonrunq($script) 1
@@ -69,7 +68,7 @@ proc filereadable {fd script} {
fileevent $fd readable {}
if {$runq eq {} && ![info exists currunq]} {
- after idle dorunq
+ after idle dorunq
}
lappend runq [list $fd $script]
}
@@ -78,11 +77,11 @@ proc nukefile {fd} {
global runq
for {set i 0} {$i < [llength $runq]} {} {
- if {[lindex $runq $i 0] eq $fd} {
- set runq [lreplace $runq $i $i]
- } else {
- incr i
- }
+ if {[lindex $runq $i 0] eq $fd} {
+ set runq [lreplace $runq $i $i]
+ } else {
+ incr i
+ }
}
}
@@ -92,30 +91,30 @@ proc dorunq {} {
set tstart [clock clicks -milliseconds]
set t0 $tstart
while {[llength $runq] > 0} {
- set fd [lindex $runq 0 0]
- set script [lindex $runq 0 1]
- set currunq [lindex $runq 0]
- set runq [lrange $runq 1 end]
- set repeat [eval $script]
- unset currunq
- set t1 [clock clicks -milliseconds]
- set t [expr {$t1 - $t0}]
- if {$repeat ne {} && $repeat} {
- if {$fd eq {} || $repeat == 2} {
- # script returns 1 if it wants to be readded
- # file readers return 2 if they could do more straight away
- lappend runq [list $fd $script]
- } else {
- fileevent $fd readable [list filereadable $fd $script]
- }
- } elseif {$fd eq {}} {
- unset isonrunq($script)
- }
- set t0 $t1
- if {$t1 - $tstart >= 80} break
+ set fd [lindex $runq 0 0]
+ set script [lindex $runq 0 1]
+ set currunq [lindex $runq 0]
+ set runq [lrange $runq 1 end]
+ set repeat [eval $script]
+ unset currunq
+ set t1 [clock clicks -milliseconds]
+ set t [expr {$t1 - $t0}]
+ if {$repeat ne {} && $repeat} {
+ if {$fd eq {} || $repeat == 2} {
+ # script returns 1 if it wants to be readded
+ # file readers return 2 if they could do more straight away
+ lappend runq [list $fd $script]
+ } else {
+ fileevent $fd readable [list filereadable $fd $script]
+ }
+ } elseif {$fd eq {}} {
+ unset isonrunq($script)
+ }
+ set t0 $t1
+ if {$t1 - $tstart >= 80} break
}
if {$runq ne {}} {
- after idle dorunq
+ after idle dorunq
}
}
@@ -135,20 +134,20 @@ proc unmerged_files {files} {
set mlist {}
set nr_unmerged 0
if {[catch {
- set fd [open "| git ls-files -u" r]
+ set fd [open "| git ls-files -u" r]
} err]} {
- show_error {} . "[mc "Couldn't get list of unmerged files:"] $err"
- exit 1
+ show_error {} . "[mc "Couldn't get list of unmerged files:"] $err"
+ exit 1
}
while {[gets $fd line] >= 0} {
- set i [string first "\t" $line]
- if {$i < 0} continue
- set fname [string range $line [expr {$i+1}] end]
- if {[lsearch -exact $mlist $fname] >= 0} continue
- incr nr_unmerged
- if {$files eq {} || [path_filter $files $fname]} {
- lappend mlist $fname
- }
+ set i [string first "\t" $line]
+ if {$i < 0} continue
+ set fname [string range $line [expr {$i+1}] end]
+ if {[lsearch -exact $mlist $fname] >= 0} continue
+ incr nr_unmerged
+ if {$files eq {} || [path_filter $files $fname]} {
+ lappend mlist $fname
+ }
}
catch {close $fd}
return $mlist
@@ -171,115 +170,115 @@ proc parseviewargs {n arglist} {
set filtered 0
set i -1
foreach arg $arglist {
- incr i
- if {$nextisval} {
- lappend glflags $arg
- set nextisval 0
- continue
- }
- switch -glob -- $arg {
- "-d" -
- "--date-order" {
- set vdatemode($n) 1
- # remove from origargs in case we hit an unknown option
- set origargs [lreplace $origargs $i $i]
- incr i -1
- }
- "-[puabwcrRBMC]" -
- "--no-renames" - "--full-index" - "--binary" - "--abbrev=*" -
- "--find-copies-harder" - "-l*" - "--ext-diff" - "--no-ext-diff" -
- "--src-prefix=*" - "--dst-prefix=*" - "--no-prefix" -
- "-O*" - "--text" - "--full-diff" - "--ignore-space-at-eol" -
- "--ignore-space-change" - "-U*" - "--unified=*" {
- # These request or affect diff output, which we don't want.
- # Some could be used to set our defaults for diff display.
- lappend diffargs $arg
- }
- "--raw" - "--patch-with-raw" - "--patch-with-stat" -
- "--name-only" - "--name-status" - "--color" -
- "--log-size" - "--pretty=*" - "--decorate" - "--abbrev-commit" -
- "--cc" - "-z" - "--header" - "--parents" - "--boundary" -
- "--no-color" - "-g" - "--walk-reflogs" - "--no-walk" -
- "--timestamp" - "relative-date" - "--date=*" - "--stdin" -
- "--objects" - "--objects-edge" - "--reverse" {
- # These cause our parsing of git log's output to fail, or else
- # they're options we want to set ourselves, so ignore them.
- }
- "--color-words*" - "--word-diff=color" {
- # These trigger a word diff in the console interface,
- # so help the user by enabling our own support
- if {[package vcompare $git_version "1.7.2"] >= 0} {
- set worddiff [mc "Color words"]
- }
- }
- "--word-diff*" {
- if {[package vcompare $git_version "1.7.2"] >= 0} {
- set worddiff [mc "Markup words"]
- }
- }
- "--stat=*" - "--numstat" - "--shortstat" - "--summary" -
- "--check" - "--exit-code" - "--quiet" - "--topo-order" -
- "--full-history" - "--dense" - "--sparse" -
- "--follow" - "--left-right" - "--encoding=*" {
- # These are harmless, and some are even useful
- lappend glflags $arg
- }
- "--diff-filter=*" - "--no-merges" - "--unpacked" -
- "--max-count=*" - "--skip=*" - "--since=*" - "--after=*" -
- "--until=*" - "--before=*" - "--max-age=*" - "--min-age=*" -
- "--author=*" - "--committer=*" - "--grep=*" - "-[iE]" -
- "--remove-empty" - "--first-parent" - "--cherry-pick" -
- "-S*" - "-G*" - "--pickaxe-all" - "--pickaxe-regex" -
- "--simplify-by-decoration" {
- # These mean that we get a subset of the commits
- set filtered 1
- lappend glflags $arg
- }
- "-L*" {
- # Line-log with 'stuck' argument (unstuck form is
- # not supported)
- set filtered 1
- set vinlinediff($n) 1
- set allknown 0
- lappend glflags $arg
- }
- "-n" {
- # This appears to be the only one that has a value as a
- # separate word following it
- set filtered 1
- set nextisval 1
- lappend glflags $arg
- }
- "--not" - "--all" {
- lappend revargs $arg
- }
- "--merge" {
- set vmergeonly($n) 1
- # git rev-parse doesn't understand --merge
- lappend revargs --gitk-symmetric-diff-marker MERGE_HEAD...HEAD
- }
- "--no-replace-objects" {
- set env(GIT_NO_REPLACE_OBJECTS) "1"
- }
- "-*" {
- # Other flag arguments including -<n>
- if {[string is digit -strict [string range $arg 1 end]]} {
- set filtered 1
- } else {
- # a flag argument that we don't recognize;
- # that means we can't optimize
- set allknown 0
- }
- lappend glflags $arg
- }
- default {
- # Non-flag arguments specify commits or ranges of commits
- if {[string match "*...*" $arg]} {
- lappend revargs --gitk-symmetric-diff-marker
- }
- lappend revargs $arg
- }
- }
+ incr i
+ if {$nextisval} {
+ lappend glflags $arg
+ set nextisval 0
+ continue
+ }
+ switch -glob -- $arg {
+ "-d" -
+ "--date-order" {
+ set vdatemode($n) 1
+ # remove from origargs in case we hit an unknown option
+ set origargs [lreplace $origargs $i $i]
+ incr i -1
+ }
+ "-[puabwcrRBMC]" -
+ "--no-renames" - "--full-index" - "--binary" - "--abbrev=*" -
+ "--find-copies-harder" - "-l*" - "--ext-diff" - "--no-ext-diff" -
+ "--src-prefix=*" - "--dst-prefix=*" - "--no-prefix" -
+ "-O*" - "--text" - "--full-diff" - "--ignore-space-at-eol" -
+ "--ignore-space-change" - "-U*" - "--unified=*" {
+ # These request or affect diff output, which we don't want.
+ # Some could be used to set our defaults for diff display.
+ lappend diffargs $arg
+ }
+ "--raw" - "--patch-with-raw" - "--patch-with-stat" -
+ "--name-only" - "--name-status" - "--color" -
+ "--log-size" - "--pretty=*" - "--decorate" - "--abbrev-commit" -
+ "--cc" - "-z" - "--header" - "--parents" - "--boundary" -
+ "--no-color" - "-g" - "--walk-reflogs" - "--no-walk" -
+ "--timestamp" - "relative-date" - "--date=*" - "--stdin" -
+ "--objects" - "--objects-edge" - "--reverse" {
+ # These cause our parsing of git log's output to fail, or else
+ # they're options we want to set ourselves, so ignore them.
+ }
+ "--color-words*" - "--word-diff=color" {
+ # These trigger a word diff in the console interface,
+ # so help the user by enabling our own support
+ if {[package vcompare $git_version "1.7.2"] >= 0} {
+ set worddiff [mc "Color words"]
+ }
+ }
+ "--word-diff*" {
+ if {[package vcompare $git_version "1.7.2"] >= 0} {
+ set worddiff [mc "Markup words"]
+ }
+ }
+ "--stat=*" - "--numstat" - "--shortstat" - "--summary" -
+ "--check" - "--exit-code" - "--quiet" - "--topo-order" -
+ "--full-history" - "--dense" - "--sparse" -
+ "--follow" - "--left-right" - "--encoding=*" {
+ # These are harmless, and some are even useful
+ lappend glflags $arg
+ }
+ "--diff-filter=*" - "--no-merges" - "--unpacked" -
+ "--max-count=*" - "--skip=*" - "--since=*" - "--after=*" -
+ "--until=*" - "--before=*" - "--max-age=*" - "--min-age=*" -
+ "--author=*" - "--committer=*" - "--grep=*" - "-[iE]" -
+ "--remove-empty" - "--first-parent" - "--cherry-pick" -
+ "-S*" - "-G*" - "--pickaxe-all" - "--pickaxe-regex" -
+ "--simplify-by-decoration" {
+ # These mean that we get a subset of the commits
+ set filtered 1
+ lappend glflags $arg
+ }
+ "-L*" {
+ # Line-log with 'stuck' argument (unstuck form is
+ # not supported)
+ set filtered 1
+ set vinlinediff($n) 1
+ set allknown 0
+ lappend glflags $arg
+ }
+ "-n" {
+ # This appears to be the only one that has a value as a
+ # separate word following it
+ set filtered 1
+ set nextisval 1
+ lappend glflags $arg
+ }
+ "--not" - "--all" {
+ lappend revargs $arg
+ }
+ "--merge" {
+ set vmergeonly($n) 1
+ # git rev-parse doesn't understand --merge
+ lappend revargs --gitk-symmetric-diff-marker MERGE_HEAD...HEAD
+ }
+ "--no-replace-objects" {
+ set env(GIT_NO_REPLACE_OBJECTS) "1"
+ }
+ "-*" {
+ # Other flag arguments including -<n>
+ if {[string is digit -strict [string range $arg 1 end]]} {
+ set filtered 1
+ } else {
+ # a flag argument that we don't recognize;
+ # that means we can't optimize
+ set allknown 0
+ }
+ lappend glflags $arg
+ }
+ default {
+ # Non-flag arguments specify commits or ranges of commits
+ if {[string match "*...*" $arg]} {
+ lappend revargs --gitk-symmetric-diff-marker
+ }
+ lappend revargs $arg
+ }
+ }
}
set vdflags($n) $diffargs
set vflags($n) $glflags
@@ -293,61 +292,61 @@ proc parseviewrevs {view revs} {
global vposids vnegids
if {$revs eq {}} {
- set revs HEAD
+ set revs HEAD
} elseif {[lsearch -exact $revs --all] >= 0} {
- lappend revs HEAD
+ lappend revs HEAD
}
if {[catch {set ids [eval exec git rev-parse $revs]} err]} {
- # we get stdout followed by stderr in $err
- # for an unknown rev, git rev-parse echoes it and then errors out
- set errlines [split $err "\n"]
- set badrev {}
- for {set l 0} {$l < [llength $errlines]} {incr l} {
- set line [lindex $errlines $l]
- if {!([string length $line] == 40 && [string is xdigit $line])} {
- if {[string match "fatal:*" $line]} {
- if {[string match "fatal: ambiguous argument*" $line]
- && $badrev ne {}} {
- if {[llength $badrev] == 1} {
- set err "unknown revision $badrev"
- } else {
- set err "unknown revisions: [join $badrev ", "]"
- }
- } else {
- set err [join [lrange $errlines $l end] "\n"]
- }
- break
- }
- lappend badrev $line
- }
- }
- error_popup "[mc "Error parsing revisions:"] $err"
- return {}
+ # we get stdout followed by stderr in $err
+ # for an unknown rev, git rev-parse echoes it and then errors out
+ set errlines [split $err "\n"]
+ set badrev {}
+ for {set l 0} {$l < [llength $errlines]} {incr l} {
+ set line [lindex $errlines $l]
+ if {!([string length $line] == 40 && [string is xdigit $line])} {
+ if {[string match "fatal:*" $line]} {
+ if {[string match "fatal: ambiguous argument*" $line]
+ && $badrev ne {}} {
+ if {[llength $badrev] == 1} {
+ set err "unknown revision $badrev"
+ } else {
+ set err "unknown revisions: [join $badrev ", "]"
+ }
+ } else {
+ set err [join [lrange $errlines $l end] "\n"]
+ }
+ break
+ }
+ lappend badrev $line
+ }
+ }
+ error_popup "[mc "Error parsing revisions:"] $err"
+ return {}
}
set ret {}
set pos {}
set neg {}
set sdm 0
foreach id [split $ids "\n"] {
- if {$id eq "--gitk-symmetric-diff-marker"} {
- set sdm 4
- } elseif {[string match "^*" $id]} {
- if {$sdm != 1} {
- lappend ret $id
- if {$sdm == 3} {
- set sdm 0
- }
- }
- lappend neg [string range $id 1 end]
- } else {
- if {$sdm != 2} {
- lappend ret $id
- } else {
- lset ret end $id...[lindex $ret end]
- }
- lappend pos $id
- }
- incr sdm -1
+ if {$id eq "--gitk-symmetric-diff-marker"} {
+ set sdm 4
+ } elseif {[string match "^*" $id]} {
+ if {$sdm != 1} {
+ lappend ret $id
+ if {$sdm == 3} {
+ set sdm 0
+ }
+ }
+ lappend neg [string range $id 1 end]
+ } else {
+ if {$sdm != 2} {
+ lappend ret $id
+ } else {
+ lset ret end $id...[lindex $ret end]
+ }
+ lappend pos $id
+ }
+ incr sdm -1
}
set vposids($view) $pos
set vnegids($view) $neg
@@ -374,63 +373,63 @@ proc start_rev_list {view} {
set args $viewargs($view)
if {$viewargscmd($view) ne {}} {
- if {[catch {
- set str [exec sh -c $viewargscmd($view)]
- } err]} {
- error_popup "[mc "Error executing --argscmd command:"] $err"
- return 0
- }
- set args [concat $args [split $str "\n"]]
+ if {[catch {
+ set str [exec sh -c $viewargscmd($view)]
+ } err]} {
+ error_popup "[mc "Error executing --argscmd command:"] $err"
+ return 0
+ }
+ set args [concat $args [split $str "\n"]]
}
set vcanopt($view) [parseviewargs $view $args]
set files $viewfiles($view)
if {$vmergeonly($view)} {
- set files [unmerged_files $files]
- if {$files eq {}} {
- global nr_unmerged
- if {$nr_unmerged == 0} {
- error_popup [mc "No files selected: --merge specified but\
- no files are unmerged."]
- } else {
- error_popup [mc "No files selected: --merge specified but\
- no unmerged files are within file limit."]
- }
- return 0
- }
+ set files [unmerged_files $files]
+ if {$files eq {}} {
+ global nr_unmerged
+ if {$nr_unmerged == 0} {
+ error_popup [mc "No files selected: --merge specified but\
+ no files are unmerged."]
+ } else {
+ error_popup [mc "No files selected: --merge specified but\
+ no unmerged files are within file limit."]
+ }
+ return 0
+ }
}
set vfilelimit($view) $files
if {$vcanopt($view)} {
- set revs [parseviewrevs $view $vrevs($view)]
- if {$revs eq {}} {
- return 0
- }
- set args [concat $vflags($view) $revs]
+ set revs [parseviewrevs $view $vrevs($view)]
+ if {$revs eq {}} {
+ return 0
+ }
+ set args [concat $vflags($view) $revs]
} else {
- set args $vorigargs($view)
+ set args $vorigargs($view)
}
if {[catch {
- set fd [open [concat | git log --no-color -z --pretty=raw $show_notes \
- --parents --boundary $args "--" $files] r]
+ set fd [open [concat | git log --no-color -z --pretty=raw $show_notes \
+ --parents --boundary $args "--" $files] r]
} err]} {
- error_popup "[mc "Error executing git log:"] $err"
- return 0
+ error_popup "[mc "Error executing git log:"] $err"
+ return 0
}
set i [reg_instance $fd]
set viewinstances($view) [list $i]
set viewmainheadid($view) $mainheadid
set viewmainheadid_orig($view) $mainheadid
if {$files ne {} && $mainheadid ne {}} {
- get_viewmainhead $view
+ get_viewmainhead $view
}
if {$showlocalchanges && $viewmainheadid($view) ne {}} {
- interestedin $viewmainheadid($view) dodiffindex
+ interestedin $viewmainheadid($view) dodiffindex
}
fconfigure $fd -blocking 0 -translation lf -eofchar {}
if {$tclencoding != {}} {
- fconfigure $fd -encoding $tclencoding
+ fconfigure $fd -encoding $tclencoding
}
filerun $fd [list getcommitlines $fd $i $view 0]
nowbusy $view [mc "Reading"]
@@ -444,13 +443,13 @@ proc stop_instance {inst} {
set fd $commfd($inst)
catch {
- set pid [pid $fd]
+ set pid [pid $fd]
- if {$::tcl_platform(platform) eq {windows}} {
- exec taskkill /pid $pid
- } else {
- exec kill $pid
- }
+ if {$::tcl_platform(platform) eq {windows}} {
+ exec taskkill /pid $pid
+ } else {
+ exec kill $pid
+ }
}
catch {close $fd}
nukefile $fd
@@ -462,7 +461,7 @@ proc stop_backends {} {
global commfd
foreach inst [array names commfd] {
- stop_instance $inst
+ stop_instance $inst
}
}
@@ -470,7 +469,7 @@ proc stop_rev_list {view} {
global viewinstances
foreach inst $viewinstances($view) {
- stop_instance $inst
+ stop_instance $inst
}
set viewinstances($view) {}
}
@@ -479,11 +478,11 @@ proc reset_pending_select {selid} {
global pending_select mainheadid selectheadid
if {$selid ne {}} {
- set pending_select $selid
+ set pending_select $selid
} elseif {$selectheadid ne {}} {
- set pending_select $selectheadid
+ set pending_select $selectheadid
} else {
- set pending_select $mainheadid
+ set pending_select $mainheadid
}
}
@@ -492,11 +491,11 @@ proc getcommits {selid} {
initlayout
if {[start_rev_list $curview]} {
- reset_pending_select $selid
- show_status [mc "Reading commits..."]
- set need_redisplay 1
+ reset_pending_select $selid
+ show_status [mc "Reading commits..."]
+ set need_redisplay 1
} else {
- show_status [mc "No commits selected"]
+ show_status [mc "No commits selected"]
}
}
@@ -513,67 +512,67 @@ proc updatecommits {} {
rereadrefs
set view $curview
if {$mainheadid ne $viewmainheadid_orig($view)} {
- if {$showlocalchanges} {
- dohidelocalchanges
- }
- set viewmainheadid($view) $mainheadid
- set viewmainheadid_orig($view) $mainheadid
- if {$vfilelimit($view) ne {}} {
- get_viewmainhead $view
- }
+ if {$showlocalchanges} {
+ dohidelocalchanges
+ }
+ set viewmainheadid($view) $mainheadid
+ set viewmainheadid_orig($view) $mainheadid
+ if {$vfilelimit($view) ne {}} {
+ get_viewmainhead $view
+ }
}
if {$showlocalchanges} {
- doshowlocalchanges
+ doshowlocalchanges
}
if {$vcanopt($view)} {
- set oldpos $vposids($view)
- set oldneg $vnegids($view)
- set revs [parseviewrevs $view $vrevs($view)]
- if {$revs eq {}} {
- return
- }
- # note: getting the delta when negative refs change is hard,
- # and could require multiple git log invocations, so in that
- # case we ask git log for all the commits (not just the delta)
- if {$oldneg eq $vnegids($view)} {
- set newrevs {}
- set npos 0
- # take out positive refs that we asked for before or
- # that we have already seen
- foreach rev $revs {
- if {[string length $rev] == 40} {
- if {[lsearch -exact $oldpos $rev] < 0
- && ![info exists varcid($view,$rev)]} {
- lappend newrevs $rev
- incr npos
- }
- } else {
- lappend $newrevs $rev
- }
- }
- if {$npos == 0} return
- set revs $newrevs
- set vposids($view) [lsort -unique [concat $oldpos $vposids($view)]]
- }
- set args [concat $vflags($view) $revs --not $oldpos]
+ set oldpos $vposids($view)
+ set oldneg $vnegids($view)
+ set revs [parseviewrevs $view $vrevs($view)]
+ if {$revs eq {}} {
+ return
+ }
+ # note: getting the delta when negative refs change is hard,
+ # and could require multiple git log invocations, so in that
+ # case we ask git log for all the commits (not just the delta)
+ if {$oldneg eq $vnegids($view)} {
+ set newrevs {}
+ set npos 0
+ # take out positive refs that we asked for before or
+ # that we have already seen
+ foreach rev $revs {
+ if {[string length $rev] == 40} {
+ if {[lsearch -exact $oldpos $rev] < 0
+ && ![info exists varcid($view,$rev)]} {
+ lappend newrevs $rev
+ incr npos
+ }
+ } else {
+ lappend $newrevs $rev
+ }
+ }
+ if {$npos == 0} return
+ set revs $newrevs
+ set vposids($view) [lsort -unique [concat $oldpos $vposids($view)]]
+ }
+ set args [concat $vflags($view) $revs --not $oldpos]
} else {
- set args $vorigargs($view)
+ set args $vorigargs($view)
}
if {[catch {
- set fd [open [concat | git log --no-color -z --pretty=raw $show_notes \
- --parents --boundary $args "--" $vfilelimit($view)] r]
+ set fd [open [concat | git log --no-color -z --pretty=raw $show_notes \
+ --parents --boundary $args "--" $vfilelimit($view)] r]
} err]} {
- error_popup "[mc "Error executing git log:"] $err"
- return
+ error_popup "[mc "Error executing git log:"] $err"
+ return
}
if {$viewactive($view) == 0} {
- set startmsecs [clock clicks -milliseconds]
+ set startmsecs [clock clicks -milliseconds]
}
set i [reg_instance $fd]
lappend viewinstances($view) $i
fconfigure $fd -blocking 0 -translation lf -eofchar {}
if {$tclencoding != {}} {
- fconfigure $fd -encoding $tclencoding
+ fconfigure $fd -encoding $tclencoding
}
filerun $fd [list getcommitlines $fd $i $view 1]
incr viewactive($view)
@@ -581,7 +580,7 @@ proc updatecommits {} {
reset_pending_select {}
nowbusy $view [mc "Reading"]
if {$showneartags} {
- getallcommits
+ getallcommits
}
}
@@ -592,11 +591,11 @@ proc reloadcommits {} {
set selid {}
if {$selectedline ne {}} {
- set selid $currentid
+ set selid $currentid
}
if {!$viewcomplete($curview)} {
- stop_rev_list $curview
+ stop_rev_list $curview
}
resetvarcs $curview
set selectedline {}
@@ -606,7 +605,7 @@ proc reloadcommits {} {
readrefs
changedrefs
if {$showneartags} {
- getallcommits
+ getallcommits
}
clear_display
unset -nocomplain commitinfo
@@ -622,11 +621,11 @@ proc reloadcommits {} {
# sorts as a string in numerical order
proc strrep {n} {
if {$n < 16} {
- return [format "%x" $n]
+ return [format "%x" $n]
} elseif {$n < 256} {
- return [format "x%.2x" $n]
+ return [format "x%.2x" $n]
} elseif {$n < 65536} {
- return [format "y%.4x" $n]
+ return [format "y%.4x" $n]
}
return [format "z%.8x" $n]
}
@@ -657,22 +656,22 @@ proc resetvarcs {view} {
global vshortids
foreach vid [array names varcid $view,*] {
- unset varcid($vid)
- unset children($vid)
- unset parents($vid)
+ unset varcid($vid)
+ unset children($vid)
+ unset parents($vid)
}
foreach vid [array names vshortids $view,*] {
- unset vshortids($vid)
+ unset vshortids($vid)
}
# some commits might have children but haven't been seen yet
foreach vid [array names children $view,*] {
- unset children($vid)
+ unset children($vid)
}
foreach va [array names varccommits $view,*] {
- unset varccommits($va)
+ unset varccommits($va)
}
foreach vd [array names vseedcount $view,*] {
- unset vseedcount($vd)
+ unset vseedcount($vd)
}
unset -nocomplain ordertok
}
@@ -684,8 +683,8 @@ proc seeds {v} {
set ret {}
set a [lindex $vdownptr($v) 0]
while {$a != 0} {
- lappend ret [lindex $varcstart($v) $a]
- set a [lindex $vleftptr($v) $a]
+ lappend ret [lindex $varcstart($v) $a]
+ set a [lindex $vleftptr($v) $a]
}
return $ret
}
@@ -698,60 +697,60 @@ proc newvarc {view id} {
set a [llength $varctok($view)]
set vid $view,$id
if {[llength $children($vid)] == 0 || $vdatemode($view)} {
- if {![info exists commitinfo($id)]} {
- parsecommit $id $commitdata($id) 1
- }
- set cdate [lindex [lindex $commitinfo($id) 4] 0]
- if {![string is integer -strict $cdate]} {
- set cdate 0
- }
- if {![info exists vseedcount($view,$cdate)]} {
- set vseedcount($view,$cdate) -1
- }
- set c [incr vseedcount($view,$cdate)]
- set cdate [expr {$cdate ^ 0xffffffff}]
- set tok "s[strrep $cdate][strrep $c]"
+ if {![info exists commitinfo($id)]} {
+ parsecommit $id $commitdata($id) 1
+ }
+ set cdate [lindex [lindex $commitinfo($id) 4] 0]
+ if {![string is integer -strict $cdate]} {
+ set cdate 0
+ }
+ if {![info exists vseedcount($view,$cdate)]} {
+ set vseedcount($view,$cdate) -1
+ }
+ set c [incr vseedcount($view,$cdate)]
+ set cdate [expr {$cdate ^ 0xffffffff}]
+ set tok "s[strrep $cdate][strrep $c]"
} else {
- set tok {}
+ set tok {}
}
set ka 0
if {[llength $children($vid)] > 0} {
- set kid [lindex $children($vid) end]
- set k $varcid($view,$kid)
- if {[string compare [lindex $varctok($view) $k] $tok] > 0} {
- set ki $kid
- set ka $k
- set tok [lindex $varctok($view) $k]
- }
+ set kid [lindex $children($vid) end]
+ set k $varcid($view,$kid)
+ if {[string compare [lindex $varctok($view) $k] $tok] > 0} {
+ set ki $kid
+ set ka $k
+ set tok [lindex $varctok($view) $k]
+ }
}
if {$ka != 0} {
- set i [lsearch -exact $parents($view,$ki) $id]
- set j [expr {[llength $parents($view,$ki)] - 1 - $i}]
- append tok [strrep $j]
+ set i [lsearch -exact $parents($view,$ki) $id]
+ set j [expr {[llength $parents($view,$ki)] - 1 - $i}]
+ append tok [strrep $j]
}
set c [lindex $vlastins($view) $ka]
if {$c == 0 || [string compare $tok [lindex $varctok($view) $c]] < 0} {
- set c $ka
- set b [lindex $vdownptr($view) $ka]
+ set c $ka
+ set b [lindex $vdownptr($view) $ka]
} else {
- set b [lindex $vleftptr($view) $c]
+ set b [lindex $vleftptr($view) $c]
}
while {$b != 0 && [string compare $tok [lindex $varctok($view) $b]] >= 0} {
- set c $b
- set b [lindex $vleftptr($view) $c]
+ set c $b
+ set b [lindex $vleftptr($view) $c]
}
if {$c == $ka} {
- lset vdownptr($view) $ka $a
- lappend vbackptr($view) 0
+ lset vdownptr($view) $ka $a
+ lappend vbackptr($view) 0
} else {
- lset vleftptr($view) $c $a
- lappend vbackptr($view) $c
+ lset vleftptr($view) $c $a
+ lappend vbackptr($view) $c
}
lset vlastins($view) $ka $a
lappend vupptr($view) $ka
lappend vleftptr($view) $b
if {$b != 0} {
- lset vbackptr($view) $b $a
+ lset vbackptr($view) $b $a
}
lappend varctok($view) $tok
lappend varcstart($view) $id
@@ -782,7 +781,7 @@ proc splitvarc {p v} {
set varccommits($v,$na) [lrange $ac $i end]
lappend varcstart($v) $p
foreach id $varccommits($v,$na) {
- set varcid($v,$id) $na
+ set varcid($v,$id) $na
}
lappend vdownptr($v) [lindex $vdownptr($v) $oa]
lappend vlastins($v) [lindex $vlastins($v) $oa]
@@ -792,10 +791,10 @@ proc splitvarc {p v} {
lappend vleftptr($v) 0
lappend vbackptr($v) 0
for {set b [lindex $vdownptr($v) $na]} {$b != 0} {set b [lindex $vleftptr($v) $b]} {
- lset vupptr($v) $b $na
+ lset vupptr($v) $b $na
}
if {[string compare $otok $vtokmod($v)] <= 0} {
- modify_arc $v $oa
+ modify_arc $v $oa
}
}
@@ -809,120 +808,120 @@ proc renumbervarc {a v} {
set kidchanged($a) 1
set ntot 0
while {$a != 0} {
- if {[info exists isrelated($a)]} {
- lappend todo $a
- set id [lindex $varccommits($v,$a) end]
- foreach p $parents($v,$id) {
- if {[info exists varcid($v,$p)]} {
- set isrelated($varcid($v,$p)) 1
- }
- }
- }
- incr ntot
- set b [lindex $vdownptr($v) $a]
- if {$b == 0} {
- while {$a != 0} {
- set b [lindex $vleftptr($v) $a]
- if {$b != 0} break
- set a [lindex $vupptr($v) $a]
- }
- }
- set a $b
+ if {[info exists isrelated($a)]} {
+ lappend todo $a
+ set id [lindex $varccommits($v,$a) end]
+ foreach p $parents($v,$id) {
+ if {[info exists varcid($v,$p)]} {
+ set isrelated($varcid($v,$p)) 1
+ }
+ }
+ }
+ incr ntot
+ set b [lindex $vdownptr($v) $a]
+ if {$b == 0} {
+ while {$a != 0} {
+ set b [lindex $vleftptr($v) $a]
+ if {$b != 0} break
+ set a [lindex $vupptr($v) $a]
+ }
+ }
+ set a $b
}
foreach a $todo {
- if {![info exists kidchanged($a)]} continue
- set id [lindex $varcstart($v) $a]
- if {[llength $children($v,$id)] > 1} {
- set children($v,$id) [lsort -command [list vtokcmp $v] \
- $children($v,$id)]
- }
- set oldtok [lindex $varctok($v) $a]
- if {!$vdatemode($v)} {
- set tok {}
- } else {
- set tok $oldtok
- }
- set ka 0
- set kid [last_real_child $v,$id]
- if {$kid ne {}} {
- set k $varcid($v,$kid)
- if {[string compare [lindex $varctok($v) $k] $tok] > 0} {
- set ki $kid
- set ka $k
- set tok [lindex $varctok($v) $k]
- }
- }
- if {$ka != 0} {
- set i [lsearch -exact $parents($v,$ki) $id]
- set j [expr {[llength $parents($v,$ki)] - 1 - $i}]
- append tok [strrep $j]
- }
- if {$tok eq $oldtok} {
- continue
- }
- set id [lindex $varccommits($v,$a) end]
- foreach p $parents($v,$id) {
- if {[info exists varcid($v,$p)]} {
- set kidchanged($varcid($v,$p)) 1
- } else {
- set sortkids($p) 1
- }
- }
- lset varctok($v) $a $tok
- set b [lindex $vupptr($v) $a]
- if {$b != $ka} {
- if {[string compare [lindex $varctok($v) $ka] $vtokmod($v)] < 0} {
- modify_arc $v $ka
- }
- if {[string compare [lindex $varctok($v) $b] $vtokmod($v)] < 0} {
- modify_arc $v $b
- }
- set c [lindex $vbackptr($v) $a]
- set d [lindex $vleftptr($v) $a]
- if {$c == 0} {
- lset vdownptr($v) $b $d
- } else {
- lset vleftptr($v) $c $d
- }
- if {$d != 0} {
- lset vbackptr($v) $d $c
- }
- if {[lindex $vlastins($v) $b] == $a} {
- lset vlastins($v) $b $c
- }
- lset vupptr($v) $a $ka
- set c [lindex $vlastins($v) $ka]
- if {$c == 0 || \
- [string compare $tok [lindex $varctok($v) $c]] < 0} {
- set c $ka
- set b [lindex $vdownptr($v) $ka]
- } else {
- set b [lindex $vleftptr($v) $c]
- }
- while {$b != 0 && \
- [string compare $tok [lindex $varctok($v) $b]] >= 0} {
- set c $b
- set b [lindex $vleftptr($v) $c]
- }
- if {$c == $ka} {
- lset vdownptr($v) $ka $a
- lset vbackptr($v) $a 0
- } else {
- lset vleftptr($v) $c $a
- lset vbackptr($v) $a $c
- }
- lset vleftptr($v) $a $b
- if {$b != 0} {
- lset vbackptr($v) $b $a
- }
- lset vlastins($v) $ka $a
- }
+ if {![info exists kidchanged($a)]} continue
+ set id [lindex $varcstart($v) $a]
+ if {[llength $children($v,$id)] > 1} {
+ set children($v,$id) [lsort -command [list vtokcmp $v] \
+ $children($v,$id)]
+ }
+ set oldtok [lindex $varctok($v) $a]
+ if {!$vdatemode($v)} {
+ set tok {}
+ } else {
+ set tok $oldtok
+ }
+ set ka 0
+ set kid [last_real_child $v,$id]
+ if {$kid ne {}} {
+ set k $varcid($v,$kid)
+ if {[string compare [lindex $varctok($v) $k] $tok] > 0} {
+ set ki $kid
+ set ka $k
+ set tok [lindex $varctok($v) $k]
+ }
+ }
+ if {$ka != 0} {
+ set i [lsearch -exact $parents($v,$ki) $id]
+ set j [expr {[llength $parents($v,$ki)] - 1 - $i}]
+ append tok [strrep $j]
+ }
+ if {$tok eq $oldtok} {
+ continue
+ }
+ set id [lindex $varccommits($v,$a) end]
+ foreach p $parents($v,$id) {
+ if {[info exists varcid($v,$p)]} {
+ set kidchanged($varcid($v,$p)) 1
+ } else {
+ set sortkids($p) 1
+ }
+ }
+ lset varctok($v) $a $tok
+ set b [lindex $vupptr($v) $a]
+ if {$b != $ka} {
+ if {[string compare [lindex $varctok($v) $ka] $vtokmod($v)] < 0} {
+ modify_arc $v $ka
+ }
+ if {[string compare [lindex $varctok($v) $b] $vtokmod($v)] < 0} {
+ modify_arc $v $b
+ }
+ set c [lindex $vbackptr($v) $a]
+ set d [lindex $vleftptr($v) $a]
+ if {$c == 0} {
+ lset vdownptr($v) $b $d
+ } else {
+ lset vleftptr($v) $c $d
+ }
+ if {$d != 0} {
+ lset vbackptr($v) $d $c
+ }
+ if {[lindex $vlastins($v) $b] == $a} {
+ lset vlastins($v) $b $c
+ }
+ lset vupptr($v) $a $ka
+ set c [lindex $vlastins($v) $ka]
+ if {$c == 0 || \
+ [string compare $tok [lindex $varctok($v) $c]] < 0} {
+ set c $ka
+ set b [lindex $vdownptr($v) $ka]
+ } else {
+ set b [lindex $vleftptr($v) $c]
+ }
+ while {$b != 0 && \
+ [string compare $tok [lindex $varctok($v) $b]] >= 0} {
+ set c $b
+ set b [lindex $vleftptr($v) $c]
+ }
+ if {$c == $ka} {
+ lset vdownptr($v) $ka $a
+ lset vbackptr($v) $a 0
+ } else {
+ lset vleftptr($v) $c $a
+ lset vbackptr($v) $a $c
+ }
+ lset vleftptr($v) $a $b
+ if {$b != 0} {
+ lset vbackptr($v) $b $a
+ }
+ lset vlastins($v) $ka $a
+ }
}
foreach id [array names sortkids] {
- if {[llength $children($v,$id)] > 1} {
- set children($v,$id) [lsort -command [list vtokcmp $v] \
- $children($v,$id)]
- }
+ if {[llength $children($v,$id)] > 1} {
+ set children($v,$id) [lsort -command [list vtokcmp $v] \
+ $children($v,$id)]
+ }
}
set t2 [clock clicks -milliseconds]
#puts "renumbervarc did [llength $todo] of $ntot arcs in [expr {$t2-$t1}]ms"
@@ -936,14 +935,14 @@ proc fix_reversal {p a v} {
set pa $varcid($v,$p)
if {$p ne [lindex $varcstart($v) $pa]} {
- splitvarc $p $v
- set pa $varcid($v,$p)
+ splitvarc $p $v
+ set pa $varcid($v,$p)
}
# seeds always need to be renumbered
if {[lindex $vupptr($v) $pa] == 0 ||
- [string compare [lindex $varctok($v) $a] \
- [lindex $varctok($v) $pa]] > 0} {
- renumbervarc $pa $v
+ [string compare [lindex $varctok($v) $a] \
+ [lindex $varctok($v) $pa]] > 0} {
+ renumbervarc $pa $v
}
}
@@ -961,24 +960,24 @@ proc insertrow {id p v} {
set varcid($vid) $a
lappend vshortids($v,[string range $id 0 3]) $id
if {[string compare [lindex $varctok($v) $a] $vtokmod($v)] < 0} {
- modify_arc $v $a
+ modify_arc $v $a
}
lappend varccommits($v,$a) $id
set vp $v,$p
if {[llength [lappend children($vp) $id]] > 1} {
- set children($vp) [lsort -command [list vtokcmp $v] $children($vp)]
- unset -nocomplain ordertok
+ set children($vp) [lsort -command [list vtokcmp $v] $children($vp)]
+ unset -nocomplain ordertok
}
fix_reversal $p $a $v
incr commitidx($v)
if {$v == $curview} {
- set numcommits $commitidx($v)
- setcanvscroll
- if {[info exists targetid]} {
- if {![comes_before $targetid $p]} {
- incr targetrow
- }
- }
+ set numcommits $commitidx($v)
+ setcanvscroll
+ if {[info exists targetid]} {
+ if {![comes_before $targetid $p]} {
+ incr targetrow
+ }
+ }
}
}
@@ -990,8 +989,8 @@ proc insertfakerow {id p} {
set a $varcid($v,$p)
set i [lsearch -exact $varccommits($v,$a) $p]
if {$i < 0} {
- puts "oops: insertfakerow can't find [shortids $p] on arc $a"
- return
+ puts "oops: insertfakerow can't find [shortids $p] on arc $a"
+ return
}
set children($v,$id) {}
set parents($v,$id) [list $p]
@@ -1003,9 +1002,9 @@ proc insertfakerow {id p} {
set varccommits($v,$a) [linsert $varccommits($v,$a) $i $id]
modify_arc $v $a $i
if {[info exists targetid]} {
- if {![comes_before $targetid $p]} {
- incr targetrow
- }
+ if {![comes_before $targetid $p]} {
+ incr targetrow
+ }
}
setcanvscroll
drawvisible
@@ -1018,15 +1017,15 @@ proc removefakerow {id} {
set v $curview
if {[llength $parents($v,$id)] != 1} {
- puts "oops: removefakerow [shortids $id] has [llength $parents($v,$id)] parents"
- return
+ puts "oops: removefakerow [shortids $id] has [llength $parents($v,$id)] parents"
+ return
}
set p [lindex $parents($v,$id) 0]
set a $varcid($v,$id)
set i [lsearch -exact $varccommits($v,$a) $id]
if {$i < 0} {
- puts "oops: removefakerow can't find [shortids $id] on arc $a"
- return
+ puts "oops: removefakerow can't find [shortids $id] on arc $a"
+ return
}
unset varcid($v,$id)
set varccommits($v,$a) [lreplace $varccommits($v,$a) $i $i]
@@ -1036,15 +1035,15 @@ proc removefakerow {id} {
set numcommits [incr commitidx($v) -1]
set j [lsearch -exact $children($v,$p) $id]
if {$j >= 0} {
- set children($v,$p) [lreplace $children($v,$p) $j $j]
+ set children($v,$p) [lreplace $children($v,$p) $j $j]
}
modify_arc $v $a $i
if {[info exist currentid] && $id eq $currentid} {
- unset currentid
- set selectedline {}
+ unset currentid
+ set selectedline {}
}
if {[info exists targetid] && $targetid eq $id} {
- set targetid $p
+ set targetid $p
}
setcanvscroll
drawvisible
@@ -1055,9 +1054,9 @@ proc real_children {vp} {
set kids {}
foreach id $children($vp) {
- if {$id ne $nullid && $id ne $nullid2} {
- lappend kids $id
- }
+ if {$id ne $nullid && $id ne $nullid2} {
+ lappend kids $id
+ }
}
return $kids
}
@@ -1066,9 +1065,9 @@ proc first_real_child {vp} {
global children nullid nullid2
foreach id $children($vp) {
- if {$id ne $nullid && $id ne $nullid2} {
- return $id
- }
+ if {$id ne $nullid && $id ne $nullid2} {
+ return $id
+ }
}
return {}
}
@@ -1078,10 +1077,10 @@ proc last_real_child {vp} {
set kids $children($vp)
for {set i [llength $kids]} {[incr i -1] >= 0} {} {
- set id [lindex $kids $i]
- if {$id ne $nullid && $id ne $nullid2} {
- return $id
- }
+ set id [lindex $kids $i]
+ if {$id ne $nullid && $id ne $nullid2} {
+ return $id
+ }
}
return {}
}
@@ -1090,7 +1089,7 @@ proc vtokcmp {v a b} {
global varctok varcid
return [string compare [lindex $varctok($v) $varcid($v,$a)] \
- [lindex $varctok($v) $varcid($v,$b)]]
+ [lindex $varctok($v) $varcid($v,$b)]]
}
# This assumes that if lim is not given, the caller has checked that
@@ -1099,29 +1098,29 @@ proc modify_arc {v a {lim {}}} {
global varctok vtokmod varcmod varcrow vupptr curview vrowmod varccommits
if {$lim ne {}} {
- set c [string compare [lindex $varctok($v) $a] $vtokmod($v)]
- if {$c > 0} return
- if {$c == 0} {
- set r [lindex $varcrow($v) $a]
- if {$r ne {} && $vrowmod($v) <= $r + $lim} return
- }
+ set c [string compare [lindex $varctok($v) $a] $vtokmod($v)]
+ if {$c > 0} return
+ if {$c == 0} {
+ set r [lindex $varcrow($v) $a]
+ if {$r ne {} && $vrowmod($v) <= $r + $lim} return
+ }
}
set vtokmod($v) [lindex $varctok($v) $a]
set varcmod($v) $a
if {$v == $curview} {
- while {$a != 0 && [lindex $varcrow($v) $a] eq {}} {
- set a [lindex $vupptr($v) $a]
- set lim {}
- }
- set r 0
- if {$a != 0} {
- if {$lim eq {}} {
- set lim [llength $varccommits($v,$a)]
- }
- set r [expr {[lindex $varcrow($v) $a] + $lim}]
- }
- set vrowmod($v) $r
- undolayout $r
+ while {$a != 0 && [lindex $varcrow($v) $a] eq {}} {
+ set a [lindex $vupptr($v) $a]
+ set lim {}
+ }
+ set r 0
+ if {$a != 0} {
+ if {$lim eq {}} {
+ set lim [llength $varccommits($v,$a)]
+ }
+ set r [expr {[lindex $varcrow($v) $a] + $lim}]
+ }
+ set vrowmod($v) $r
+ undolayout $r
}
}
@@ -1133,62 +1132,62 @@ proc update_arcrows {v} {
if {$vrowmod($v) == $commitidx($v)} return
if {$v == $curview} {
- if {[llength $displayorder] > $vrowmod($v)} {
- set displayorder [lrange $displayorder 0 [expr {$vrowmod($v) - 1}]]
- set parentlist [lrange $parentlist 0 [expr {$vrowmod($v) - 1}]]
- }
- unset -nocomplain cached_commitrow
+ if {[llength $displayorder] > $vrowmod($v)} {
+ set displayorder [lrange $displayorder 0 [expr {$vrowmod($v) - 1}]]
+ set parentlist [lrange $parentlist 0 [expr {$vrowmod($v) - 1}]]
+ }
+ unset -nocomplain cached_commitrow
}
set narctot [expr {[llength $varctok($v)] - 1}]
set a $varcmod($v)
while {$a != 0 && [lindex $varcix($v) $a] eq {}} {
- # go up the tree until we find something that has a row number,
- # or we get to a seed
- set a [lindex $vupptr($v) $a]
+ # go up the tree until we find something that has a row number,
+ # or we get to a seed
+ set a [lindex $vupptr($v) $a]
}
if {$a == 0} {
- set a [lindex $vdownptr($v) 0]
- if {$a == 0} return
- set vrownum($v) {0}
- set varcorder($v) [list $a]
- lset varcix($v) $a 0
- lset varcrow($v) $a 0
- set arcn 0
- set row 0
+ set a [lindex $vdownptr($v) 0]
+ if {$a == 0} return
+ set vrownum($v) {0}
+ set varcorder($v) [list $a]
+ lset varcix($v) $a 0
+ lset varcrow($v) $a 0
+ set arcn 0
+ set row 0
} else {
- set arcn [lindex $varcix($v) $a]
- if {[llength $vrownum($v)] > $arcn + 1} {
- set vrownum($v) [lrange $vrownum($v) 0 $arcn]
- set varcorder($v) [lrange $varcorder($v) 0 $arcn]
- }
- set row [lindex $varcrow($v) $a]
+ set arcn [lindex $varcix($v) $a]
+ if {[llength $vrownum($v)] > $arcn + 1} {
+ set vrownum($v) [lrange $vrownum($v) 0 $arcn]
+ set varcorder($v) [lrange $varcorder($v) 0 $arcn]
+ }
+ set row [lindex $varcrow($v) $a]
}
while {1} {
- set p $a
- incr row [llength $varccommits($v,$a)]
- # go down if possible
- set b [lindex $vdownptr($v) $a]
- if {$b == 0} {
- # if not, go left, or go up until we can go left
- while {$a != 0} {
- set b [lindex $vleftptr($v) $a]
- if {$b != 0} break
- set a [lindex $vupptr($v) $a]
- }
- if {$a == 0} break
- }
- set a $b
- incr arcn
- lappend vrownum($v) $row
- lappend varcorder($v) $a
- lset varcix($v) $a $arcn
- lset varcrow($v) $a $row
+ set p $a
+ incr row [llength $varccommits($v,$a)]
+ # go down if possible
+ set b [lindex $vdownptr($v) $a]
+ if {$b == 0} {
+ # if not, go left, or go up until we can go left
+ while {$a != 0} {
+ set b [lindex $vleftptr($v) $a]
+ if {$b != 0} break
+ set a [lindex $vupptr($v) $a]
+ }
+ if {$a == 0} break
+ }
+ set a $b
+ incr arcn
+ lappend vrownum($v) $row
+ lappend varcorder($v) $a
+ lset varcix($v) $a $arcn
+ lset varcrow($v) $a $row
}
set vtokmod($v) [lindex $varctok($v) $p]
set varcmod($v) $p
set vrowmod($v) $row
if {[info exists currentid]} {
- set selectedline [rowofcommit $currentid]
+ set selectedline [rowofcommit $currentid]
}
}
@@ -1206,20 +1205,20 @@ proc rowofcommit {id} {
set v $curview
if {![info exists varcid($v,$id)]} {
- puts "oops rowofcommit no arc for [shortids $id]"
- return {}
+ puts "oops rowofcommit no arc for [shortids $id]"
+ return {}
}
set a $varcid($v,$id)
if {[string compare [lindex $varctok($v) $a] $vtokmod($v)] >= 0} {
- update_arcrows $v
+ update_arcrows $v
}
if {[info exists cached_commitrow($id)]} {
- return $cached_commitrow($id)
+ return $cached_commitrow($id)
}
set i [lsearch -exact $varccommits($v,$a) $id]
if {$i < 0} {
- puts "oops didn't find commit [shortids $id] in arc $a"
- return {}
+ puts "oops didn't find commit [shortids $id] in arc $a"
+ return {}
}
incr i [lindex $varcrow($v) $a]
set cached_commitrow($id) $i
@@ -1232,32 +1231,32 @@ proc comes_before {a b} {
set v $curview
if {$a eq $b || ![info exists varcid($v,$a)] || \
- ![info exists varcid($v,$b)]} {
- return 0
+ ![info exists varcid($v,$b)]} {
+ return 0
}
if {$varcid($v,$a) != $varcid($v,$b)} {
- return [expr {[string compare [lindex $varctok($v) $varcid($v,$a)] \
- [lindex $varctok($v) $varcid($v,$b)]] < 0}]
+ return [expr {[string compare [lindex $varctok($v) $varcid($v,$a)] \
+ [lindex $varctok($v) $varcid($v,$b)]] < 0}]
}
return [expr {[rowofcommit $a] < [rowofcommit $b]}]
}
proc bsearch {l elt} {
if {[llength $l] == 0 || $elt <= [lindex $l 0]} {
- return 0
+ return 0
}
set lo 0
set hi [llength $l]
while {$hi - $lo > 1} {
- set mid [expr {int(($lo + $hi) / 2)}]
- set t [lindex $l $mid]
- if {$elt < $t} {
- set hi $mid
- } elseif {$elt > $t} {
- set lo $mid
- } else {
- return $mid
- }
+ set mid [expr {int(($lo + $hi) / 2)}]
+ set t [lindex $l $mid]
+ if {$elt < $t} {
+ set hi $mid
+ } elseif {$elt > $t} {
+ set lo $mid
+ } else {
+ return $mid
+ }
}
return $lo
}
@@ -1269,37 +1268,37 @@ proc make_disporder {start end} {
global d_valid_start d_valid_end
if {$end > $vrowmod($curview)} {
- update_arcrows $curview
+ update_arcrows $curview
}
set ai [bsearch $vrownum($curview) $start]
set start [lindex $vrownum($curview) $ai]
set narc [llength $vrownum($curview)]
for {set r $start} {$ai < $narc && $r < $end} {incr ai} {
- set a [lindex $varcorder($curview) $ai]
- set l [llength $displayorder]
- set al [llength $varccommits($curview,$a)]
- if {$l < $r + $al} {
- if {$l < $r} {
- set pad [ntimes [expr {$r - $l}] {}]
- set displayorder [concat $displayorder $pad]
- set parentlist [concat $parentlist $pad]
- } elseif {$l > $r} {
- set displayorder [lrange $displayorder 0 [expr {$r - 1}]]
- set parentlist [lrange $parentlist 0 [expr {$r - 1}]]
- }
- foreach id $varccommits($curview,$a) {
- lappend displayorder $id
- lappend parentlist $parents($curview,$id)
- }
- } elseif {[lindex $displayorder [expr {$r + $al - 1}]] eq {}} {
- set i $r
- foreach id $varccommits($curview,$a) {
- lset displayorder $i $id
- lset parentlist $i $parents($curview,$id)
- incr i
- }
- }
- incr r $al
+ set a [lindex $varcorder($curview) $ai]
+ set l [llength $displayorder]
+ set al [llength $varccommits($curview,$a)]
+ if {$l < $r + $al} {
+ if {$l < $r} {
+ set pad [ntimes [expr {$r - $l}] {}]
+ set displayorder [concat $displayorder $pad]
+ set parentlist [concat $parentlist $pad]
+ } elseif {$l > $r} {
+ set displayorder [lrange $displayorder 0 [expr {$r - 1}]]
+ set parentlist [lrange $parentlist 0 [expr {$r - 1}]]
+ }
+ foreach id $varccommits($curview,$a) {
+ lappend displayorder $id
+ lappend parentlist $parents($curview,$id)
+ }
+ } elseif {[lindex $displayorder [expr {$r + $al - 1}]] eq {}} {
+ set i $r
+ foreach id $varccommits($curview,$a) {
+ lset displayorder $i $id
+ lset parentlist $i $parents($curview,$id)
+ incr i
+ }
+ }
+ incr r $al
}
}
@@ -1308,8 +1307,8 @@ proc commitonrow {row} {
set id [lindex $displayorder $row]
if {$id eq {}} {
- make_disporder $row [expr {$row + 1}]
- set id [lindex $displayorder $row]
+ make_disporder $row [expr {$row + 1}]
+ set id [lindex $displayorder $row]
}
return $id
}
@@ -1322,35 +1321,35 @@ proc closevarcs {v} {
set scripts {}
set narcs [llength $varctok($v)]
for {set a 1} {$a < $narcs} {incr a} {
- set id [lindex $varccommits($v,$a) end]
- foreach p $parents($v,$id) {
- if {[info exists varcid($v,$p)]} continue
- # add p as a new commit
- incr missing_parents
- set cmitlisted($v,$p) 0
- set parents($v,$p) {}
- if {[llength $children($v,$p)] == 1 &&
- [llength $parents($v,$id)] == 1} {
- set b $a
- } else {
- set b [newvarc $v $p]
- }
- set varcid($v,$p) $b
- if {[string compare [lindex $varctok($v) $b] $vtokmod($v)] < 0} {
- modify_arc $v $b
- }
- lappend varccommits($v,$b) $p
- incr commitidx($v)
- if {$v == $curview} {
- set numcommits $commitidx($v)
- }
- set scripts [check_interest $p $scripts]
- }
+ set id [lindex $varccommits($v,$a) end]
+ foreach p $parents($v,$id) {
+ if {[info exists varcid($v,$p)]} continue
+ # add p as a new commit
+ incr missing_parents
+ set cmitlisted($v,$p) 0
+ set parents($v,$p) {}
+ if {[llength $children($v,$p)] == 1 &&
+ [llength $parents($v,$id)] == 1} {
+ set b $a
+ } else {
+ set b [newvarc $v $p]
+ }
+ set varcid($v,$p) $b
+ if {[string compare [lindex $varctok($v) $b] $vtokmod($v)] < 0} {
+ modify_arc $v $b
+ }
+ lappend varccommits($v,$b) $p
+ incr commitidx($v)
+ if {$v == $curview} {
+ set numcommits $commitidx($v)
+ }
+ set scripts [check_interest $p $scripts]
+ }
}
if {$missing_parents > 0} {
- foreach s $scripts {
- eval $s
- }
+ foreach s $scripts {
+ eval $s
+ }
}
}
@@ -1360,23 +1359,23 @@ proc rewrite_commit {v id rwid} {
global children parents varcid varctok vtokmod varccommits
foreach ch $children($v,$id) {
- # make $rwid be $ch's parent in place of $id
- set i [lsearch -exact $parents($v,$ch) $id]
- if {$i < 0} {
- puts "oops rewrite_commit didn't find $id in parent list for $ch"
- }
- set parents($v,$ch) [lreplace $parents($v,$ch) $i $i $rwid]
- # add $ch to $rwid's children and sort the list if necessary
- if {[llength [lappend children($v,$rwid) $ch]] > 1} {
- set children($v,$rwid) [lsort -command [list vtokcmp $v] \
- $children($v,$rwid)]
- }
- # fix the graph after joining $id to $rwid
- set a $varcid($v,$ch)
- fix_reversal $rwid $a $v
- # parentlist is wrong for the last element of arc $a
- # even if displayorder is right, hence the 3rd arg here
- modify_arc $v $a [expr {[llength $varccommits($v,$a)] - 1}]
+ # make $rwid be $ch's parent in place of $id
+ set i [lsearch -exact $parents($v,$ch) $id]
+ if {$i < 0} {
+ puts "oops rewrite_commit didn't find $id in parent list for $ch"
+ }
+ set parents($v,$ch) [lreplace $parents($v,$ch) $i $i $rwid]
+ # add $ch to $rwid's children and sort the list if necessary
+ if {[llength [lappend children($v,$rwid) $ch]] > 1} {
+ set children($v,$rwid) [lsort -command [list vtokcmp $v] \
+ $children($v,$rwid)]
+ }
+ # fix the graph after joining $id to $rwid
+ set a $varcid($v,$ch)
+ fix_reversal $rwid $a $v
+ # parentlist is wrong for the last element of arc $a
+ # even if displayorder is right, hence the 3rd arg here
+ modify_arc $v $a [expr {[llength $varccommits($v,$a)] - 1}]
}
}
@@ -1396,19 +1395,19 @@ proc check_interest {id scripts} {
set prefix [string range $id 0 3]
if {[info exists commitinterest($prefix)]} {
- set newlist {}
- foreach {i script} $commitinterest($prefix) {
- if {[string match "$i*" $id]} {
- lappend scripts [string map [list "%I" $id "%P" $i] $script]
- } else {
- lappend newlist $i $script
- }
- }
- if {$newlist ne {}} {
- set commitinterest($prefix) $newlist
- } else {
- unset commitinterest($prefix)
- }
+ set newlist {}
+ foreach {i script} $commitinterest($prefix) {
+ if {[string match "$i*" $id]} {
+ lappend scripts [string map [list "%I" $id "%P" $i] $script]
+ } else {
+ lappend newlist $i $script
+ }
+ }
+ if {$newlist ne {}} {
+ set commitinterest($prefix) $newlist
+ } else {
+ unset commitinterest($prefix)
+ }
}
return $scripts
}
@@ -1423,192 +1422,192 @@ proc getcommitlines {fd inst view updating} {
set stuff [read $fd 500000]
# git log doesn't terminate the last commit with a null...
if {$stuff == {} && $leftover($inst) ne {} && [eof $fd]} {
- set stuff "\0"
+ set stuff "\0"
}
if {$stuff == {}} {
- if {![eof $fd]} {
- return 1
- }
- global commfd viewcomplete viewactive viewname
- global viewinstances
- unset commfd($inst)
- set i [lsearch -exact $viewinstances($view) $inst]
- if {$i >= 0} {
- set viewinstances($view) [lreplace $viewinstances($view) $i $i]
- }
- # set it blocking so we wait for the process to terminate
- fconfigure $fd -blocking 1
- if {[catch {close $fd} err]} {
- set fv {}
- if {$view != $curview} {
- set fv " for the \"$viewname($view)\" view"
- }
- if {[string range $err 0 4] == "usage"} {
- set err "Gitk: error reading commits$fv:\
- bad arguments to git log."
- if {$viewname($view) eq [mc "Command line"]} {
- append err \
- " (Note: arguments to gitk are passed to git log\
- to allow selection of commits to be displayed.)"
- }
- } else {
- set err "Error reading commits$fv: $err"
- }
- error_popup $err
- }
- if {[incr viewactive($view) -1] <= 0} {
- set viewcomplete($view) 1
- # Check if we have seen any ids listed as parents that haven't
- # appeared in the list
- closevarcs $view
- notbusy $view
- }
- if {$view == $curview} {
- run chewcommits
- }
- return 0
+ if {![eof $fd]} {
+ return 1
+ }
+ global commfd viewcomplete viewactive viewname
+ global viewinstances
+ unset commfd($inst)
+ set i [lsearch -exact $viewinstances($view) $inst]
+ if {$i >= 0} {
+ set viewinstances($view) [lreplace $viewinstances($view) $i $i]
+ }
+ # set it blocking so we wait for the process to terminate
+ fconfigure $fd -blocking 1
+ if {[catch {close $fd} err]} {
+ set fv {}
+ if {$view != $curview} {
+ set fv " for the \"$viewname($view)\" view"
+ }
+ if {[string range $err 0 4] == "usage"} {
+ set err "Gitk: error reading commits$fv:\
+ bad arguments to git log."
+ if {$viewname($view) eq [mc "Command line"]} {
+ append err \
+ " (Note: arguments to gitk are passed to git log\
+ to allow selection of commits to be displayed.)"
+ }
+ } else {
+ set err "Error reading commits$fv: $err"
+ }
+ error_popup $err
+ }
+ if {[incr viewactive($view) -1] <= 0} {
+ set viewcomplete($view) 1
+ # Check if we have seen any ids listed as parents that haven't
+ # appeared in the list
+ closevarcs $view
+ notbusy $view
+ }
+ if {$view == $curview} {
+ run chewcommits
+ }
+ return 0
}
set start 0
set gotsome 0
set scripts {}
while 1 {
- set i [string first "\0" $stuff $start]
- if {$i < 0} {
- append leftover($inst) [string range $stuff $start end]
- break
- }
- if {$start == 0} {
- set cmit $leftover($inst)
- append cmit [string range $stuff 0 [expr {$i - 1}]]
- set leftover($inst) {}
- } else {
- set cmit [string range $stuff $start [expr {$i - 1}]]
- }
- set start [expr {$i + 1}]
- set j [string first "\n" $cmit]
- set ok 0
- set listed 1
- if {$j >= 0 && [string match "commit *" $cmit]} {
- set ids [string range $cmit 7 [expr {$j - 1}]]
- if {[string match {[-^<>]*} $ids]} {
- switch -- [string index $ids 0] {
- "-" {set listed 0}
- "^" {set listed 2}
- "<" {set listed 3}
- ">" {set listed 4}
- }
- set ids [string range $ids 1 end]
- }
- set ok 1
- foreach id $ids {
- if {[string length $id] != 40} {
- set ok 0
- break
- }
- }
- }
- if {!$ok} {
- set shortcmit $cmit
- if {[string length $shortcmit] > 80} {
- set shortcmit "[string range $shortcmit 0 80]..."
- }
- error_popup "[mc "Can't parse git log output:"] {$shortcmit}"
- exit 1
- }
- set id [lindex $ids 0]
- set vid $view,$id
-
- lappend vshortids($view,[string range $id 0 3]) $id
-
- if {!$listed && $updating && ![info exists varcid($vid)] &&
- $vfilelimit($view) ne {}} {
- # git log doesn't rewrite parents for unlisted commits
- # when doing path limiting, so work around that here
- # by working out the rewritten parent with git rev-list
- # and if we already know about it, using the rewritten
- # parent as a substitute parent for $id's children.
- if {![catch {
- set rwid [exec git rev-list --first-parent --max-count=1 \
- $id -- $vfilelimit($view)]
- }]} {
- if {$rwid ne {} && [info exists varcid($view,$rwid)]} {
- # use $rwid in place of $id
- rewrite_commit $view $id $rwid
- continue
- }
- }
- }
-
- set a 0
- if {[info exists varcid($vid)]} {
- if {$cmitlisted($vid) || !$listed} continue
- set a $varcid($vid)
- }
- if {$listed} {
- set olds [lrange $ids 1 end]
- } else {
- set olds {}
- }
- set commitdata($id) [string range $cmit [expr {$j + 1}] end]
- set cmitlisted($vid) $listed
- set parents($vid) $olds
- if {![info exists children($vid)]} {
- set children($vid) {}
- } elseif {$a == 0 && [llength $children($vid)] == 1} {
- set k [lindex $children($vid) 0]
- if {[llength $parents($view,$k)] == 1 &&
- (!$vdatemode($view) ||
- $varcid($view,$k) == [llength $varctok($view)] - 1)} {
- set a $varcid($view,$k)
- }
- }
- if {$a == 0} {
- # new arc
- set a [newvarc $view $id]
- }
- if {[string compare [lindex $varctok($view) $a] $vtokmod($view)] < 0} {
- modify_arc $view $a
- }
- if {![info exists varcid($vid)]} {
- set varcid($vid) $a
- lappend varccommits($view,$a) $id
- incr commitidx($view)
- }
-
- set i 0
- foreach p $olds {
- if {$i == 0 || [lsearch -exact $olds $p] >= $i} {
- set vp $view,$p
- if {[llength [lappend children($vp) $id]] > 1 &&
- [vtokcmp $view [lindex $children($vp) end-1] $id] > 0} {
- set children($vp) [lsort -command [list vtokcmp $view] \
- $children($vp)]
- unset -nocomplain ordertok
- }
- if {[info exists varcid($view,$p)]} {
- fix_reversal $p $a $view
- }
- }
- incr i
- }
-
- set scripts [check_interest $id $scripts]
- set gotsome 1
+ set i [string first "\0" $stuff $start]
+ if {$i < 0} {
+ append leftover($inst) [string range $stuff $start end]
+ break
+ }
+ if {$start == 0} {
+ set cmit $leftover($inst)
+ append cmit [string range $stuff 0 [expr {$i - 1}]]
+ set leftover($inst) {}
+ } else {
+ set cmit [string range $stuff $start [expr {$i - 1}]]
+ }
+ set start [expr {$i + 1}]
+ set j [string first "\n" $cmit]
+ set ok 0
+ set listed 1
+ if {$j >= 0 && [string match "commit *" $cmit]} {
+ set ids [string range $cmit 7 [expr {$j - 1}]]
+ if {[string match {[-^<>]*} $ids]} {
+ switch -- [string index $ids 0] {
+ "-" {set listed 0}
+ "^" {set listed 2}
+ "<" {set listed 3}
+ ">" {set listed 4}
+ }
+ set ids [string range $ids 1 end]
+ }
+ set ok 1
+ foreach id $ids {
+ if {[string length $id] != 40} {
+ set ok 0
+ break
+ }
+ }
+ }
+ if {!$ok} {
+ set shortcmit $cmit
+ if {[string length $shortcmit] > 80} {
+ set shortcmit "[string range $shortcmit 0 80]..."
+ }
+ error_popup "[mc "Can't parse git log output:"] {$shortcmit}"
+ exit 1
+ }
+ set id [lindex $ids 0]
+ set vid $view,$id
+
+ lappend vshortids($view,[string range $id 0 3]) $id
+
+ if {!$listed && $updating && ![info exists varcid($vid)] &&
+ $vfilelimit($view) ne {}} {
+ # git log doesn't rewrite parents for unlisted commits
+ # when doing path limiting, so work around that here
+ # by working out the rewritten parent with git rev-list
+ # and if we already know about it, using the rewritten
+ # parent as a substitute parent for $id's children.
+ if {![catch {
+ set rwid [exec git rev-list --first-parent --max-count=1 \
+ $id -- $vfilelimit($view)]
+ }]} {
+ if {$rwid ne {} && [info exists varcid($view,$rwid)]} {
+ # use $rwid in place of $id
+ rewrite_commit $view $id $rwid
+ continue
+ }
+ }
+ }
+
+ set a 0
+ if {[info exists varcid($vid)]} {
+ if {$cmitlisted($vid) || !$listed} continue
+ set a $varcid($vid)
+ }
+ if {$listed} {
+ set olds [lrange $ids 1 end]
+ } else {
+ set olds {}
+ }
+ set commitdata($id) [string range $cmit [expr {$j + 1}] end]
+ set cmitlisted($vid) $listed
+ set parents($vid) $olds
+ if {![info exists children($vid)]} {
+ set children($vid) {}
+ } elseif {$a == 0 && [llength $children($vid)] == 1} {
+ set k [lindex $children($vid) 0]
+ if {[llength $parents($view,$k)] == 1 &&
+ (!$vdatemode($view) ||
+ $varcid($view,$k) == [llength $varctok($view)] - 1)} {
+ set a $varcid($view,$k)
+ }
+ }
+ if {$a == 0} {
+ # new arc
+ set a [newvarc $view $id]
+ }
+ if {[string compare [lindex $varctok($view) $a] $vtokmod($view)] < 0} {
+ modify_arc $view $a
+ }
+ if {![info exists varcid($vid)]} {
+ set varcid($vid) $a
+ lappend varccommits($view,$a) $id
+ incr commitidx($view)
+ }
+
+ set i 0
+ foreach p $olds {
+ if {$i == 0 || [lsearch -exact $olds $p] >= $i} {
+ set vp $view,$p
+ if {[llength [lappend children($vp) $id]] > 1 &&
+ [vtokcmp $view [lindex $children($vp) end-1] $id] > 0} {
+ set children($vp) [lsort -command [list vtokcmp $view] \
+ $children($vp)]
+ unset -nocomplain ordertok
+ }
+ if {[info exists varcid($view,$p)]} {
+ fix_reversal $p $a $view
+ }
+ }
+ incr i
+ }
+
+ set scripts [check_interest $id $scripts]
+ set gotsome 1
}
if {$gotsome} {
- global numcommits hlview
-
- if {$view == $curview} {
- set numcommits $commitidx($view)
- run chewcommits
- }
- if {[info exists hlview] && $view == $hlview} {
- # we never actually get here...
- run vhighlightmore
- }
- foreach s $scripts {
- eval $s
- }
+ global numcommits hlview
+
+ if {$view == $curview} {
+ set numcommits $commitidx($view)
+ run chewcommits
+ }
+ if {[info exists hlview] && $view == $hlview} {
+ # we never actually get here...
+ run vhighlightmore
+ }
+ foreach s $scripts {
+ eval $s
+ }
}
return 2
}
@@ -1619,28 +1618,28 @@ proc chewcommits {} {
layoutmore
if {$viewcomplete($curview)} {
- global commitidx varctok
- global numcommits startmsecs
-
- if {[info exists pending_select]} {
- update
- reset_pending_select {}
-
- if {[commitinview $pending_select $curview]} {
- selectline [rowofcommit $pending_select] 1
- } else {
- set row [first_real_row]
- selectline $row 1
- }
- }
- if {$commitidx($curview) > 0} {
- #set ms [expr {[clock clicks -milliseconds] - $startmsecs}]
- #puts "overall $ms ms for $numcommits commits"
- #puts "[llength $varctok($view)] arcs, $commitidx($view) commits"
- } else {
- show_status [mc "No commits selected"]
- }
- notbusy layout
+ global commitidx varctok
+ global numcommits startmsecs
+
+ if {[info exists pending_select]} {
+ update
+ reset_pending_select {}
+
+ if {[commitinview $pending_select $curview]} {
+ selectline [rowofcommit $pending_select] 1
+ } else {
+ set row [first_real_row]
+ selectline $row 1
+ }
+ }
+ if {$commitidx($curview) > 0} {
+ #set ms [expr {[clock clicks -milliseconds] - $startmsecs}]
+ #puts "overall $ms ms for $numcommits commits"
+ #puts "[llength $varctok($view)] arcs, $commitidx($view) commits"
+ } else {
+ show_status [mc "No commits selected"]
+ }
+ notbusy layout
}
return 0
}
@@ -1653,7 +1652,7 @@ proc do_readcommit {id} {
# Read the results using i18n.logoutputencoding
fconfigure $fd -translation lf -eofchar {}
if {$tclencoding != {}} {
- fconfigure $fd -encoding $tclencoding
+ fconfigure $fd -encoding $tclencoding
}
set contents [read $fd]
close $fd
@@ -1680,44 +1679,44 @@ proc parsecommit {id contents listed} {
set comdate {}
set hdrend [string first "\n\n" $contents]
if {$hdrend < 0} {
- # should never happen...
- set hdrend [string length $contents]
+ # should never happen...
+ set hdrend [string length $contents]
}
set header [string range $contents 0 [expr {$hdrend - 1}]]
set comment [string range $contents [expr {$hdrend + 2}] end]
foreach line [split $header "\n"] {
- set line [split $line " "]
- set tag [lindex $line 0]
- if {$tag == "author"} {
- set audate [lrange $line end-1 end]
- set auname [join [lrange $line 1 end-2] " "]
- } elseif {$tag == "committer"} {
- set comdate [lrange $line end-1 end]
- set comname [join [lrange $line 1 end-2] " "]
- }
+ set line [split $line " "]
+ set tag [lindex $line 0]
+ if {$tag == "author"} {
+ set audate [lrange $line end-1 end]
+ set auname [join [lrange $line 1 end-2] " "]
+ } elseif {$tag == "committer"} {
+ set comdate [lrange $line end-1 end]
+ set comname [join [lrange $line 1 end-2] " "]
+ }
}
set headline {}
# take the first non-blank line of the comment as the headline
set headline [string trimleft $comment]
set i [string first "\n" $headline]
if {$i >= 0} {
- set headline [string range $headline 0 $i]
+ set headline [string range $headline 0 $i]
}
set headline [string trimright $headline]
set i [string first "\r" $headline]
if {$i >= 0} {
- set headline [string trimright [string range $headline 0 $i]]
+ set headline [string trimright [string range $headline 0 $i]]
}
if {!$listed} {
- # git log indents the comment by 4 spaces;
- # if we got this via git cat-file, add the indentation
- set newcomment {}
- foreach line [split $comment "\n"] {
- append newcomment " "
- append newcomment $line
- append newcomment "\n"
- }
- set comment $newcomment
+ # git log indents the comment by 4 spaces;
+ # if we got this via git cat-file, add the indentation
+ set newcomment {}
+ foreach line [split $comment "\n"] {
+ append newcomment " "
+ append newcomment $line
+ append newcomment "\n"
+ }
+ set comment $newcomment
}
set hasnote [string first "\nNotes:\n" $contents]
set diff ""
@@ -1726,23 +1725,23 @@ proc parsecommit {id contents listed} {
# diff.
set i [string first "\n\ndiff" $comment]
if {$i >= 0} {
- set diff [string range $comment $i+1 end]
- set comment [string range $comment 0 $i-1]
+ set diff [string range $comment $i+1 end]
+ set comment [string range $comment 0 $i-1]
}
set commitinfo($id) [list $headline $auname $audate \
- $comname $comdate $comment $hasnote $diff]
+ $comname $comdate $comment $hasnote $diff]
}
proc getcommit {id} {
global commitdata commitinfo
if {[info exists commitdata($id)]} {
- parsecommit $id $commitdata($id) 1
+ parsecommit $id $commitdata($id) 1
} else {
- readcommit $id
- if {![info exists commitinfo($id)]} {
- set commitinfo($id) [list [mc "No commit information available"]]
- }
+ readcommit $id
+ if {![info exists commitinfo($id)]} {
+ set commitinfo($id) [list [mc "No commit information available"]]
+ }
}
return 1
}
@@ -1755,22 +1754,22 @@ proc longid {prefix} {
set ids {}
if {[string length $prefix] >= 4} {
- set vshortid $curview,[string range $prefix 0 3]
- if {[info exists vshortids($vshortid)]} {
- foreach id $vshortids($vshortid) {
- if {[string match "$prefix*" $id]} {
- if {[lsearch -exact $ids $id] < 0} {
- lappend ids $id
- if {[llength $ids] >= 2} break
- }
- }
- }
- }
+ set vshortid $curview,[string range $prefix 0 3]
+ if {[info exists vshortids($vshortid)]} {
+ foreach id $vshortids($vshortid) {
+ if {[string match "$prefix*" $id]} {
+ if {[lsearch -exact $ids $id] < 0} {
+ lappend ids $id
+ if {[llength $ids] >= 2} break
+ }
+ }
+ }
+ }
} else {
- foreach match [array names varcid "$curview,$prefix*"] {
- lappend ids [lindex [split $match ","] 1]
- if {[llength $ids] >= 2} break
- }
+ foreach match [array names varcid "$curview,$prefix*"] {
+ lappend ids [lindex [split $match ","] 1]
+ if {[llength $ids] >= 2} break
+ }
}
return $ids
}
@@ -1780,57 +1779,61 @@ proc readrefs {} {
global otherrefids idotherrefs mainhead mainheadid
global selecthead selectheadid
global hideremotes
+ global tclencoding
foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
- unset -nocomplain $v
+ unset -nocomplain $v
}
set refd [open [list | git show-ref -d] r]
+ if {$tclencoding != {}} {
+ fconfigure $refd -encoding $tclencoding
+ }
while {[gets $refd line] >= 0} {
- if {[string index $line 40] ne " "} continue
- set id [string range $line 0 39]
- set ref [string range $line 41 end]
- if {![string match "refs/*" $ref]} continue
- set name [string range $ref 5 end]
- if {[string match "remotes/*" $name]} {
- if {![string match "*/HEAD" $name] && !$hideremotes} {
- set headids($name) $id
- lappend idheads($id) $name
- }
- } elseif {[string match "heads/*" $name]} {
- set name [string range $name 6 end]
- set headids($name) $id
- lappend idheads($id) $name
- } elseif {[string match "tags/*" $name]} {
- # this lets refs/tags/foo^{} overwrite refs/tags/foo,
- # which is what we want since the former is the commit ID
- set name [string range $name 5 end]
- if {[string match "*^{}" $name]} {
- set name [string range $name 0 end-3]
- } else {
- set tagobjid($name) $id
- }
- set tagids($name) $id
- lappend idtags($id) $name
- } else {
- set otherrefids($name) $id
- lappend idotherrefs($id) $name
- }
+ if {[string index $line 40] ne " "} continue
+ set id [string range $line 0 39]
+ set ref [string range $line 41 end]
+ if {![string match "refs/*" $ref]} continue
+ set name [string range $ref 5 end]
+ if {[string match "remotes/*" $name]} {
+ if {![string match "*/HEAD" $name] && !$hideremotes} {
+ set headids($name) $id
+ lappend idheads($id) $name
+ }
+ } elseif {[string match "heads/*" $name]} {
+ set name [string range $name 6 end]
+ set headids($name) $id
+ lappend idheads($id) $name
+ } elseif {[string match "tags/*" $name]} {
+ # this lets refs/tags/foo^{} overwrite refs/tags/foo,
+ # which is what we want since the former is the commit ID
+ set name [string range $name 5 end]
+ if {[string match "*^{}" $name]} {
+ set name [string range $name 0 end-3]
+ } else {
+ set tagobjid($name) $id
+ }
+ set tagids($name) $id
+ lappend idtags($id) $name
+ } else {
+ set otherrefids($name) $id
+ lappend idotherrefs($id) $name
+ }
}
catch {close $refd}
set mainhead {}
set mainheadid {}
catch {
- set mainheadid [exec git rev-parse HEAD]
- set thehead [exec git symbolic-ref HEAD]
- if {[string match "refs/heads/*" $thehead]} {
- set mainhead [string range $thehead 11 end]
- }
+ set mainheadid [exec git rev-parse HEAD]
+ set thehead [exec git symbolic-ref HEAD]
+ if {[string match "refs/heads/*" $thehead]} {
+ set mainhead [string range $thehead 11 end]
+ }
}
set selectheadid {}
if {$selecthead ne {}} {
- catch {
- set selectheadid [exec git rev-parse --verify $selecthead]
- }
+ catch {
+ set selectheadid [exec git rev-parse --verify $selecthead]
+ }
}
}
@@ -1839,10 +1842,10 @@ proc first_real_row {} {
global nullid nullid2 numcommits
for {set row 0} {$row < $numcommits} {incr row} {
- set id [commitonrow $row]
- if {$id ne $nullid && $id ne $nullid2} {
- break
- }
+ set id [commitonrow $row]
+ if {$id ne $nullid && $id ne $nullid2} {
+ break
+ }
}
return $row
}
@@ -1861,12 +1864,12 @@ proc removehead {id name} {
global headids idheads
if {$idheads($id) eq $name} {
- unset idheads($id)
+ unset idheads($id)
} else {
- set i [lsearch -exact $idheads($id) $name]
- if {$i >= 0} {
- set idheads($id) [lreplace $idheads($id) $i $i]
- }
+ set i [lsearch -exact $idheads($id) $name]
+ if {$i >= 0} {
+ set idheads($id) [lreplace $idheads($id) $i $i]
+ }
}
unset headids($name)
}
@@ -1894,7 +1897,7 @@ proc make_transient {window origin} {
# Windows fails to place transient windows normally, so
# schedule a callback to center them on the parent.
if {[tk windowingsystem] eq {win32}} {
- after idle [list tk::PlaceWindow $window widget $origin]
+ after idle [list tk::PlaceWindow $window widget $origin]
}
}
@@ -1994,41 +1997,41 @@ proc setttkstyle {} {
proc makemenu {m items} {
menu $m
if {[tk windowingsystem] eq {aqua}} {
- set Meta1 Cmd
+ set Meta1 Cmd
} else {
- set Meta1 Ctrl
+ set Meta1 Ctrl
}
foreach i $items {
- set name [mc [lindex $i 1]]
- set type [lindex $i 2]
- set thing [lindex $i 3]
- set params [list $type]
- if {$name ne {}} {
- set u [string first "&" [string map {&& x} $name]]
- lappend params -label [string map {&& & & {}} $name]
- if {$u >= 0} {
- lappend params -underline $u
- }
- }
- switch -- $type {
- "cascade" {
- set submenu [string tolower [string map {& ""} [lindex $i 1]]]
- lappend params -menu $m.$submenu
- }
- "command" {
- lappend params -command $thing
- }
- "radiobutton" {
- lappend params -variable [lindex $thing 0] \
- -value [lindex $thing 1]
- }
- }
- set tail [lrange $i 4 end]
- regsub -all {\yMeta1\y} $tail $Meta1 tail
- eval $m add $params $tail
- if {$type eq "cascade"} {
- makemenu $m.$submenu $thing
- }
+ set name [mc [lindex $i 1]]
+ set type [lindex $i 2]
+ set thing [lindex $i 3]
+ set params [list $type]
+ if {$name ne {}} {
+ set u [string first "&" [string map {&& x} $name]]
+ lappend params -label [string map {&& & & {}} $name]
+ if {$u >= 0} {
+ lappend params -underline $u
+ }
+ }
+ switch -- $type {
+ "cascade" {
+ set submenu [string tolower [string map {& ""} [lindex $i 1]]]
+ lappend params -menu $m.$submenu
+ }
+ "command" {
+ lappend params -command $thing
+ }
+ "radiobutton" {
+ lappend params -variable [lindex $thing 0] \
+ -value [lindex $thing 1]
+ }
+ }
+ set tail [lrange $i 4 end]
+ regsub -all {\yMeta1\y} $tail $Meta1 tail
+ eval $m add $params $tail
+ if {$type eq "cascade"} {
+ makemenu $m.$submenu $thing
+ }
}
}
@@ -2048,12 +2051,12 @@ proc makedroplist {w varname args} {
set cx [string length $label]
if {$cx > $width} {set width $cx}
}
- set gm [ttk::combobox $w -width $width -state readonly\
- -textvariable $varname -values $args \
- -exportselection false]
- bind $gm <<ComboboxSelected>> [list $gm selection clear]
+ set gm [ttk::combobox $w -width $width -state readonly\
+ -textvariable $varname -values $args \
+ -exportselection false]
+ bind $gm <<ComboboxSelected>> [list $gm selection clear]
} else {
- set gm [eval [linsert $args 0 tk_optionMenu $w $varname]]
+ set gm [eval [linsert $args 0 tk_optionMenu $w $varname]]
}
return $gm
}
@@ -2069,7 +2072,7 @@ proc makewindow {} {
global rowctxmenu fakerowmenu mergemax wrapcomment
global highlight_files gdttype
global searchstring sstring
- global bgcolor fgcolor bglist fglist diffcolors selectbgcolor
+ global bgcolor fgcolor bglist fglist diffcolors diffbgcolors selectbgcolor
global uifgcolor uifgdisabledcolor
global filesepbgcolor filesepfgcolor
global mergecolors foundbgcolor currentsearchhitbgcolor
@@ -2083,49 +2086,49 @@ proc makewindow {} {
# The "mc" arguments here are purely so that xgettext
# sees the following string as needing to be translated
set file {
- mc "&File" cascade {
- {mc "&Update" command updatecommits -accelerator F5}
- {mc "&Reload" command reloadcommits -accelerator Shift-F5}
- {mc "Reread re&ferences" command rereadrefs}
- {mc "&List references" command showrefs -accelerator F2}
- {xx "" separator}
- {mc "Start git &gui" command {exec git gui &}}
- {xx "" separator}
- {mc "&Quit" command doquit -accelerator Meta1-Q}
- }}
+ mc "&File" cascade {
+ {mc "&Update" command updatecommits -accelerator F5}
+ {mc "&Reload" command reloadcommits -accelerator Shift-F5}
+ {mc "Reread re&ferences" command rereadrefs}
+ {mc "&List references" command showrefs -accelerator F2}
+ {xx "" separator}
+ {mc "Start git &gui" command {exec git gui &}}
+ {xx "" separator}
+ {mc "&Quit" command doquit -accelerator Meta1-Q}
+ }}
set edit {
- mc "&Edit" cascade {
- {mc "&Preferences" command doprefs}
- }}
+ mc "&Edit" cascade {
+ {mc "&Preferences" command doprefs}
+ }}
set view {
- mc "&View" cascade {
- {mc "&New view..." command {newview 0} -accelerator Shift-F4}
- {mc "&Edit view..." command editview -state disabled -accelerator F4}
- {mc "&Delete view" command delview -state disabled}
- {xx "" separator}
- {mc "&All files" radiobutton {selectedview 0} -command {showview 0}}
- }}
+ mc "&View" cascade {
+ {mc "&New view..." command {newview 0} -accelerator Shift-F4}
+ {mc "&Edit view..." command editview -state disabled -accelerator F4}
+ {mc "&Delete view" command delview -state disabled}
+ {xx "" separator}
+ {mc "&All files" radiobutton {selectedview 0} -command {showview 0}}
+ }}
if {[tk windowingsystem] ne "aqua"} {
- set help {
- mc "&Help" cascade {
- {mc "&About gitk" command about}
- {mc "&Key bindings" command keys}
- }}
- set bar [list $file $edit $view $help]
+ set help {
+ mc "&Help" cascade {
+ {mc "&About gitk" command about}
+ {mc "&Key bindings" command keys}
+ }}
+ set bar [list $file $edit $view $help]
} else {
- proc ::tk::mac::ShowPreferences {} {doprefs}
- proc ::tk::mac::Quit {} {doquit}
- lset file end [lreplace [lindex $file end] end-1 end]
- set apple {
- xx "&Apple" cascade {
- {mc "&About gitk" command about}
- {xx "" separator}
- }}
- set help {
- mc "&Help" cascade {
- {mc "&Key bindings" command keys}
- }}
- set bar [list $apple $file $view $help]
+ proc ::tk::mac::ShowPreferences {} {doprefs}
+ proc ::tk::mac::Quit {} {doquit}
+ lset file end [lreplace [lindex $file end] end-1 end]
+ set apple {
+ xx "&Apple" cascade {
+ {mc "&About gitk" command about}
+ {xx "" separator}
+ }}
+ set help {
+ mc "&Help" cascade {
+ {mc "&Key bindings" command keys}
+ }}
+ set bar [list $apple $file $view $help]
}
makemenu .bar $bar
. configure -menu .bar
@@ -2153,36 +2156,36 @@ proc makewindow {} {
${NS}::frame .tf.histframe
${NS}::panedwindow .tf.histframe.pwclist -orient horizontal
if {!$use_ttk} {
- .tf.histframe.pwclist configure -sashpad 0 -handlesize 4
+ .tf.histframe.pwclist configure -sashpad 0 -handlesize 4
}
# create three canvases
set cscroll .tf.histframe.csb
set canv .tf.histframe.pwclist.canv
canvas $canv \
- -selectbackground $selectbgcolor \
- -background $bgcolor -bd 0 \
- -yscrollincr $linespc -yscrollcommand "scrollcanv $cscroll"
+ -selectbackground $selectbgcolor \
+ -background $bgcolor -bd 0 \
+ -yscrollincr $linespc -yscrollcommand "scrollcanv $cscroll"
.tf.histframe.pwclist add $canv
set canv2 .tf.histframe.pwclist.canv2
canvas $canv2 \
- -selectbackground $selectbgcolor \
- -background $bgcolor -bd 0 -yscrollincr $linespc
+ -selectbackground $selectbgcolor \
+ -background $bgcolor -bd 0 -yscrollincr $linespc
.tf.histframe.pwclist add $canv2
set canv3 .tf.histframe.pwclist.canv3
canvas $canv3 \
- -selectbackground $selectbgcolor \
- -background $bgcolor -bd 0 -yscrollincr $linespc
+ -selectbackground $selectbgcolor \
+ -background $bgcolor -bd 0 -yscrollincr $linespc
.tf.histframe.pwclist add $canv3
if {$use_ttk} {
- bind .tf.histframe.pwclist <Map> {
- bind %W <Map> {}
- .tf.histframe.pwclist sashpos 1 [lindex $::geometry(pwsash1) 0]
- .tf.histframe.pwclist sashpos 0 [lindex $::geometry(pwsash0) 0]
- }
+ bind .tf.histframe.pwclist <Map> {
+ bind %W <Map> {}
+ .tf.histframe.pwclist sashpos 1 [lindex $::geometry(pwsash1) 0]
+ .tf.histframe.pwclist sashpos 0 [lindex $::geometry(pwsash0) 0]
+ }
} else {
- eval .tf.histframe.pwclist sash place 0 $geometry(pwsash0)
- eval .tf.histframe.pwclist sash place 1 $geometry(pwsash1)
+ eval .tf.histframe.pwclist sash place 0 $geometry(pwsash0)
+ eval .tf.histframe.pwclist sash place 1 $geometry(pwsash1)
}
# a scroll bar to rule them
@@ -2201,7 +2204,7 @@ proc makewindow {} {
set entries $sha1entry
set sha1but .tf.bar.sha1label
button $sha1but -text "[mc "SHA1 ID:"] " -state disabled -relief flat \
- -command gotocommit -width 8
+ -command gotocommit -width 8
$sha1but conf -disabledforeground [$sha1but cget -foreground]
pack .tf.bar.sha1label -side left
${NS}::entry $sha1entry -width 40 -font textfont -textvariable sha1string
@@ -2209,20 +2212,20 @@ proc makewindow {} {
pack $sha1entry -side left -pady 2
set bm_left_data {
- #define left_width 16
- #define left_height 16
- static unsigned char left_bits[] = {
- 0x00, 0x00, 0xc0, 0x01, 0xe0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1c, 0x00,
- 0x0e, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x0e, 0x00, 0x1c, 0x00,
- 0x38, 0x00, 0x70, 0x00, 0xe0, 0x00, 0xc0, 0x01};
+ #define left_width 16
+ #define left_height 16
+ static unsigned char left_bits[] = {
+ 0x00, 0x00, 0xc0, 0x01, 0xe0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1c, 0x00,
+ 0x0e, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x0e, 0x00, 0x1c, 0x00,
+ 0x38, 0x00, 0x70, 0x00, 0xe0, 0x00, 0xc0, 0x01};
}
set bm_right_data {
- #define right_width 16
- #define right_height 16
- static unsigned char right_bits[] = {
- 0x00, 0x00, 0xc0, 0x01, 0x80, 0x03, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x1c,
- 0x00, 0x38, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x38, 0x00, 0x1c,
- 0x00, 0x0e, 0x00, 0x07, 0x80, 0x03, 0xc0, 0x01};
+ #define right_width 16
+ #define right_height 16
+ static unsigned char right_bits[] = {
+ 0x00, 0x00, 0xc0, 0x01, 0x80, 0x03, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x1c,
+ 0x00, 0x38, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x38, 0x00, 0x1c,
+ 0x00, 0x0e, 0x00, 0x07, 0x80, 0x03, 0xc0, 0x01};
}
image create bitmap bm-left -data $bm_left_data -foreground $uifgcolor
image create bitmap bm-left-gray -data $bm_left_data -foreground $uifgdisabledcolor
@@ -2231,28 +2234,28 @@ proc makewindow {} {
${NS}::button .tf.bar.leftbut -command goback -state disabled -width 26
if {$use_ttk} {
- .tf.bar.leftbut configure -image [list bm-left disabled bm-left-gray]
+ .tf.bar.leftbut configure -image [list bm-left disabled bm-left-gray]
} else {
- .tf.bar.leftbut configure -image bm-left
+ .tf.bar.leftbut configure -image bm-left
}
pack .tf.bar.leftbut -side left -fill y
${NS}::button .tf.bar.rightbut -command goforw -state disabled -width 26
if {$use_ttk} {
- .tf.bar.rightbut configure -image [list bm-right disabled bm-right-gray]
+ .tf.bar.rightbut configure -image [list bm-right disabled bm-right-gray]
} else {
- .tf.bar.rightbut configure -image bm-right
+ .tf.bar.rightbut configure -image bm-right
}
pack .tf.bar.rightbut -side left -fill y
${NS}::label .tf.bar.rowlabel -text [mc "Row"]
set rownumsel {}
${NS}::label .tf.bar.rownum -width 7 -textvariable rownumsel \
- -relief sunken -anchor e
+ -relief sunken -anchor e
${NS}::label .tf.bar.rowlabel2 -text "/"
${NS}::label .tf.bar.numcommits -width 7 -textvariable numcommits \
- -relief sunken -anchor e
+ -relief sunken -anchor e
pack .tf.bar.rowlabel .tf.bar.rownum .tf.bar.rowlabel2 .tf.bar.numcommits \
- -side left
+ -side left
if {!$use_ttk} {
foreach w {rownum numcommits} {.tf.bar.$w configure -font textfont}
}
@@ -2264,14 +2267,14 @@ proc makewindow {} {
${NS}::label $statusw -width 15 -relief sunken
pack $statusw -side left -padx 5
if {$use_ttk} {
- set progresscanv [ttk::progressbar .tf.bar.progress]
+ set progresscanv [ttk::progressbar .tf.bar.progress]
} else {
- set h [expr {[font metrics uifont -linespace] + 2}]
- set progresscanv .tf.bar.progress
- canvas $progresscanv -relief sunken -height $h -borderwidth 2
- set progressitem [$progresscanv create rect -1 0 0 $h -fill "#00ff00"]
- set fprogitem [$progresscanv create rect -1 0 0 $h -fill yellow]
- set rprogitem [$progresscanv create rect -1 0 0 $h -fill red]
+ set h [expr {[font metrics uifont -linespace] + 2}]
+ set progresscanv .tf.bar.progress
+ canvas $progresscanv -relief sunken -height $h -borderwidth 2
+ set progressitem [$progresscanv create rect -1 0 0 $h -fill "#00ff00"]
+ set fprogitem [$progresscanv create rect -1 0 0 $h -fill yellow]
+ set rprogitem [$progresscanv create rect -1 0 0 $h -fill red]
}
pack $progresscanv -side right -expand 1 -fill x -padx {0 2}
set progresscoords {0 0}
@@ -2285,26 +2288,26 @@ proc makewindow {} {
${NS}::label .tf.lbar.flabel -text "[mc "Find"] "
set bm_down_data {
- #define down_width 16
- #define down_height 16
- static unsigned char down_bits[] = {
- 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
- 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
- 0x87, 0xe1, 0x8e, 0x71, 0x9c, 0x39, 0xb8, 0x1d,
- 0xf0, 0x0f, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01};
+ #define down_width 16
+ #define down_height 16
+ static unsigned char down_bits[] = {
+ 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
+ 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
+ 0x87, 0xe1, 0x8e, 0x71, 0x9c, 0x39, 0xb8, 0x1d,
+ 0xf0, 0x0f, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01};
}
image create bitmap bm-down -data $bm_down_data -foreground $uifgcolor
${NS}::button .tf.lbar.fnext -width 26 -command {dofind 1 1}
.tf.lbar.fnext configure -image bm-down
set bm_up_data {
- #define up_width 16
- #define up_height 16
- static unsigned char up_bits[] = {
- 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xf0, 0x0f,
- 0xb8, 0x1d, 0x9c, 0x39, 0x8e, 0x71, 0x87, 0xe1,
- 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
- 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01};
+ #define up_width 16
+ #define up_height 16
+ static unsigned char up_bits[] = {
+ 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xf0, 0x0f,
+ 0xb8, 0x1d, 0x9c, 0x39, 0x8e, 0x71, 0x87, 0xe1,
+ 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
+ 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01};
}
image create bitmap bm-up -data $bm_up_data -foreground $uifgcolor
${NS}::button .tf.lbar.fprev -width 26 -command {dofind -1 1}
@@ -2313,13 +2316,13 @@ proc makewindow {} {
${NS}::label .tf.lbar.flab2 -text " [mc "commit"] "
pack .tf.lbar.flabel .tf.lbar.fnext .tf.lbar.fprev .tf.lbar.flab2 \
- -side left -fill y
+ -side left -fill y
set gdttype [mc "containing:"]
set gm [makedroplist .tf.lbar.gdttype gdttype \
- [mc "containing:"] \
- [mc "touching paths:"] \
- [mc "adding/removing string:"] \
- [mc "changing lines matching:"]]
+ [mc "containing:"] \
+ [mc "touching paths:"] \
+ [mc "adding/removing string:"] \
+ [mc "changing lines matching:"]]
trace add variable gdttype write gdttype_change
pack .tf.lbar.gdttype -side left -fill y
@@ -2330,11 +2333,11 @@ proc makewindow {} {
trace add variable findstring write find_change
set findtype [mc "Exact"]
set findtypemenu [makedroplist .tf.lbar.findtype \
- findtype [mc "Exact"] [mc "IgnCase"] [mc "Regexp"]]
+ findtype [mc "Exact"] [mc "IgnCase"] [mc "Regexp"]]
trace add variable findtype write findcom_change
set findloc [mc "All fields"]
makedroplist .tf.lbar.findloc findloc [mc "All fields"] [mc "Headline"] \
- [mc "Comments"] [mc "Author"] [mc "Committer"]
+ [mc "Comments"] [mc "Author"] [mc "Committer"]
trace add variable findloc write find_change
pack .tf.lbar.findloc -side right
pack .tf.lbar.findtype -side right
@@ -2346,8 +2349,8 @@ proc makewindow {} {
pack .tf.histframe -fill both -side top -expand 1
.ctop add .tf
if {!$use_ttk} {
- .ctop paneconfigure .tf -height $geometry(topheight)
- .ctop paneconfigure .tf -width $geometry(topwidth)
+ .ctop paneconfigure .tf -height $geometry(topheight)
+ .ctop paneconfigure .tf -width $geometry(topwidth)
}
# now build up the bottom
@@ -2357,9 +2360,9 @@ proc makewindow {} {
# if we know window height, then that will set the lower text height, otherwise
# we set lower text height which will drive window height
if {[info exists geometry(main)]} {
- ${NS}::frame .bleft -width $geometry(botwidth)
+ ${NS}::frame .bleft -width $geometry(botwidth)
} else {
- ${NS}::frame .bleft -width $geometry(botwidth) -height $geometry(botheight)
+ ${NS}::frame .bleft -width $geometry(botwidth) -height $geometry(botheight)
}
${NS}::frame .bleft.top
${NS}::frame .bleft.mid
@@ -2377,41 +2380,41 @@ proc makewindow {} {
trace add variable searchstring write incrsearch
pack $sstring -side left -expand 1 -fill x
${NS}::radiobutton .bleft.mid.diff -text [mc "Diff"] \
- -command changediffdisp -variable diffelide -value {0 0}
+ -command changediffdisp -variable diffelide -value {0 0}
${NS}::radiobutton .bleft.mid.old -text [mc "Old version"] \
- -command changediffdisp -variable diffelide -value {0 1}
+ -command changediffdisp -variable diffelide -value {0 1}
${NS}::radiobutton .bleft.mid.new -text [mc "New version"] \
- -command changediffdisp -variable diffelide -value {1 0}
+ -command changediffdisp -variable diffelide -value {1 0}
${NS}::label .bleft.mid.labeldiffcontext -text " [mc "Lines of context"]: "
pack .bleft.mid.diff .bleft.mid.old .bleft.mid.new -side left -ipadx $wgap
spinbox .bleft.mid.diffcontext -width 5 \
- -from 0 -increment 1 -to 10000000 \
- -validate all -validatecommand "diffcontextvalidate %P" \
- -textvariable diffcontextstring
+ -from 0 -increment 1 -to 10000000 \
+ -validate all -validatecommand "diffcontextvalidate %P" \
+ -textvariable diffcontextstring
.bleft.mid.diffcontext set $diffcontext
trace add variable diffcontextstring write diffcontextchange
lappend entries .bleft.mid.diffcontext
pack .bleft.mid.labeldiffcontext .bleft.mid.diffcontext -side left -ipadx $wgap
${NS}::checkbutton .bleft.mid.ignspace -text [mc "Ignore space change"] \
- -command changeignorespace -variable ignorespace
+ -command changeignorespace -variable ignorespace
pack .bleft.mid.ignspace -side left -padx 5
set worddiff [mc "Line diff"]
if {[package vcompare $git_version "1.7.2"] >= 0} {
- makedroplist .bleft.mid.worddiff worddiff [mc "Line diff"] \
- [mc "Markup words"] [mc "Color words"]
- trace add variable worddiff write changeworddiff
- pack .bleft.mid.worddiff -side left -padx 5
+ makedroplist .bleft.mid.worddiff worddiff [mc "Line diff"] \
+ [mc "Markup words"] [mc "Color words"]
+ trace add variable worddiff write changeworddiff
+ pack .bleft.mid.worddiff -side left -padx 5
}
set ctext .bleft.bottom.ctext
text $ctext -background $bgcolor -foreground $fgcolor \
- -state disabled -undo 0 -font textfont \
- -yscrollcommand scrolltext -wrap none \
- -xscrollcommand ".bleft.bottom.sbhorizontal set"
+ -state disabled -undo 0 -font textfont \
+ -yscrollcommand scrolltext -wrap none \
+ -xscrollcommand ".bleft.bottom.sbhorizontal set"
if {$have_tk85} {
- $ctext conf -tabstyle wordprocessor
+ $ctext conf -tabstyle wordprocessor
}
${NS}::scrollbar .bleft.bottom.sb -command "$ctext yview"
${NS}::scrollbar .bleft.bottom.sbhorizontal -command "$ctext xview" -orient h
@@ -2430,7 +2433,9 @@ proc makewindow {} {
$ctext tag conf filesep -font textfontbold -fore $filesepfgcolor -back $filesepbgcolor
$ctext tag conf hunksep -fore [lindex $diffcolors 2]
$ctext tag conf d0 -fore [lindex $diffcolors 0]
+ $ctext tag conf d0 -back [lindex $diffbgcolors 0]
$ctext tag conf dresult -fore [lindex $diffcolors 1]
+ $ctext tag conf dresult -back [lindex $diffbgcolors 1]
$ctext tag conf m0 -fore [lindex $mergecolors 0]
$ctext tag conf m1 -fore [lindex $mergecolors 1]
$ctext tag conf m2 -fore [lindex $mergecolors 2]
@@ -2455,38 +2460,44 @@ proc makewindow {} {
$ctext tag conf currentsearchhit -back $currentsearchhitbgcolor
$ctext tag conf wwrap -wrap word -lmargin2 1c
$ctext tag conf bold -font textfontbold
+ # set these to the lowest priority:
+ $ctext tag lower currentsearchhit
+ $ctext tag lower found
+ $ctext tag lower filesep
+ $ctext tag lower dresult
+ $ctext tag lower d0
.pwbottom add .bleft
if {!$use_ttk} {
- .pwbottom paneconfigure .bleft -width $geometry(botwidth)
+ .pwbottom paneconfigure .bleft -width $geometry(botwidth)
}
# lower right
${NS}::frame .bright
${NS}::frame .bright.mode
${NS}::radiobutton .bright.mode.patch -text [mc "Patch"] \
- -command reselectline -variable cmitmode -value "patch"
+ -command reselectline -variable cmitmode -value "patch"
${NS}::radiobutton .bright.mode.tree -text [mc "Tree"] \
- -command reselectline -variable cmitmode -value "tree"
+ -command reselectline -variable cmitmode -value "tree"
grid .bright.mode.patch .bright.mode.tree -sticky ew
pack .bright.mode -side top -fill x
set cflist .bright.cfiles
set indent [font measure mainfont "nn"]
text $cflist \
- -selectbackground $selectbgcolor \
- -background $bgcolor -foreground $fgcolor \
- -font mainfont \
- -tabs [list $indent [expr {2 * $indent}]] \
- -yscrollcommand ".bright.sb set" \
- -cursor [. cget -cursor] \
- -spacing1 1 -spacing3 1
+ -selectbackground $selectbgcolor \
+ -background $bgcolor -foreground $fgcolor \
+ -font mainfont \
+ -tabs [list $indent [expr {2 * $indent}]] \
+ -yscrollcommand ".bright.sb set" \
+ -cursor [. cget -cursor] \
+ -spacing1 1 -spacing3 1
lappend bglist $cflist
lappend fglist $cflist
${NS}::scrollbar .bright.sb -command "$cflist yview"
pack .bright.sb -side right -fill y
pack $cflist -side left -fill both -expand 1
$cflist tag configure highlight \
- -background [$cflist cget -selectbackground]
+ -background [$cflist cget -selectbackground]
$cflist tag configure bold -font mainfontbold
.pwbottom add .bright
@@ -2494,15 +2505,15 @@ proc makewindow {} {
# restore window width & height if known
if {[info exists geometry(main)]} {
- if {[scan $geometry(main) "%dx%d" w h] >= 2} {
- if {$w > [winfo screenwidth .]} {
- set w [winfo screenwidth .]
- }
- if {$h > [winfo screenheight .]} {
- set h [winfo screenheight .]
- }
- wm geometry . "${w}x$h"
- }
+ if {[scan $geometry(main) "%dx%d" w h] >= 2} {
+ if {$w > [winfo screenwidth .]} {
+ set w [winfo screenwidth .]
+ }
+ if {$h > [winfo screenheight .]} {
+ set h [winfo screenheight .]
+ }
+ wm geometry . "${w}x$h"
+ }
}
if {[info exists geometry(state)] && $geometry(state) eq "zoomed"} {
@@ -2526,25 +2537,25 @@ proc makewindow {} {
bind %W <Map> {}
%W sashpos 0 $::geometry(botwidth)
}
+ bind .pwbottom <Configure> {resizecdetpanes %W %w}
}
- bind .pwbottom <Configure> {resizecdetpanes %W %w}
pack .ctop -fill both -expand 1
bindall <1> {selcanvline %W %x %y}
#bindall <B1-Motion> {selcanvline %W %x %y}
if {[tk windowingsystem] == "win32"} {
- bind . <MouseWheel> { windows_mousewheel_redirector %W %X %Y %D }
- bind $ctext <MouseWheel> { windows_mousewheel_redirector %W %X %Y %D ; break }
+ bind . <MouseWheel> { windows_mousewheel_redirector %W %X %Y %D }
+ bind $ctext <MouseWheel> { windows_mousewheel_redirector %W %X %Y %D ; break }
} else {
- bindall <ButtonRelease-4> "allcanvs yview scroll -5 units"
- bindall <ButtonRelease-5> "allcanvs yview scroll 5 units"
- bind $ctext <Button> {
- if {"%b" eq 6} {
- $ctext xview scroll -5 units
- } elseif {"%b" eq 7} {
- $ctext xview scroll 5 units
- }
- }
+ bindall <ButtonRelease-4> "allcanvs yview scroll -5 units"
+ bindall <ButtonRelease-5> "allcanvs yview scroll 5 units"
+ bind $ctext <Button> {
+ if {"%b" eq 6} {
+ $ctext xview scroll -5 units
+ } elseif {"%b" eq 7} {
+ $ctext xview scroll 5 units
+ }
+ }
if {[tk windowingsystem] eq "aqua"} {
bindall <MouseWheel> {
set delta [expr {- (%D)}]
@@ -2627,7 +2638,7 @@ proc makewindow {} {
bind $ctext <Button-1> {focus %W}
bind $ctext <<Selection>> rehighlight_search_results
for {set i 1} {$i < 10} {incr i} {
- bind . <$M1B-Key-$i> [list go_to_parent $i]
+ bind . <$M1B-Key-$i> [list go_to_parent $i]
}
set maincursor [. cget -cursor]
@@ -2636,60 +2647,60 @@ proc makewindow {} {
set rowctxmenu .rowctxmenu
makemenu $rowctxmenu {
- {mc "Diff this -> selected" command {diffvssel 0}}
- {mc "Diff selected -> this" command {diffvssel 1}}
- {mc "Make patch" command mkpatch}
- {mc "Create tag" command mktag}
- {mc "Copy commit summary" command copysummary}
- {mc "Write commit to file" command writecommit}
- {mc "Create new branch" command mkbranch}
- {mc "Cherry-pick this commit" command cherrypick}
- {mc "Reset HEAD branch to here" command resethead}
- {mc "Mark this commit" command markhere}
- {mc "Return to mark" command gotomark}
- {mc "Find descendant of this and mark" command find_common_desc}
- {mc "Compare with marked commit" command compare_commits}
- {mc "Diff this -> marked commit" command {diffvsmark 0}}
- {mc "Diff marked commit -> this" command {diffvsmark 1}}
- {mc "Revert this commit" command revert}
+ {mc "Diff this -> selected" command {diffvssel 0}}
+ {mc "Diff selected -> this" command {diffvssel 1}}
+ {mc "Make patch" command mkpatch}
+ {mc "Create tag" command mktag}
+ {mc "Copy commit reference" command copyreference}
+ {mc "Write commit to file" command writecommit}
+ {mc "Create new branch" command mkbranch}
+ {mc "Cherry-pick this commit" command cherrypick}
+ {mc "Reset HEAD branch to here" command resethead}
+ {mc "Mark this commit" command markhere}
+ {mc "Return to mark" command gotomark}
+ {mc "Find descendant of this and mark" command find_common_desc}
+ {mc "Compare with marked commit" command compare_commits}
+ {mc "Diff this -> marked commit" command {diffvsmark 0}}
+ {mc "Diff marked commit -> this" command {diffvsmark 1}}
+ {mc "Revert this commit" command revert}
}
$rowctxmenu configure -tearoff 0
set fakerowmenu .fakerowmenu
makemenu $fakerowmenu {
- {mc "Diff this -> selected" command {diffvssel 0}}
- {mc "Diff selected -> this" command {diffvssel 1}}
- {mc "Make patch" command mkpatch}
- {mc "Diff this -> marked commit" command {diffvsmark 0}}
- {mc "Diff marked commit -> this" command {diffvsmark 1}}
+ {mc "Diff this -> selected" command {diffvssel 0}}
+ {mc "Diff selected -> this" command {diffvssel 1}}
+ {mc "Make patch" command mkpatch}
+ {mc "Diff this -> marked commit" command {diffvsmark 0}}
+ {mc "Diff marked commit -> this" command {diffvsmark 1}}
}
$fakerowmenu configure -tearoff 0
set headctxmenu .headctxmenu
makemenu $headctxmenu {
- {mc "Check out this branch" command cobranch}
- {mc "Rename this branch" command mvbranch}
- {mc "Remove this branch" command rmbranch}
- {mc "Copy branch name" command {clipboard clear; clipboard append $headmenuhead}}
+ {mc "Check out this branch" command cobranch}
+ {mc "Rename this branch" command mvbranch}
+ {mc "Remove this branch" command rmbranch}
+ {mc "Copy branch name" command {clipboard clear; clipboard append $headmenuhead}}
}
$headctxmenu configure -tearoff 0
global flist_menu
set flist_menu .flistctxmenu
makemenu $flist_menu {
- {mc "Highlight this too" command {flist_hl 0}}
- {mc "Highlight this only" command {flist_hl 1}}
- {mc "External diff" command {external_diff}}
- {mc "Blame parent commit" command {external_blame 1}}
- {mc "Copy path" command {clipboard clear; clipboard append $flist_menu_file}}
+ {mc "Highlight this too" command {flist_hl 0}}
+ {mc "Highlight this only" command {flist_hl 1}}
+ {mc "External diff" command {external_diff}}
+ {mc "Blame parent commit" command {external_blame 1}}
+ {mc "Copy path" command {clipboard clear; clipboard append $flist_menu_file}}
}
$flist_menu configure -tearoff 0
global diff_menu
set diff_menu .diffctxmenu
makemenu $diff_menu {
- {mc "Show origin of this line" command show_line_source}
- {mc "Run git gui blame on this line" command {external_blame_diff}}
+ {mc "Show origin of this line" command show_line_source}
+ {mc "Run git gui blame on this line" command {external_blame_diff}}
}
$diff_menu configure -tearoff 0
}
@@ -2701,14 +2712,14 @@ proc windows_mousewheel_redirector {W X Y D} {
global canv canv2 canv3
set w [winfo containing -displayof $W $X $Y]
if {$w ne ""} {
- set u [expr {$D < 0 ? 5 : -5}]
- if {$w == $canv || $w == $canv2 || $w == $canv3} {
- allcanvs yview scroll $u units
- } else {
- catch {
- $w yview scroll $u units
- }
- }
+ set u [expr {$D < 0 ? 5 : -5}]
+ if {$w == $canv || $w == $canv2 || $w == $canv3} {
+ allcanvs yview scroll $u units
+ } else {
+ catch {
+ $w yview scroll $u units
+ }
+ }
}
}
@@ -2717,9 +2728,9 @@ proc selectedline_change {n1 n2 op} {
global selectedline rownumsel
if {$selectedline eq {}} {
- set rownumsel {}
+ set rownumsel {}
} else {
- set rownumsel [expr {$selectedline + 1}]
+ set rownumsel [expr {$selectedline + 1}]
}
}
@@ -2728,11 +2739,11 @@ proc selectedline_change {n1 n2 op} {
proc canvscan {op w x y} {
global canv canv2 canv3
foreach c [list $canv $canv2 $canv3] {
- if {$c == $w} {
- $c scan $op $x $y
- } else {
- $c scan $op 0 $y
- }
+ if {$c == $w} {
+ $c scan $op $x $y
+ } else {
+ $c scan $op 0 $y
+ }
}
}
@@ -2750,10 +2761,10 @@ proc bindkey {ev script} {
bind . $ev $script
set escript [bind Entry $ev]
if {$escript == {}} {
- set escript [bind Entry <Key>]
+ set escript [bind Entry <Key>]
}
foreach e $entries {
- bind $e $ev "$escript; break"
+ bind $e $ev "$escript; break"
}
}
@@ -2767,7 +2778,7 @@ proc bindmodfunctionkey {mod n script} {
proc click {w} {
global ctext entries
foreach e [concat $entries $ctext] {
- if {$w == $e} return
+ if {$w == $e} return
}
focus .
}
@@ -2779,8 +2790,8 @@ proc adjustprogress {} {
global rprogitem rprogcoord use_ttk
if {$use_ttk} {
- $progresscanv configure -value [expr {int($fprogcoord * 100)}]
- return
+ $progresscanv configure -value [expr {int($fprogcoord * 100)}]
+ return
}
set w [expr {[winfo width $progresscanv] - 4}]
@@ -2792,11 +2803,11 @@ proc adjustprogress {} {
$progresscanv coords $rprogitem 0 0 [expr {$w * $rprogcoord}] $h
set now [clock clicks -milliseconds]
if {$now >= $lastprogupdate + 100} {
- set progupdatepending 0
- update
+ set progupdatepending 0
+ update
} elseif {!$progupdatepending} {
- set progupdatepending 1
- after [expr {$lastprogupdate + 100 - $now}] doprogupdate
+ set progupdatepending 1
+ after [expr {$lastprogupdate + 100 - $now}] doprogupdate
}
}
@@ -2804,9 +2815,9 @@ proc doprogupdate {} {
global lastprogupdate progupdatepending
if {$progupdatepending} {
- set progupdatepending 0
- set lastprogupdate [clock clicks -milliseconds]
- update
+ set progupdatepending 0
+ set lastprogupdate [clock clicks -milliseconds]
+ update
}
}
@@ -2814,14 +2825,14 @@ proc config_check_tmp_exists {tries_left} {
global config_file_tmp
if {[file exists $config_file_tmp]} {
- incr tries_left -1
- if {$tries_left > 0} {
- after 100 [list config_check_tmp_exists $tries_left]
- } else {
- error_popup "There appears to be a stale $config_file_tmp\
+ incr tries_left -1
+ if {$tries_left > 0} {
+ after 100 [list config_check_tmp_exists $tries_left]
+ } else {
+ error_popup "There appears to be a stale $config_file_tmp\
file, which will prevent gitk from saving its configuration on exit.\
Please remove it if it is not being used by any existing gitk process."
- }
+ }
}
}
@@ -2838,9 +2849,9 @@ proc config_variable_change_cb {name name2 op} {
upvar #0 $name var
if {$op eq "write" &&
- (![info exists config_variable_original($name)] ||
- $config_variable_original($name) ne $var)} {
- set config_variable_changed($name) 1
+ (![info exists config_variable_original($name)] ||
+ $config_variable_original($name) ne $var)} {
+ set config_variable_changed($name) 1
}
}
@@ -2862,151 +2873,158 @@ proc savestuff {w} {
if {![winfo viewable .]} return
set remove_tmp 0
if {[catch {
- set try_count 0
- while {[catch {set f [open $config_file_tmp {WRONLY CREAT EXCL}]}]} {
- if {[incr try_count] > 50} {
- error "Unable to write config file: $config_file_tmp exists"
- }
- after 100
- }
- set remove_tmp 1
- if {$::tcl_platform(platform) eq {windows}} {
- file attributes $config_file_tmp -hidden true
- }
- if {[file exists $config_file]} {
- source $config_file
- }
- foreach var_name $config_variables {
- upvar #0 $var_name var
- upvar 0 $var_name old_var
- if {!$config_variable_changed($var_name) && [info exists old_var]} {
- puts $f [list set $var_name $old_var]
- } else {
- puts $f [list set $var_name $var]
- }
- }
-
- puts $f "set geometry(main) [wm geometry .]"
- puts $f "set geometry(state) [wm state .]"
- puts $f "set geometry(topwidth) [winfo width .tf]"
- puts $f "set geometry(topheight) [winfo height .tf]"
- if {$current_use_ttk} {
- puts $f "set geometry(pwsash0) \"[.tf.histframe.pwclist sashpos 0] 1\""
- puts $f "set geometry(pwsash1) \"[.tf.histframe.pwclist sashpos 1] 1\""
- } else {
- puts $f "set geometry(pwsash0) \"[.tf.histframe.pwclist sash coord 0]\""
- puts $f "set geometry(pwsash1) \"[.tf.histframe.pwclist sash coord 1]\""
- }
- puts $f "set geometry(botwidth) [winfo width .bleft]"
- puts $f "set geometry(botheight) [winfo height .bleft]"
-
- array set view_save {}
- array set views {}
- if {![info exists permviews]} { set permviews {} }
- foreach view $permviews {
- set view_save([lindex $view 0]) 1
- set views([lindex $view 0]) $view
- }
- puts -nonewline $f "set permviews {"
- for {set v 1} {$v < $current_nextviewnum} {incr v} {
- if {$viewchanged($v)} {
- if {$current_viewperm($v)} {
- set views($current_viewname($v)) [list $current_viewname($v) $current_viewfiles($v) $current_viewargs($v) $current_viewargscmd($v)]
- } else {
- set view_save($current_viewname($v)) 0
- }
- }
- }
- # write old and updated view to their places and append remaining to the end
- foreach view $permviews {
- set view_name [lindex $view 0]
- if {$view_save($view_name)} {
- puts $f "{$views($view_name)}"
- }
- unset views($view_name)
- }
- foreach view_name [array names views] {
- puts $f "{$views($view_name)}"
- }
- puts $f "}"
- close $f
- file rename -force $config_file_tmp $config_file
- set remove_tmp 0
+ set try_count 0
+ while {[catch {set f [open $config_file_tmp {WRONLY CREAT EXCL}]}]} {
+ if {[incr try_count] > 50} {
+ error "Unable to write config file: $config_file_tmp exists"
+ }
+ after 100
+ }
+ set remove_tmp 1
+ if {$::tcl_platform(platform) eq {windows}} {
+ file attributes $config_file_tmp -hidden true
+ }
+ if {[file exists $config_file]} {
+ source $config_file
+ }
+ foreach var_name $config_variables {
+ upvar #0 $var_name var
+ upvar 0 $var_name old_var
+ if {!$config_variable_changed($var_name) && [info exists old_var]} {
+ puts $f [list set $var_name $old_var]
+ } else {
+ puts $f [list set $var_name $var]
+ }
+ }
+
+ puts $f "set geometry(main) [wm geometry .]"
+ puts $f "set geometry(state) [wm state .]"
+ puts $f "set geometry(topwidth) [winfo width .tf]"
+ puts $f "set geometry(topheight) [winfo height .tf]"
+ if {$current_use_ttk} {
+ puts $f "set geometry(pwsash0) \"[.tf.histframe.pwclist sashpos 0] 1\""
+ puts $f "set geometry(pwsash1) \"[.tf.histframe.pwclist sashpos 1] 1\""
+ } else {
+ puts $f "set geometry(pwsash0) \"[.tf.histframe.pwclist sash coord 0]\""
+ puts $f "set geometry(pwsash1) \"[.tf.histframe.pwclist sash coord 1]\""
+ }
+ puts $f "set geometry(botwidth) [winfo width .bleft]"
+ puts $f "set geometry(botheight) [winfo height .bleft]"
+
+ array set view_save {}
+ array set views {}
+ if {![info exists permviews]} { set permviews {} }
+ foreach view $permviews {
+ set view_save([lindex $view 0]) 1
+ set views([lindex $view 0]) $view
+ }
+ puts -nonewline $f "set permviews {"
+ for {set v 1} {$v < $current_nextviewnum} {incr v} {
+ if {$viewchanged($v)} {
+ if {$current_viewperm($v)} {
+ set views($current_viewname($v)) [list $current_viewname($v) $current_viewfiles($v) $current_viewargs($v) $current_viewargscmd($v)]
+ } else {
+ set view_save($current_viewname($v)) 0
+ }
+ }
+ }
+ # write old and updated view to their places and append remaining to the end
+ foreach view $permviews {
+ set view_name [lindex $view 0]
+ if {$view_save($view_name)} {
+ puts $f "{$views($view_name)}"
+ }
+ unset views($view_name)
+ }
+ foreach view_name [array names views] {
+ puts $f "{$views($view_name)}"
+ }
+ puts $f "}"
+ close $f
+ file rename -force $config_file_tmp $config_file
+ set remove_tmp 0
} err]} {
puts "Error saving config: $err"
}
if {$remove_tmp} {
- file delete -force $config_file_tmp
+ file delete -force $config_file_tmp
}
set stuffsaved 1
}
proc resizeclistpanes {win w} {
- global oldwidth use_ttk
+ global oldwidth oldsash use_ttk
if {[info exists oldwidth($win)]} {
- if {$use_ttk} {
- set s0 [$win sashpos 0]
- set s1 [$win sashpos 1]
- } else {
- set s0 [$win sash coord 0]
- set s1 [$win sash coord 1]
- }
- if {$w < 60} {
- set sash0 [expr {int($w/2 - 2)}]
- set sash1 [expr {int($w*5/6 - 2)}]
- } else {
- set factor [expr {1.0 * $w / $oldwidth($win)}]
- set sash0 [expr {int($factor * [lindex $s0 0])}]
- set sash1 [expr {int($factor * [lindex $s1 0])}]
- if {$sash0 < 30} {
- set sash0 30
- }
- if {$sash1 < $sash0 + 20} {
- set sash1 [expr {$sash0 + 20}]
- }
- if {$sash1 > $w - 10} {
- set sash1 [expr {$w - 10}]
- if {$sash0 > $sash1 - 20} {
- set sash0 [expr {$sash1 - 20}]
- }
- }
- }
- if {$use_ttk} {
- $win sashpos 0 $sash0
- $win sashpos 1 $sash1
- } else {
- $win sash place 0 $sash0 [lindex $s0 1]
- $win sash place 1 $sash1 [lindex $s1 1]
- }
+ if {[info exists oldsash($win)]} {
+ set s0 [lindex $oldsash($win) 0]
+ set s1 [lindex $oldsash($win) 1]
+ } elseif {$use_ttk} {
+ set s0 [$win sashpos 0]
+ set s1 [$win sashpos 1]
+ } else {
+ set s0 [$win sash coord 0]
+ set s1 [$win sash coord 1]
+ }
+ if {$w < 60} {
+ set sash0 [expr {int($w/2 - 2)}]
+ set sash1 [expr {int($w*5/6 - 2)}]
+ } else {
+ set factor [expr {1.0 * $w / $oldwidth($win)}]
+ set sash0 [expr {int($factor * [lindex $s0 0])}]
+ set sash1 [expr {int($factor * [lindex $s1 0])}]
+ if {$sash0 < 30} {
+ set sash0 30
+ }
+ if {$sash1 < $sash0 + 20} {
+ set sash1 [expr {$sash0 + 20}]
+ }
+ if {$sash1 > $w - 10} {
+ set sash1 [expr {$w - 10}]
+ if {$sash0 > $sash1 - 20} {
+ set sash0 [expr {$sash1 - 20}]
+ }
+ }
+ }
+ if {$use_ttk} {
+ $win sashpos 0 $sash0
+ $win sashpos 1 $sash1
+ } else {
+ $win sash place 0 $sash0 [lindex $s0 1]
+ $win sash place 1 $sash1 [lindex $s1 1]
+ }
+ set oldsash($win) [list $sash0 $sash1]
}
set oldwidth($win) $w
}
proc resizecdetpanes {win w} {
- global oldwidth use_ttk
+ global oldwidth oldsash use_ttk
if {[info exists oldwidth($win)]} {
- if {$use_ttk} {
- set s0 [$win sashpos 0]
- } else {
- set s0 [$win sash coord 0]
- }
- if {$w < 60} {
- set sash0 [expr {int($w*3/4 - 2)}]
- } else {
- set factor [expr {1.0 * $w / $oldwidth($win)}]
- set sash0 [expr {int($factor * [lindex $s0 0])}]
- if {$sash0 < 45} {
- set sash0 45
- }
- if {$sash0 > $w - 15} {
- set sash0 [expr {$w - 15}]
- }
- }
- if {$use_ttk} {
- $win sashpos 0 $sash0
- } else {
- $win sash place 0 $sash0 [lindex $s0 1]
- }
+ if {[info exists oldsash($win)]} {
+ set s0 $oldsash($win)
+ } elseif {$use_ttk} {
+ set s0 [$win sashpos 0]
+ } else {
+ set s0 [$win sash coord 0]
+ }
+ if {$w < 60} {
+ set sash0 [expr {int($w*3/4 - 2)}]
+ } else {
+ set factor [expr {1.0 * $w / $oldwidth($win)}]
+ set sash0 [expr {int($factor * [lindex $s0 0])}]
+ if {$sash0 < 45} {
+ set sash0 45
+ }
+ if {$sash0 > $w - 15} {
+ set sash0 [expr {$w - 15}]
+ }
+ }
+ if {$use_ttk} {
+ $win sashpos 0 $sash0
+ } else {
+ $win sash place 0 $sash0 [lindex $s0 1]
+ }
+ set oldsash($win) $sash0
}
set oldwidth($win) $w
}
@@ -3029,8 +3047,8 @@ proc about {} {
global bgcolor NS
set w .about
if {[winfo exists $w]} {
- raise $w
- return
+ raise $w
+ return
}
ttk_toplevel $w
wm title $w [mc "About gitk"]
@@ -3041,7 +3059,7 @@ Gitk - a commit viewer for git
Copyright \u00a9 2005-2016 Paul Mackerras
Use and redistribute under the terms of the GNU General Public License"] \
- -justify center -aspect 400 -border 2 -bg $bgcolor -relief groove
+ -justify center -aspect 400 -border 2 -bg $bgcolor -relief groove
pack $w.m -side top -fill x -padx 2 -pady 2
${NS}::button $w.ok -text [mc "Close"] -command "destroy $w" -default active
pack $w.ok -side bottom
@@ -3055,13 +3073,13 @@ proc keys {} {
global bgcolor NS
set w .keys
if {[winfo exists $w]} {
- raise $w
- return
+ raise $w
+ return
}
if {[tk windowingsystem] eq {aqua}} {
- set M1T Cmd
+ set M1T Cmd
} else {
- set M1T Ctrl
+ set M1T Ctrl
}
ttk_toplevel $w
wm title $w [mc "Gitk key bindings"]
@@ -3108,7 +3126,7 @@ proc keys {} {
[mc "<%s-minus> Decrease font size" $M1T]
[mc "<F5> Update"]
" \
- -justify left -bg $bgcolor -border 2 -relief groove
+ -justify left -bg $bgcolor -border 2 -relief groove
pack $w.m -side top -fill both -padx 2 -pady 2
${NS}::button $w.ok -text [mc "Close"] -command "destroy $w" -default active
bind $w <Key-Escape> [list destroy $w]
@@ -3135,68 +3153,68 @@ proc treeview {w l openlevs} {
set treecontents() {}
$w conf -state normal
foreach f $l {
- while {[string range $f 0 $prefixend] ne $prefix} {
- if {$lev <= $openlevs} {
- $w mark set e:$treeindex($prefix) "end -1c"
- $w mark gravity e:$treeindex($prefix) left
- }
- set treeheight($prefix) $ht
- incr ht [lindex $htstack end]
- set htstack [lreplace $htstack end end]
- set prefixend [lindex $prefendstack end]
- set prefendstack [lreplace $prefendstack end end]
- set prefix [string range $prefix 0 $prefixend]
- incr lev -1
- }
- set tail [string range $f [expr {$prefixend+1}] end]
- while {[set slash [string first "/" $tail]] >= 0} {
- lappend htstack $ht
- set ht 0
- lappend prefendstack $prefixend
- incr prefixend [expr {$slash + 1}]
- set d [string range $tail 0 $slash]
- lappend treecontents($prefix) $d
- set oldprefix $prefix
- append prefix $d
- set treecontents($prefix) {}
- set treeindex($prefix) [incr ix]
- set treeparent($prefix) $oldprefix
- set tail [string range $tail [expr {$slash+1}] end]
- if {$lev <= $openlevs} {
- set ht 1
- set treediropen($prefix) [expr {$lev < $openlevs}]
- set bm [expr {$lev == $openlevs? "tri-rt": "tri-dn"}]
- $w mark set d:$ix "end -1c"
- $w mark gravity d:$ix left
- set str "\n"
- for {set i 0} {$i < $lev} {incr i} {append str "\t"}
- $w insert end $str
- $w image create end -align center -image $bm -padx 1 \
- -name a:$ix
- $w insert end $d [highlight_tag $prefix]
- $w mark set s:$ix "end -1c"
- $w mark gravity s:$ix left
- }
- incr lev
- }
- if {$tail ne {}} {
- if {$lev <= $openlevs} {
- incr ht
- set str "\n"
- for {set i 0} {$i < $lev} {incr i} {append str "\t"}
- $w insert end $str
- $w insert end $tail [highlight_tag $f]
- }
- lappend treecontents($prefix) $tail
- }
+ while {[string range $f 0 $prefixend] ne $prefix} {
+ if {$lev <= $openlevs} {
+ $w mark set e:$treeindex($prefix) "end -1c"
+ $w mark gravity e:$treeindex($prefix) left
+ }
+ set treeheight($prefix) $ht
+ incr ht [lindex $htstack end]
+ set htstack [lreplace $htstack end end]
+ set prefixend [lindex $prefendstack end]
+ set prefendstack [lreplace $prefendstack end end]
+ set prefix [string range $prefix 0 $prefixend]
+ incr lev -1
+ }
+ set tail [string range $f [expr {$prefixend+1}] end]
+ while {[set slash [string first "/" $tail]] >= 0} {
+ lappend htstack $ht
+ set ht 0
+ lappend prefendstack $prefixend
+ incr prefixend [expr {$slash + 1}]
+ set d [string range $tail 0 $slash]
+ lappend treecontents($prefix) $d
+ set oldprefix $prefix
+ append prefix $d
+ set treecontents($prefix) {}
+ set treeindex($prefix) [incr ix]
+ set treeparent($prefix) $oldprefix
+ set tail [string range $tail [expr {$slash+1}] end]
+ if {$lev <= $openlevs} {
+ set ht 1
+ set treediropen($prefix) [expr {$lev < $openlevs}]
+ set bm [expr {$lev == $openlevs? "tri-rt": "tri-dn"}]
+ $w mark set d:$ix "end -1c"
+ $w mark gravity d:$ix left
+ set str "\n"
+ for {set i 0} {$i < $lev} {incr i} {append str "\t"}
+ $w insert end $str
+ $w image create end -align center -image $bm -padx 1 \
+ -name a:$ix
+ $w insert end $d [highlight_tag $prefix]
+ $w mark set s:$ix "end -1c"
+ $w mark gravity s:$ix left
+ }
+ incr lev
+ }
+ if {$tail ne {}} {
+ if {$lev <= $openlevs} {
+ incr ht
+ set str "\n"
+ for {set i 0} {$i < $lev} {incr i} {append str "\t"}
+ $w insert end $str
+ $w insert end $tail [highlight_tag $f]
+ }
+ lappend treecontents($prefix) $tail
+ }
}
while {$htstack ne {}} {
- set treeheight($prefix) $ht
- incr ht [lindex $htstack end]
- set htstack [lreplace $htstack end end]
- set prefixend [lindex $prefendstack end]
- set prefendstack [lreplace $prefendstack end end]
- set prefix [string range $prefix 0 $prefixend]
+ set treeheight($prefix) $ht
+ incr ht [lindex $htstack end]
+ set htstack [lreplace $htstack end end]
+ set prefixend [lindex $prefendstack end]
+ set prefendstack [lreplace $prefendstack end end]
+ set prefix [string range $prefix 0 $prefixend]
}
$w conf -state disabled
}
@@ -3207,21 +3225,21 @@ proc linetoelt {l} {
set y 2
set prefix {}
while {1} {
- foreach e $treecontents($prefix) {
- if {$y == $l} {
- return "$prefix$e"
- }
- set n 1
- if {[string index $e end] eq "/"} {
- set n $treeheight($prefix$e)
- if {$y + $n > $l} {
- append prefix $e
- incr y
- break
- }
- }
- incr y $n
- }
+ foreach e $treecontents($prefix) {
+ if {$y == $l} {
+ return "$prefix$e"
+ }
+ set n 1
+ if {[string index $e end] eq "/"} {
+ set n $treeheight($prefix$e)
+ if {$y + $n > $l} {
+ append prefix $e
+ incr y
+ break
+ }
+ }
+ incr y $n
+ }
}
}
@@ -3229,14 +3247,14 @@ proc highlight_tree {y prefix} {
global treeheight treecontents cflist
foreach e $treecontents($prefix) {
- set path $prefix$e
- if {[highlight_tag $path] ne {}} {
- $cflist tag add bold $y.0 "$y.0 lineend"
- }
- incr y
- if {[string index $e end] eq "/" && $treeheight($path) > 1} {
- set y [highlight_tree $y $path]
- }
+ set path $prefix$e
+ if {[highlight_tag $path] ne {}} {
+ $cflist tag add bold $y.0 "$y.0 lineend"
+ }
+ incr y
+ if {[string index $e end] eq "/" && $treeheight($path) > 1} {
+ set y [highlight_tree $y $path]
+ }
}
return $y
}
@@ -3252,8 +3270,8 @@ proc treeclosedir {w dir} {
$w conf -state disabled
set n [expr {1 - $treeheight($dir)}]
while {$dir ne {}} {
- incr treeheight($dir) $n
- set dir $treeparent($dir)
+ incr treeheight($dir) $n
+ set dir $treeparent($dir)
}
}
@@ -3269,28 +3287,28 @@ proc treeopendir {w dir} {
set str "\n"
set n [llength $treecontents($dir)]
for {set x $dir} {$x ne {}} {set x $treeparent($x)} {
- incr lev
- append str "\t"
- incr treeheight($x) $n
+ incr lev
+ append str "\t"
+ incr treeheight($x) $n
}
foreach e $treecontents($dir) {
- set de $dir$e
- if {[string index $e end] eq "/"} {
- set iy $treeindex($de)
- $w mark set d:$iy e:$ix
- $w mark gravity d:$iy left
- $w insert e:$ix $str
- set treediropen($de) 0
- $w image create e:$ix -align center -image tri-rt -padx 1 \
- -name a:$iy
- $w insert e:$ix $e [highlight_tag $de]
- $w mark set s:$iy e:$ix
- $w mark gravity s:$iy left
- set treeheight($de) 1
- } else {
- $w insert e:$ix $str
- $w insert e:$ix $e [highlight_tag $de]
- }
+ set de $dir$e
+ if {[string index $e end] eq "/"} {
+ set iy $treeindex($de)
+ $w mark set d:$iy e:$ix
+ $w mark gravity d:$iy left
+ $w insert e:$ix $str
+ set treediropen($de) 0
+ $w image create e:$ix -align center -image tri-rt -padx 1 \
+ -name a:$iy
+ $w insert e:$ix $e [highlight_tag $de]
+ $w mark set s:$iy e:$ix
+ $w mark gravity s:$iy left
+ set treeheight($de) 1
+ } else {
+ $w insert e:$ix $str
+ $w insert e:$ix $e [highlight_tag $de]
+ }
}
$w mark gravity e:$ix right
$w conf -state disabled
@@ -3299,13 +3317,13 @@ proc treeopendir {w dir} {
set ht [$w cget -height]
set l [lindex [split [$w index s:$ix] .] 0]
if {$l < $top} {
- $w yview $l.0
+ $w yview $l.0
} elseif {$l + $n + 1 > $top + $ht} {
- set top [expr {$l + $n + 2 - $ht}]
- if {$l < $top} {
- set top $l
- }
- $w yview $top.0
+ set top [expr {$l + $n + 2 - $ht}]
+ if {$l < $top} {
+ set top $l
+ }
+ $w yview $top.0
}
}
@@ -3319,16 +3337,16 @@ proc treeclick {w x y} {
$cflist tag add highlight $l.0 "$l.0 lineend"
set cflist_top $l
if {$l == 1} {
- $ctext yview 1.0
- return
+ $ctext yview 1.0
+ return
}
set e [linetoelt $l]
if {[string index $e end] ne "/"} {
- showfile $e
+ showfile $e
} elseif {$treediropen($e)} {
- treeclosedir $w $e
+ treeclosedir $w $e
} else {
- treeopendir $w $e
+ treeopendir $w $e
}
}
@@ -3337,10 +3355,10 @@ proc setfilelist {id} {
treeview $cflist $treefilelist($id) 0
if {$jump_to_here ne {}} {
- set f [lindex $jump_to_here 0]
- if {[lsearch -exact $treefilelist($id) $f] >= 0} {
- showfile $f
- }
+ set f [lindex $jump_to_here 0]
+ if {[lsearch -exact $treefilelist($id) $f] >= 0} {
+ showfile $f
+ }
}
}
@@ -3415,11 +3433,11 @@ proc init_flist {first} {
$cflist conf -state normal
$cflist delete 0.0 end
if {$first ne {}} {
- $cflist insert end $first
- set cflist_top 1
- $cflist tag add highlight 1.0 "1.0 lineend"
+ $cflist insert end $first
+ set cflist_top 1
+ $cflist tag add highlight 1.0 "1.0 lineend"
} else {
- unset -nocomplain cflist_top
+ unset -nocomplain cflist_top
}
$cflist conf -state disabled
set difffilestart {}
@@ -3429,9 +3447,9 @@ proc highlight_tag {f} {
global highlight_paths
foreach p $highlight_paths {
- if {[string match $p $f]} {
- return "bold"
- }
+ if {[string match $p $f]} {
+ return "bold"
+ }
}
return {}
}
@@ -3441,15 +3459,15 @@ proc highlight_filelist {} {
$cflist conf -state normal
if {$cmitmode ne "tree"} {
- set end [lindex [split [$cflist index end] .] 0]
- for {set l 2} {$l < $end} {incr l} {
- set line [$cflist get $l.0 "$l.0 lineend"]
- if {[highlight_tag $line] ne {}} {
- $cflist tag add bold $l.0 "$l.0 lineend"
- }
- }
+ set end [lindex [split [$cflist index end] .] 0]
+ for {set l 2} {$l < $end} {incr l} {
+ set line [$cflist get $l.0 "$l.0 lineend"]
+ if {[highlight_tag $line] ne {}} {
+ $cflist tag add bold $l.0 "$l.0 lineend"
+ }
+ }
} else {
- highlight_tree 2 {}
+ highlight_tree 2 {}
}
$cflist conf -state disabled
}
@@ -3467,8 +3485,8 @@ proc add_flist {fl} {
$cflist conf -state normal
foreach f $fl {
- $cflist insert end "\n"
- $cflist insert end $f [highlight_tag $f]
+ $cflist insert end "\n"
+ $cflist insert end $f [highlight_tag $f]
}
$cflist conf -state disabled
}
@@ -3483,9 +3501,9 @@ proc sel_flist {w x y} {
$cflist tag add highlight $l.0 "$l.0 lineend"
set cflist_top $l
if {$l == 1} {
- $ctext yview 1.0
+ $ctext yview 1.0
} else {
- catch {$ctext yview [lindex $difffilestart [expr {$l - 2}]]}
+ catch {$ctext yview [lindex $difffilestart [expr {$l - 2}]]}
}
suppress_highlighting_file_for_current_scrollpos
}
@@ -3498,15 +3516,15 @@ proc pop_flist_menu {w X Y x y} {
set l [lindex [split [$w index "@$x,$y"] "."] 0]
if {$l <= 1} return
if {$cmitmode eq "tree"} {
- set e [linetoelt $l]
- if {[string index $e end] eq "/"} return
+ set e [linetoelt $l]
+ if {[string index $e end] eq "/"} return
} else {
- set e [lindex $treediffs($diffids) [expr {$l-2}]]
+ set e [lindex $treediffs($diffids) [expr {$l-2}]]
}
set flist_menu_file $e
set xdiffstate "normal"
if {$cmitmode eq "tree"} {
- set xdiffstate "disabled"
+ set xdiffstate "disabled"
}
# Disable "External diff" item in tree mode
$flist_menu entryconf 2 -state $xdiffstate
@@ -3535,7 +3553,7 @@ proc pop_diff_menu {w X Y x y} {
set diff_menu_line [lindex $diff_menu_txtpos 0]
# don't pop up the menu on hunk-separator or file-separator lines
if {[lsearch -glob [$ctext tag names $diff_menu_line.0] "*sep"] >= 0} {
- return
+ return
}
stopfinding
set f [find_ctext_fileinfo $diff_menu_line]
@@ -3550,9 +3568,9 @@ proc flist_hl {only} {
set x [shellquote $flist_menu_file]
if {$only || $findstring eq {} || $gdttype ne [mc "touching paths:"]} {
- set findstring $x
+ set findstring $x
} else {
- append findstring " " $x
+ append findstring " " $x
}
set gdttype [mc "touching paths:"]
}
@@ -3561,29 +3579,29 @@ proc gitknewtmpdir {} {
global diffnum gitktmpdir gitdir env
if {![info exists gitktmpdir]} {
- if {[info exists env(GITK_TMPDIR)]} {
- set tmpdir $env(GITK_TMPDIR)
- } elseif {[info exists env(TMPDIR)]} {
- set tmpdir $env(TMPDIR)
- } else {
- set tmpdir $gitdir
- }
- set gitktmpformat [file join $tmpdir ".gitk-tmp.XXXXXX"]
- if {[catch {set gitktmpdir [exec mktemp -d $gitktmpformat]}]} {
- set gitktmpdir [file join $gitdir [format ".gitk-tmp.%s" [pid]]]
- }
- if {[catch {file mkdir $gitktmpdir} err]} {
- error_popup "[mc "Error creating temporary directory %s:" $gitktmpdir] $err"
- unset gitktmpdir
- return {}
- }
- set diffnum 0
+ if {[info exists env(GITK_TMPDIR)]} {
+ set tmpdir $env(GITK_TMPDIR)
+ } elseif {[info exists env(TMPDIR)]} {
+ set tmpdir $env(TMPDIR)
+ } else {
+ set tmpdir $gitdir
+ }
+ set gitktmpformat [file join $tmpdir ".gitk-tmp.XXXXXX"]
+ if {[catch {set gitktmpdir [exec mktemp -d $gitktmpformat]}]} {
+ set gitktmpdir [file join $gitdir [format ".gitk-tmp.%s" [pid]]]
+ }
+ if {[catch {file mkdir $gitktmpdir} err]} {
+ error_popup "[mc "Error creating temporary directory %s:" $gitktmpdir] $err"
+ unset gitktmpdir
+ return {}
+ }
+ set diffnum 0
}
incr diffnum
set diffdir [file join $gitktmpdir $diffnum]
if {[catch {file mkdir $diffdir} err]} {
- error_popup "[mc "Error creating temporary directory %s:" $diffdir] $err"
- return {}
+ error_popup "[mc "Error creating temporary directory %s:" $diffdir] $err"
+ return {}
}
return $diffdir
}
@@ -3592,11 +3610,11 @@ proc save_file_from_commit {filename output what} {
global nullfile
if {[catch {exec git show $filename -- > $output} err]} {
- if {[string match "fatal: bad revision *" $err]} {
- return $nullfile
- }
- error_popup "[mc "Error getting \"%s\" from %s:" $filename $what] $err"
- return {}
+ if {[string match "fatal: bad revision *" $err]} {
+ return $nullfile
+ }
+ error_popup "[mc "Error getting \"%s\" from %s:" $filename $what] $err"
+ return {}
}
return $output
}
@@ -3607,10 +3625,10 @@ proc external_diff_get_one_file {diffid filename diffdir} {
if {$diffid == $nullid} {
set difffile [file join $worktree $filename]
- if {[file exists $difffile]} {
- return $difffile
- }
- return $nullfile
+ if {[file exists $difffile]} {
+ return $difffile
+ }
+ return $nullfile
}
if {$diffid == $nullid2} {
set difffile [file join $diffdir "\[index\] [file tail $filename]"]
@@ -3618,7 +3636,7 @@ proc external_diff_get_one_file {diffid filename diffdir} {
}
set difffile [file join $diffdir "\[$diffid\] [file tail $filename]"]
return [save_file_from_commit $diffid:$filename $difffile \
- "revision $diffid"]
+ "revision $diffid"]
}
proc external_diff {} {
@@ -3675,18 +3693,18 @@ proc find_hunk_blamespec {base line} {
set s_line [$ctext get $s_lix "$s_lix + 1 lines"]
if {![regexp {^@@@*(( -\d+(,\d+)?)+) \+(\d+)(,\d+)? @@} $s_line \
- s_line old_specs osz osz1 new_line nsz]} {
- return
+ s_line old_specs osz osz1 new_line nsz]} {
+ return
}
# base lines for the parents
set base_lines [list $new_line]
foreach old_spec [lrange [split $old_specs " "] 1 end] {
- if {![regexp -- {-(\d+)(,\d+)?} $old_spec \
- old_spec old_line osz]} {
- return
- }
- lappend base_lines $old_line
+ if {![regexp -- {-(\d+)(,\d+)?} $old_spec \
+ old_spec old_line osz]} {
+ return
+ }
+ lappend base_lines $old_line
}
# Now scan the lines to determine offset within the hunk
@@ -3697,38 +3715,38 @@ proc find_hunk_blamespec {base line} {
# Determine if the line is removed
set chunk [$ctext get $line.0 "$line.1 + $max_parent chars"]
if {[string match {[-+ ]*} $chunk]} {
- set removed_idx [string first "-" $chunk]
- # Choose a parent index
- if {$removed_idx >= 0} {
- set parent $removed_idx
- } else {
- set unchanged_idx [string first " " $chunk]
- if {$unchanged_idx >= 0} {
- set parent $unchanged_idx
- } else {
- # blame the current commit
- set parent -1
- }
- }
- # then count other lines that belong to it
- for {set i $line} {[incr i -1] > $s_lno} {} {
- set chunk [$ctext get $i.0 "$i.1 + $max_parent chars"]
- # Determine if the line is removed
- set removed_idx [string first "-" $chunk]
- if {$parent >= 0} {
- set code [string index $chunk $parent]
- if {$code eq "-" || ($removed_idx < 0 && $code ne "+")} {
- incr dline
- }
- } else {
- if {$removed_idx < 0} {
- incr dline
- }
- }
- }
- incr parent
+ set removed_idx [string first "-" $chunk]
+ # Choose a parent index
+ if {$removed_idx >= 0} {
+ set parent $removed_idx
+ } else {
+ set unchanged_idx [string first " " $chunk]
+ if {$unchanged_idx >= 0} {
+ set parent $unchanged_idx
+ } else {
+ # blame the current commit
+ set parent -1
+ }
+ }
+ # then count other lines that belong to it
+ for {set i $line} {[incr i -1] > $s_lno} {} {
+ set chunk [$ctext get $i.0 "$i.1 + $max_parent chars"]
+ # Determine if the line is removed
+ set removed_idx [string first "-" $chunk]
+ if {$parent >= 0} {
+ set code [string index $chunk $parent]
+ if {$code eq "-" || ($removed_idx < 0 && $code ne "+")} {
+ incr dline
+ }
+ } else {
+ if {$removed_idx < 0} {
+ incr dline
+ }
+ }
+ }
+ incr parent
} else {
- set parent 0
+ set parent 0
}
incr dline [lindex $base_lines $parent]
@@ -3741,17 +3759,17 @@ proc external_blame_diff {} {
global diff_menu_filebase flist_menu_file
if {$cmitmode eq "tree"} {
- set parent_idx 0
- set line [expr {$diff_menu_line - $diff_menu_filebase}]
+ set parent_idx 0
+ set line [expr {$diff_menu_line - $diff_menu_filebase}]
} else {
- set hinfo [find_hunk_blamespec $diff_menu_filebase $diff_menu_line]
- if {$hinfo ne {}} {
- set parent_idx [lindex $hinfo 0]
- set line [lindex $hinfo 1]
- } else {
- set parent_idx 0
- set line 0
- }
+ set hinfo [find_hunk_blamespec $diff_menu_filebase $diff_menu_line]
+ if {$hinfo ne {}} {
+ set parent_idx [lindex $hinfo 0]
+ set line [lindex $hinfo 1]
+ } else {
+ set parent_idx 0
+ set line 0
+ }
}
external_blame $parent_idx $line
@@ -3762,12 +3780,12 @@ proc external_blame_diff {} {
proc index_sha1 {fname} {
set f [open [list | git ls-files -s $fname] r]
while {[gets $f line] >= 0} {
- set info [lindex [split $line "\t"] 0]
- set stage [lindex $info 2]
- if {$stage eq "0" || $stage eq "2"} {
- close $f
- return [lindex $info 1]
- }
+ set info [lindex [split $line "\t"] 0]
+ set stage [lindex $info 2]
+ if {$stage eq "0" || $stage eq "2"} {
+ close $f
+ return [lindex $info 1]
+ }
}
close $f
return {}
@@ -3776,7 +3794,7 @@ proc index_sha1 {fname} {
# Turn an absolute path into one relative to the current directory
proc make_relative {f} {
if {[file pathtype $f] eq "relative"} {
- return $f
+ return $f
}
set elts [file split $f]
set here [file split [pwd]]
@@ -3784,12 +3802,12 @@ proc make_relative {f} {
set hi 0
set res {}
foreach d $here {
- if {$ei < $hi || $ei >= [llength $elts] || [lindex $elts $ei] ne $d} {
- lappend res ".."
- } else {
- incr ei
- }
- incr hi
+ if {$ei < $hi || $ei >= [llength $elts] || [lindex $elts $ei] ne $d} {
+ lappend res ".."
+ } else {
+ incr ei
+ }
+ incr hi
}
set elts [concat $res [lrange $elts $ei end]]
return [eval file join $elts]
@@ -3801,19 +3819,19 @@ proc external_blame {parent_idx {line {}}} {
global parentlist selectedline currentid
if {$parent_idx > 0} {
- set base_commit [lindex $parentlist $selectedline [expr {$parent_idx-1}]]
+ set base_commit [lindex $parentlist $selectedline [expr {$parent_idx-1}]]
} else {
- set base_commit $currentid
+ set base_commit $currentid
}
if {$base_commit eq {} || $base_commit eq $nullid || $base_commit eq $nullid2} {
- error_popup [mc "No such commit"]
- return
+ error_popup [mc "No such commit"]
+ return
}
set cmdline [list git gui blame]
if {$line ne {} && $line > 1} {
- lappend cmdline "--line=$line"
+ lappend cmdline "--line=$line"
}
set f [file join $cdup $flist_menu_file]
# Unfortunately it seems git gui blame doesn't like
@@ -3821,7 +3839,7 @@ proc external_blame {parent_idx {line {}}} {
set f [make_relative $f]
lappend cmdline $base_commit $f
if {[catch {eval exec $cmdline &} err]} {
- error_popup "[mc "git gui blame: command failed:"] $err"
+ error_popup "[mc "git gui blame: command failed:"] $err"
}
}
@@ -3832,61 +3850,61 @@ proc show_line_source {} {
set from_index {}
if {$cmitmode eq "tree"} {
- set id $currentid
- set line [expr {$diff_menu_line - $diff_menu_filebase}]
+ set id $currentid
+ set line [expr {$diff_menu_line - $diff_menu_filebase}]
} else {
- set h [find_hunk_blamespec $diff_menu_filebase $diff_menu_line]
- if {$h eq {}} return
- set pi [lindex $h 0]
- if {$pi == 0} {
- mark_ctext_line $diff_menu_line
- return
- }
- incr pi -1
- if {$currentid eq $nullid} {
- if {$pi > 0} {
- # must be a merge in progress...
- if {[catch {
- # get the last line from .git/MERGE_HEAD
- set f [open [file join $gitdir MERGE_HEAD] r]
- set id [lindex [split [read $f] "\n"] end-1]
- close $f
- } err]} {
- error_popup [mc "Couldn't read merge head: %s" $err]
- return
- }
- } elseif {$parents($curview,$currentid) eq $nullid2} {
- # need to do the blame from the index
- if {[catch {
- set from_index [index_sha1 $flist_menu_file]
- } err]} {
- error_popup [mc "Error reading index: %s" $err]
- return
- }
- } else {
- set id $parents($curview,$currentid)
- }
- } else {
- set id [lindex $parents($curview,$currentid) $pi]
- }
- set line [lindex $h 1]
+ set h [find_hunk_blamespec $diff_menu_filebase $diff_menu_line]
+ if {$h eq {}} return
+ set pi [lindex $h 0]
+ if {$pi == 0} {
+ mark_ctext_line $diff_menu_line
+ return
+ }
+ incr pi -1
+ if {$currentid eq $nullid} {
+ if {$pi > 0} {
+ # must be a merge in progress...
+ if {[catch {
+ # get the last line from .git/MERGE_HEAD
+ set f [open [file join $gitdir MERGE_HEAD] r]
+ set id [lindex [split [read $f] "\n"] end-1]
+ close $f
+ } err]} {
+ error_popup [mc "Couldn't read merge head: %s" $err]
+ return
+ }
+ } elseif {$parents($curview,$currentid) eq $nullid2} {
+ # need to do the blame from the index
+ if {[catch {
+ set from_index [index_sha1 $flist_menu_file]
+ } err]} {
+ error_popup [mc "Error reading index: %s" $err]
+ return
+ }
+ } else {
+ set id $parents($curview,$currentid)
+ }
+ } else {
+ set id [lindex $parents($curview,$currentid) $pi]
+ }
+ set line [lindex $h 1]
}
set blameargs {}
if {$from_index ne {}} {
- lappend blameargs | git cat-file blob $from_index
+ lappend blameargs | git cat-file blob $from_index
}
lappend blameargs | git blame -p -L$line,+1
if {$from_index ne {}} {
- lappend blameargs --contents -
+ lappend blameargs --contents -
} else {
- lappend blameargs $id
+ lappend blameargs $id
}
lappend blameargs -- [file join $cdup $flist_menu_file]
if {[catch {
- set f [open $blameargs r]
+ set f [open $blameargs r]
} err]} {
- error_popup [mc "Couldn't start git blame: %s" $err]
- return
+ error_popup [mc "Couldn't start git blame: %s" $err]
+ return
}
nowbusy blaming [mc "Searching"]
fconfigure $f -blocking 0
@@ -3900,9 +3918,9 @@ proc stopblaming {} {
global blameinst
if {[info exists blameinst]} {
- stop_instance $blameinst
- unset blameinst
- notbusy blaming
+ stop_instance $blameinst
+ unset blameinst
+ notbusy blaming
}
}
@@ -3910,18 +3928,18 @@ proc read_line_source {fd inst} {
global blamestuff curview commfd blameinst nullid nullid2
while {[gets $fd line] >= 0} {
- lappend blamestuff($inst) $line
+ lappend blamestuff($inst) $line
}
if {![eof $fd]} {
- return 1
+ return 1
}
unset commfd($inst)
unset blameinst
notbusy blaming
fconfigure $fd -blocking 1
if {[catch {close $fd} err]} {
- error_popup [mc "Error running git blame: %s" $err]
- return 0
+ error_popup [mc "Error running git blame: %s" $err]
+ return 0
}
set fname {}
@@ -3929,30 +3947,30 @@ proc read_line_source {fd inst} {
set id [lindex $line 0]
set lnum [lindex $line 1]
if {[string length $id] == 40 && [string is xdigit $id] &&
- [string is digit -strict $lnum]} {
- # look for "filename" line
- foreach l $blamestuff($inst) {
- if {[string match "filename *" $l]} {
- set fname [string range $l 9 end]
- break
- }
- }
+ [string is digit -strict $lnum]} {
+ # look for "filename" line
+ foreach l $blamestuff($inst) {
+ if {[string match "filename *" $l]} {
+ set fname [string range $l 9 end]
+ break
+ }
+ }
}
if {$fname ne {}} {
- # all looks good, select it
- if {$id eq $nullid} {
- # blame uses all-zeroes to mean not committed,
- # which would mean a change in the index
- set id $nullid2
- }
- if {[commitinview $id $curview]} {
- selectline [rowofcommit $id] 1 [list $fname $lnum] 1
- } else {
- error_popup [mc "That line comes from commit %s, \
- which is not in this view" [shortids $id]]
- }
+ # all looks good, select it
+ if {$id eq $nullid} {
+ # blame uses all-zeroes to mean not committed,
+ # which would mean a change in the index
+ set id $nullid2
+ }
+ if {[commitinview $id $curview]} {
+ selectline [rowofcommit $id] 1 [list $fname $lnum] 1
+ } else {
+ error_popup [mc "That line comes from commit %s, \
+ which is not in this view" [shortids $id]]
+ }
} else {
- puts "oops couldn't parse git blame output"
+ puts "oops couldn't parse git blame output"
}
return 0
}
@@ -3961,11 +3979,11 @@ proc read_line_source {fd inst} {
proc delete_at_eof {f dir} {
while {[gets $f line] >= 0} {}
if {[eof $f]} {
- if {[catch {close $f} err]} {
- error_popup "[mc "External diff viewer failed:"] $err"
- }
- file delete -force $dir
- return 0
+ if {[catch {close $f} err]} {
+ error_popup "[mc "External diff viewer failed:"] $err"
+ }
+ file delete -force $dir
+ return 0
}
return 1
}
@@ -3974,13 +3992,13 @@ proc delete_at_eof {f dir} {
proc shellquote {str} {
if {![string match "*\['\"\\ \t]*" $str]} {
- return $str
+ return $str
}
if {![string match "*\['\"\\]*" $str]} {
- return "\"$str\""
+ return "\"$str\""
}
if {![string match "*'*" $str]} {
- return "'$str'"
+ return "'$str'"
}
return "\"[string map {\" \\\" \\ \\\\} $str]\""
}
@@ -3988,10 +4006,10 @@ proc shellquote {str} {
proc shellarglist {l} {
set str {}
foreach a $l {
- if {$str ne {}} {
- append str " "
- }
- append str [shellquote $a]
+ if {$str ne {}} {
+ append str " "
+ }
+ append str [shellquote $a]
}
return $str
}
@@ -4000,52 +4018,52 @@ proc shelldequote {str} {
set ret {}
set used -1
while {1} {
- incr used
- if {![regexp -start $used -indices "\['\"\\\\ \t]" $str first]} {
- append ret [string range $str $used end]
- set used [string length $str]
- break
- }
- set first [lindex $first 0]
- set ch [string index $str $first]
- if {$first > $used} {
- append ret [string range $str $used [expr {$first - 1}]]
- set used $first
- }
- if {$ch eq " " || $ch eq "\t"} break
- incr used
- if {$ch eq "'"} {
- set first [string first "'" $str $used]
- if {$first < 0} {
- error "unmatched single-quote"
- }
- append ret [string range $str $used [expr {$first - 1}]]
- set used $first
- continue
- }
- if {$ch eq "\\"} {
- if {$used >= [string length $str]} {
- error "trailing backslash"
- }
- append ret [string index $str $used]
- continue
- }
- # here ch == "\""
- while {1} {
- if {![regexp -start $used -indices "\[\"\\\\]" $str first]} {
- error "unmatched double-quote"
- }
- set first [lindex $first 0]
- set ch [string index $str $first]
- if {$first > $used} {
- append ret [string range $str $used [expr {$first - 1}]]
- set used $first
- }
- if {$ch eq "\""} break
- incr used
- append ret [string index $str $used]
- incr used
- }
+ incr used
+ if {![regexp -start $used -indices "\['\"\\\\ \t]" $str first]} {
+ append ret [string range $str $used end]
+ set used [string length $str]
+ break
+ }
+ set first [lindex $first 0]
+ set ch [string index $str $first]
+ if {$first > $used} {
+ append ret [string range $str $used [expr {$first - 1}]]
+ set used $first
+ }
+ if {$ch eq " " || $ch eq "\t"} break
+ incr used
+ if {$ch eq "'"} {
+ set first [string first "'" $str $used]
+ if {$first < 0} {
+ error "unmatched single-quote"
+ }
+ append ret [string range $str $used [expr {$first - 1}]]
+ set used $first
+ continue
+ }
+ if {$ch eq "\\"} {
+ if {$used >= [string length $str]} {
+ error "trailing backslash"
+ }
+ append ret [string index $str $used]
+ continue
+ }
+ # here ch == "\""
+ while {1} {
+ if {![regexp -start $used -indices "\[\"\\\\]" $str first]} {
+ error "unmatched double-quote"
+ }
+ set first [lindex $first 0]
+ set ch [string index $str $first]
+ if {$first > $used} {
+ append ret [string range $str $used [expr {$first - 1}]]
+ set used $first
+ }
+ if {$ch eq "\""} break
+ incr used
+ append ret [string index $str $used]
+ incr used
+ }
}
return [list $used $ret]
}
@@ -4053,13 +4071,13 @@ proc shelldequote {str} {
proc shellsplit {str} {
set l {}
while {1} {
- set str [string trimleft $str]
- if {$str eq {}} break
- set dq [shelldequote $str]
- set n [lindex $dq 0]
- set word [lindex $dq 1]
- set str [string range $str $n end]
- lappend l $word
+ set str [string trimleft $str]
+ if {$str eq {}} break
+ set dq [shelldequote $str]
+ set n [lindex $dq 0]
+ set word [lindex $dq 1]
+ set str [string range $str $n end]
+ lappend l $word
}
return $l
}
@@ -4068,11 +4086,11 @@ proc set_window_title {} {
global appname curview viewname vrevs
set rev [mc "All files"]
if {$curview ne 0} {
- if {$viewname($curview) eq [mc "Command line"]} {
- set rev [string map {"--gitk-symmetric-diff-marker" "--merge"} $vrevs($curview)]
- } else {
- set rev $viewname($curview)
- }
+ if {$viewname($curview) eq [mc "Command line"]} {
+ set rev [string map {"--gitk-symmetric-diff-marker" "--merge"} $vrevs($curview)]
+ } else {
+ set rev $viewname($curview)
+ }
}
wm title . "[reponame]: $rev - $appname"
}
@@ -4086,8 +4104,8 @@ proc newview {ishighlight} {
set newishighlight $ishighlight
set top .gitkview
if {[winfo exists $top]} {
- raise $top
- return
+ raise $top
+ return
}
decode_view_opts $nextviewnum $revtreeargs
set newviewname($nextviewnum) "[mc "View"] $nextviewnum"
@@ -4136,29 +4154,29 @@ proc encode_view_opts {n} {
set rargs [list]
foreach opt $known_view_options {
- set patterns [lindex $opt 3]
- if {$patterns eq {}} continue
- set pattern [lindex $patterns 0]
-
- if {[lindex $opt 1] eq "b"} {
- set val $newviewopts($n,[lindex $opt 0])
- if {$val} {
- lappend rargs $pattern
- }
- } elseif {[regexp {^r(\d+)$} [lindex $opt 1] type value]} {
- regexp {^(.*_)} [lindex $opt 0] uselessvar button_id
- set val $newviewopts($n,$button_id)
- if {$val eq $value} {
- lappend rargs $pattern
- }
- } else {
- set val $newviewopts($n,[lindex $opt 0])
- set val [string trim $val]
- if {$val ne {}} {
- set pfix [string range $pattern 0 end-1]
- lappend rargs $pfix$val
- }
- }
+ set patterns [lindex $opt 3]
+ if {$patterns eq {}} continue
+ set pattern [lindex $patterns 0]
+
+ if {[lindex $opt 1] eq "b"} {
+ set val $newviewopts($n,[lindex $opt 0])
+ if {$val} {
+ lappend rargs $pattern
+ }
+ } elseif {[regexp {^r(\d+)$} [lindex $opt 1] type value]} {
+ regexp {^(.*_)} [lindex $opt 0] uselessvar button_id
+ set val $newviewopts($n,$button_id)
+ if {$val eq $value} {
+ lappend rargs $pattern
+ }
+ } else {
+ set val $newviewopts($n,[lindex $opt 0])
+ set val [string trim $val]
+ if {$val ne {}} {
+ set pfix [string range $pattern 0 end-1]
+ lappend rargs $pfix$val
+ }
+ }
}
set rargs [concat $rargs [shellsplit $newviewopts($n,refs)]]
return [concat $rargs [shellsplit $newviewopts($n,args)]]
@@ -4169,59 +4187,59 @@ proc decode_view_opts {n view_args} {
global known_view_options newviewopts
foreach opt $known_view_options {
- set id [lindex $opt 0]
- if {[lindex $opt 1] eq "b"} {
- # Checkboxes
- set val 0
+ set id [lindex $opt 0]
+ if {[lindex $opt 1] eq "b"} {
+ # Checkboxes
+ set val 0
} elseif {[regexp {^r(\d+)$} [lindex $opt 1]]} {
- # Radiobuttons
- regexp {^(.*_)} $id uselessvar id
- set val 0
- } else {
- # Text fields
- set val {}
- }
- set newviewopts($n,$id) $val
+ # Radiobuttons
+ regexp {^(.*_)} $id uselessvar id
+ set val 0
+ } else {
+ # Text fields
+ set val {}
+ }
+ set newviewopts($n,$id) $val
}
set oargs [list]
set refargs [list]
foreach arg $view_args {
- if {[regexp -- {^-([0-9]+)$} $arg arg cnt]
- && ![info exists found(limit)]} {
- set newviewopts($n,limit) $cnt
- set found(limit) 1
- continue
- }
- catch { unset val }
- foreach opt $known_view_options {
- set id [lindex $opt 0]
- if {[info exists found($id)]} continue
- foreach pattern [lindex $opt 3] {
- if {![string match $pattern $arg]} continue
- if {[lindex $opt 1] eq "b"} {
- # Check buttons
- set val 1
- } elseif {[regexp {^r(\d+)$} [lindex $opt 1] match num]} {
- # Radio buttons
- regexp {^(.*_)} $id uselessvar id
- set val $num
- } else {
- # Text input fields
- set size [string length $pattern]
- set val [string range $arg [expr {$size-1}] end]
- }
- set newviewopts($n,$id) $val
- set found($id) 1
- break
- }
- if {[info exists val]} break
- }
- if {[info exists val]} continue
- if {[regexp {^-} $arg]} {
- lappend oargs $arg
- } else {
- lappend refargs $arg
- }
+ if {[regexp -- {^-([0-9]+)$} $arg arg cnt]
+ && ![info exists found(limit)]} {
+ set newviewopts($n,limit) $cnt
+ set found(limit) 1
+ continue
+ }
+ catch { unset val }
+ foreach opt $known_view_options {
+ set id [lindex $opt 0]
+ if {[info exists found($id)]} continue
+ foreach pattern [lindex $opt 3] {
+ if {![string match $pattern $arg]} continue
+ if {[lindex $opt 1] eq "b"} {
+ # Check buttons
+ set val 1
+ } elseif {[regexp {^r(\d+)$} [lindex $opt 1] match num]} {
+ # Radio buttons
+ regexp {^(.*_)} $id uselessvar id
+ set val $num
+ } else {
+ # Text input fields
+ set size [string length $pattern]
+ set val [string range $arg [expr {$size-1}] end]
+ }
+ set newviewopts($n,$id) $val
+ set found($id) 1
+ break
+ }
+ if {[info exists val]} break
+ }
+ if {[info exists val]} continue
+ if {[regexp {^-} $arg]} {
+ lappend oargs $arg
+ } else {
+ lappend refargs $arg
+ }
}
set newviewopts($n,refs) [shellarglist $refargs]
set newviewopts($n,args) [shellarglist $oargs]
@@ -4231,9 +4249,9 @@ proc edit_or_newview {} {
global curview
if {$curview > 0} {
- editview
+ editview
} else {
- newview 0
+ newview 0
}
}
@@ -4244,8 +4262,8 @@ proc editview {} {
set top .gitkvedit-$curview
if {[winfo exists $top]} {
- raise $top
- return
+ raise $top
+ return
}
decode_view_opts $curview $viewargs($curview)
set newviewname($curview) $viewname($curview)
@@ -4275,66 +4293,66 @@ proc vieweditor {top n title} {
set cexpand 0
set cnt 0
foreach opt $known_view_options {
- set id [lindex $opt 0]
- set type [lindex $opt 1]
- set flags [lindex $opt 2]
- set title [eval [lindex $opt 4]]
- set lxpad 0
-
- if {$flags eq "+" || $flags eq "*"} {
- set cframe $top.fr$cnt
- incr cnt
- ${NS}::frame $cframe
- pack $cframe -in $top -fill x -pady 3 -padx 3
- set cexpand [expr {$flags eq "*"}]
+ set id [lindex $opt 0]
+ set type [lindex $opt 1]
+ set flags [lindex $opt 2]
+ set title [eval [lindex $opt 4]]
+ set lxpad 0
+
+ if {$flags eq "+" || $flags eq "*"} {
+ set cframe $top.fr$cnt
+ incr cnt
+ ${NS}::frame $cframe
+ pack $cframe -in $top -fill x -pady 3 -padx 3
+ set cexpand [expr {$flags eq "*"}]
} elseif {$flags eq ".." || $flags eq "*."} {
- set cframe $top.fr$cnt
- incr cnt
- ${NS}::frame $cframe
- pack $cframe -in $top -fill x -pady 3 -padx [list 15 3]
- set cexpand [expr {$flags eq "*."}]
- } else {
- set lxpad 5
- }
-
- if {$type eq "l"} {
+ set cframe $top.fr$cnt
+ incr cnt
+ ${NS}::frame $cframe
+ pack $cframe -in $top -fill x -pady 3 -padx [list 15 3]
+ set cexpand [expr {$flags eq "*."}]
+ } else {
+ set lxpad 5
+ }
+
+ if {$type eq "l"} {
${NS}::label $cframe.l_$id -text $title
pack $cframe.l_$id -in $cframe -side left -pady [list 3 0] -anchor w
- } elseif {$type eq "b"} {
- ${NS}::checkbutton $cframe.c_$id -text $title -variable newviewopts($n,$id)
- pack $cframe.c_$id -in $cframe -side left \
- -padx [list $lxpad 0] -expand $cexpand -anchor w
- } elseif {[regexp {^r(\d+)$} $type type sz]} {
- regexp {^(.*_)} $id uselessvar button_id
- ${NS}::radiobutton $cframe.c_$id -text $title -variable newviewopts($n,$button_id) -value $sz
- pack $cframe.c_$id -in $cframe -side left \
- -padx [list $lxpad 0] -expand $cexpand -anchor w
- } elseif {[regexp {^t(\d+)$} $type type sz]} {
- ${NS}::label $cframe.l_$id -text $title
- ${NS}::entry $cframe.e_$id -width $sz -background $bgcolor \
- -textvariable newviewopts($n,$id)
- pack $cframe.l_$id -in $cframe -side left -padx [list $lxpad 0]
- pack $cframe.e_$id -in $cframe -side left -expand 1 -fill x
- } elseif {[regexp {^t(\d+)=$} $type type sz]} {
- ${NS}::label $cframe.l_$id -text $title
- ${NS}::entry $cframe.e_$id -width $sz -background $bgcolor \
- -textvariable newviewopts($n,$id)
- pack $cframe.l_$id -in $cframe -side top -pady [list 3 0] -anchor w
- pack $cframe.e_$id -in $cframe -side top -fill x
- } elseif {$type eq "path"} {
- ${NS}::label $top.l -text $title
- pack $top.l -in $top -side top -pady [list 3 0] -anchor w -padx 3
- text $top.t -width 40 -height 5 -background $bgcolor
- if {[info exists viewfiles($n)]} {
- foreach f $viewfiles($n) {
- $top.t insert end $f
- $top.t insert end "\n"
- }
- $top.t delete {end - 1c} end
- $top.t mark set insert 0.0
- }
- pack $top.t -in $top -side top -pady [list 0 5] -fill both -expand 1 -padx 3
- }
+ } elseif {$type eq "b"} {
+ ${NS}::checkbutton $cframe.c_$id -text $title -variable newviewopts($n,$id)
+ pack $cframe.c_$id -in $cframe -side left \
+ -padx [list $lxpad 0] -expand $cexpand -anchor w
+ } elseif {[regexp {^r(\d+)$} $type type sz]} {
+ regexp {^(.*_)} $id uselessvar button_id
+ ${NS}::radiobutton $cframe.c_$id -text $title -variable newviewopts($n,$button_id) -value $sz
+ pack $cframe.c_$id -in $cframe -side left \
+ -padx [list $lxpad 0] -expand $cexpand -anchor w
+ } elseif {[regexp {^t(\d+)$} $type type sz]} {
+ ${NS}::label $cframe.l_$id -text $title
+ ${NS}::entry $cframe.e_$id -width $sz -background $bgcolor \
+ -textvariable newviewopts($n,$id)
+ pack $cframe.l_$id -in $cframe -side left -padx [list $lxpad 0]
+ pack $cframe.e_$id -in $cframe -side left -expand 1 -fill x
+ } elseif {[regexp {^t(\d+)=$} $type type sz]} {
+ ${NS}::label $cframe.l_$id -text $title
+ ${NS}::entry $cframe.e_$id -width $sz -background $bgcolor \
+ -textvariable newviewopts($n,$id)
+ pack $cframe.l_$id -in $cframe -side top -pady [list 3 0] -anchor w
+ pack $cframe.e_$id -in $cframe -side top -fill x
+ } elseif {$type eq "path"} {
+ ${NS}::label $top.l -text $title
+ pack $top.l -in $top -side top -pady [list 3 0] -anchor w -padx 3
+ text $top.t -width 40 -height 5 -background $bgcolor
+ if {[info exists viewfiles($n)]} {
+ foreach f $viewfiles($n) {
+ $top.t insert end $f
+ $top.t insert end "\n"
+ }
+ $top.t delete {end - 1c} end
+ $top.t mark set insert 0.0
+ }
+ pack $top.t -in $top -side top -pady [list 0 5] -fill both -expand 1 -padx 3
+ }
}
${NS}::frame $top.buts
@@ -4355,10 +4373,10 @@ proc vieweditor {top n title} {
proc doviewmenu {m first cmd op argv} {
set nmenu [$m index end]
for {set i $first} {$i <= $nmenu} {incr i} {
- if {[$m entrycget $i -command] eq $cmd} {
- eval $m $op $i $argv
- break
- }
+ if {[$m entrycget $i -command] eq $cmd} {
+ eval $m $op $i $argv
+ break
+ }
}
}
@@ -4375,53 +4393,53 @@ proc newviewok {top n {apply 0}} {
global viewargs viewargscmd newviewopts viewhlmenu
if {[catch {
- set newargs [encode_view_opts $n]
+ set newargs [encode_view_opts $n]
} err]} {
- error_popup "[mc "Error in commit selection arguments:"] $err" $top
- return
+ error_popup "[mc "Error in commit selection arguments:"] $err" $top
+ return
}
set files {}
foreach f [split [$top.t get 0.0 end] "\n"] {
- set ft [string trim $f]
- if {$ft ne {}} {
- lappend files $ft
- }
+ set ft [string trim $f]
+ if {$ft ne {}} {
+ lappend files $ft
+ }
}
if {![info exists viewfiles($n)]} {
- # creating a new view
- incr nextviewnum
- set viewname($n) $newviewname($n)
- set viewperm($n) $newviewopts($n,perm)
- set viewchanged($n) 1
- set viewfiles($n) $files
- set viewargs($n) $newargs
- set viewargscmd($n) $newviewopts($n,cmd)
- addviewmenu $n
- if {!$newishighlight} {
- run showview $n
- } else {
- run addvhighlight $n
- }
+ # creating a new view
+ incr nextviewnum
+ set viewname($n) $newviewname($n)
+ set viewperm($n) $newviewopts($n,perm)
+ set viewchanged($n) 1
+ set viewfiles($n) $files
+ set viewargs($n) $newargs
+ set viewargscmd($n) $newviewopts($n,cmd)
+ addviewmenu $n
+ if {!$newishighlight} {
+ run showview $n
+ } else {
+ run addvhighlight $n
+ }
} else {
- # editing an existing view
- set viewperm($n) $newviewopts($n,perm)
- set viewchanged($n) 1
- if {$newviewname($n) ne $viewname($n)} {
- set viewname($n) $newviewname($n)
- doviewmenu .bar.view 5 [list showview $n] \
- entryconf [list -label $viewname($n)]
- # doviewmenu $viewhlmenu 1 [list addvhighlight $n] \
- # entryconf [list -label $viewname($n) -value $viewname($n)]
- }
- if {$files ne $viewfiles($n) || $newargs ne $viewargs($n) || \
- $newviewopts($n,cmd) ne $viewargscmd($n)} {
- set viewfiles($n) $files
- set viewargs($n) $newargs
- set viewargscmd($n) $newviewopts($n,cmd)
- if {$curview == $n} {
- run reloadcommits
- }
- }
+ # editing an existing view
+ set viewperm($n) $newviewopts($n,perm)
+ set viewchanged($n) 1
+ if {$newviewname($n) ne $viewname($n)} {
+ set viewname($n) $newviewname($n)
+ doviewmenu .bar.view 5 [list showview $n] \
+ entryconf [list -label $viewname($n)]
+ # doviewmenu $viewhlmenu 1 [list addvhighlight $n] \
+ # entryconf [list -label $viewname($n) -value $viewname($n)]
+ }
+ if {$files ne $viewfiles($n) || $newargs ne $viewargs($n) || \
+ $newviewopts($n,cmd) ne $viewargscmd($n)} {
+ set viewfiles($n) $files
+ set viewargs($n) $newargs
+ set viewargscmd($n) $newviewopts($n,cmd)
+ if {$curview == $n} {
+ run reloadcommits
+ }
+ }
}
if {$apply} return
catch {destroy $top}
@@ -4432,8 +4450,8 @@ proc delview {} {
if {$curview == 0} return
if {[info exists hlview] && $hlview == $curview} {
- set selectedhlview [mc "None"]
- unset hlview
+ set selectedhlview [mc "None"]
+ unset hlview
}
allviewmenus $curview delete
set viewperm($curview) 0
@@ -4445,7 +4463,7 @@ proc addviewmenu {n} {
global viewname viewhlmenu
.bar.view add radiobutton -label $viewname($n) \
- -command [list showview $n] -variable selectedview -value $n
+ -command [list showview $n] -variable selectedview -value $n
#$viewhlmenu add radiobutton -label $viewname($n) \
# -command [list addvhighlight $n] -variable selectedhlview
}
@@ -4470,22 +4488,22 @@ proc showview {n} {
set ybot [expr {[lindex $span 1] * $ymax}]
set yscreen [expr {($ybot - $ytop) / 2}]
if {$selectedline ne {}} {
- set selid $currentid
- set y [yc $selectedline]
- if {$ytop < $y && $y < $ybot} {
- set yscreen [expr {$y - $ytop}]
- }
+ set selid $currentid
+ set y [yc $selectedline]
+ if {$ytop < $y && $y < $ybot} {
+ set yscreen [expr {$y - $ytop}]
+ }
} elseif {[info exists pending_select]} {
- set selid $pending_select
- unset pending_select
+ set selid $pending_select
+ unset pending_select
}
unselectline
normalline
unset -nocomplain treediffs
clear_display
if {[info exists hlview] && $hlview == $n} {
- unset hlview
- set selectedhlview [mc "None"]
+ unset hlview
+ set selectedhlview [mc "None"]
}
unset -nocomplain commitinterest
unset -nocomplain cached_commitrow
@@ -4498,8 +4516,8 @@ proc showview {n} {
run refill_reflist
if {![info exists viewcomplete($n)]} {
- getcommits $selid
- return
+ getcommits $selid
+ return
}
set displayorder {}
@@ -4519,39 +4537,39 @@ proc showview {n} {
set yf 0
set row {}
if {$selid ne {} && [commitinview $selid $n]} {
- set row [rowofcommit $selid]
- # try to get the selected row in the same position on the screen
- set ymax [lindex [$canv cget -scrollregion] 3]
- set ytop [expr {[yc $row] - $yscreen}]
- if {$ytop < 0} {
- set ytop 0
- }
- set yf [expr {$ytop * 1.0 / $ymax}]
+ set row [rowofcommit $selid]
+ # try to get the selected row in the same position on the screen
+ set ymax [lindex [$canv cget -scrollregion] 3]
+ set ytop [expr {[yc $row] - $yscreen}]
+ if {$ytop < 0} {
+ set ytop 0
+ }
+ set yf [expr {$ytop * 1.0 / $ymax}]
}
allcanvs yview moveto $yf
drawvisible
if {$row ne {}} {
- selectline $row 0
+ selectline $row 0
} elseif {!$viewcomplete($n)} {
- reset_pending_select $selid
+ reset_pending_select $selid
} else {
- reset_pending_select {}
+ reset_pending_select {}
- if {[commitinview $pending_select $curview]} {
- selectline [rowofcommit $pending_select] 1
- } else {
- set row [first_real_row]
- if {$row < $numcommits} {
- selectline $row 0
- }
- }
+ if {[commitinview $pending_select $curview]} {
+ selectline [rowofcommit $pending_select] 1
+ } else {
+ set row [first_real_row]
+ if {$row < $numcommits} {
+ selectline $row 0
+ }
+ }
}
if {!$viewcomplete($n)} {
- if {$numcommits == 0} {
- show_status [mc "Reading commits..."]
- }
+ if {$numcommits == 0} {
+ show_status [mc "Reading commits..."]
+ }
} elseif {$numcommits == 0} {
- show_status [mc "No commits selected"]
+ show_status [mc "No commits selected"]
}
set_window_title
}
@@ -4562,16 +4580,16 @@ proc ishighlighted {id} {
global vhighlights fhighlights nhighlights rhighlights
if {[info exists nhighlights($id)] && $nhighlights($id) > 0} {
- return $nhighlights($id)
+ return $nhighlights($id)
}
if {[info exists vhighlights($id)] && $vhighlights($id) > 0} {
- return $vhighlights($id)
+ return $vhighlights($id)
}
if {[info exists fhighlights($id)] && $fhighlights($id) > 0} {
- return $fhighlights($id)
+ return $fhighlights($id)
}
if {[info exists rhighlights($id)] && $rhighlights($id) > 0} {
- return $rhighlights($id)
+ return $rhighlights($id)
}
return 0
}
@@ -4584,14 +4602,14 @@ proc bolden {id font} {
lappend boldids $id
$canv itemconf $linehtag($id) -font $font
if {[info exists currentid] && $id eq $currentid} {
- $canv delete secsel
- set t [eval $canv create rect [$canv bbox $linehtag($id)] \
- -outline {{}} -tags secsel \
- -fill [$canv cget -selectbackground]]
- $canv lower $t
+ $canv delete secsel
+ set t [eval $canv create rect [$canv bbox $linehtag($id)] \
+ -outline {{}} -tags secsel \
+ -fill [$canv cget -selectbackground]]
+ $canv lower $t
}
if {[info exists markedid] && $id eq $markedid} {
- make_idmark $id
+ make_idmark $id
}
}
@@ -4602,11 +4620,11 @@ proc bolden_name {id font} {
lappend boldnameids $id
$canv2 itemconf $linentag($id) -font $font
if {[info exists currentid] && $id eq $currentid} {
- $canv2 delete secsel
- set t [eval $canv2 create rect [$canv2 bbox $linentag($id)] \
- -outline {{}} -tags secsel \
- -fill [$canv2 cget -selectbackground]]
- $canv2 lower $t
+ $canv2 delete secsel
+ set t [eval $canv2 create rect [$canv2 bbox $linentag($id)] \
+ -outline {{}} -tags secsel \
+ -fill [$canv2 cget -selectbackground]]
+ $canv2 lower $t
}
}
@@ -4615,11 +4633,11 @@ proc unbolden {} {
set stillbold {}
foreach id $boldids {
- if {![ishighlighted $id]} {
- bolden $id mainfont
- } else {
- lappend stillbold $id
- }
+ if {![ishighlighted $id]} {
+ bolden $id mainfont
+ } else {
+ lappend stillbold $id
+ }
}
set boldids $stillbold
}
@@ -4628,15 +4646,15 @@ proc addvhighlight {n} {
global hlview viewcomplete curview vhl_done commitidx
if {[info exists hlview]} {
- delvhighlight
+ delvhighlight
}
set hlview $n
if {$n != $curview && ![info exists viewcomplete($n)]} {
- start_rev_list $n
+ start_rev_list $n
}
set vhl_done $commitidx($hlview)
if {$vhl_done > 0} {
- drawvisible
+ drawvisible
}
}
@@ -4657,16 +4675,16 @@ proc vhighlightmore {} {
set r0 [lindex $vr 0]
set r1 [lindex $vr 1]
for {set i $vhl_done} {$i < $max} {incr i} {
- set id [commitonrow $i $hlview]
- if {[commitinview $id $curview]} {
- set row [rowofcommit $id]
- if {$r0 <= $row && $row <= $r1} {
- if {![highlighted $row]} {
- bolden $id mainfontbold
- }
- set vhighlights($id) 1
- }
- }
+ set id [commitonrow $i $hlview]
+ if {[commitinview $id $curview]} {
+ set row [rowofcommit $id]
+ if {$r0 <= $row && $row <= $r1} {
+ if {![highlighted $row]} {
+ bolden $id mainfontbold
+ }
+ set vhighlights($id) 1
+ }
+ }
}
set vhl_done $max
return 0
@@ -4676,12 +4694,12 @@ proc askvhighlight {row id} {
global hlview vhighlights iddrawn
if {[commitinview $id $hlview]} {
- if {[info exists iddrawn($id)] && ![ishighlighted $id]} {
- bolden $id mainfontbold
- }
- set vhighlights($id) 1
+ if {[info exists iddrawn($id)] && ![ishighlighted $id]} {
+ bolden $id mainfontbold
+ }
+ set vhighlights($id) 1
} else {
- set vhighlights($id) 0
+ set vhighlights($id) 0
}
}
@@ -4690,18 +4708,18 @@ proc hfiles_change {} {
global highlight_paths
if {[info exists filehighlight]} {
- # delete previous highlights
- catch {close $filehighlight}
- unset filehighlight
- unset -nocomplain fhighlights
- unbolden
- unhighlight_filelist
+ # delete previous highlights
+ catch {close $filehighlight}
+ unset filehighlight
+ unset -nocomplain fhighlights
+ unbolden
+ unhighlight_filelist
}
set highlight_paths {}
after cancel do_file_hl $fh_serial
incr fh_serial
if {$highlight_files ne {}} {
- after 300 do_file_hl $fh_serial
+ after 300 do_file_hl $fh_serial
}
}
@@ -4710,21 +4728,21 @@ proc gdttype_change {name ix op} {
stopfinding
if {$findstring ne {}} {
- if {$gdttype eq [mc "containing:"]} {
- if {$highlight_files ne {}} {
- set highlight_files {}
- hfiles_change
- }
- findcom_change
- } else {
- if {$findpattern ne {}} {
- set findpattern {}
- findcom_change
- }
- set highlight_files $findstring
- hfiles_change
- }
- drawvisible
+ if {$gdttype eq [mc "containing:"]} {
+ if {$highlight_files ne {}} {
+ set highlight_files {}
+ hfiles_change
+ }
+ findcom_change
+ } else {
+ if {$findpattern ne {}} {
+ set findpattern {}
+ findcom_change
+ }
+ set highlight_files $findstring
+ hfiles_change
+ }
+ drawvisible
}
# enable/disable findtype/findloc menus too
}
@@ -4734,12 +4752,12 @@ proc find_change {name ix op} {
stopfinding
if {$gdttype eq [mc "containing:"]} {
- findcom_change
+ findcom_change
} else {
- if {$highlight_files ne $findstring} {
- set highlight_files $findstring
- hfiles_change
- }
+ if {$highlight_files ne $findstring} {
+ set highlight_files $findstring
+ hfiles_change
+ }
}
drawvisible
}
@@ -4751,33 +4769,33 @@ proc findcom_change args {
stopfinding
# delete previous highlights, if any
foreach id $boldnameids {
- bolden_name $id mainfont
+ bolden_name $id mainfont
}
set boldnameids {}
unset -nocomplain nhighlights
unbolden
unmarkmatches
if {$gdttype ne [mc "containing:"] || $findstring eq {}} {
- set findpattern {}
+ set findpattern {}
} elseif {$findtype eq [mc "Regexp"]} {
- set findpattern $findstring
+ set findpattern $findstring
} else {
- set e [string map {"*" "\\*" "?" "\\?" "\[" "\\\[" "\\" "\\\\"} \
- $findstring]
- set findpattern "*$e*"
+ set e [string map {"*" "\\*" "?" "\\?" "\[" "\\\[" "\\" "\\\\"} \
+ $findstring]
+ set findpattern "*$e*"
}
}
proc makepatterns {l} {
set ret {}
foreach e $l {
- set ee [string map {"*" "\\*" "?" "\\?" "\[" "\\\[" "\\" "\\\\"} $e]
- if {[string index $ee end] eq "/"} {
- lappend ret "$ee*"
- } else {
- lappend ret $ee
- lappend ret "$ee/*"
- }
+ set ee [string map {"*" "\\*" "?" "\\?" "\[" "\\\[" "\\" "\\\\"} $e]
+ if {[string index $ee end] eq "/"} {
+ lappend ret "$ee*"
+ } else {
+ lappend ret $ee
+ lappend ret "$ee/*"
+ }
}
return $ret
}
@@ -4787,26 +4805,26 @@ proc do_file_hl {serial} {
global cdup findtype
if {$gdttype eq [mc "touching paths:"]} {
- # If "exact" match then convert backslashes to forward slashes.
- # Most useful to support Windows-flavoured file paths.
- if {$findtype eq [mc "Exact"]} {
- set highlight_files [string map {"\\" "/"} $highlight_files]
- }
- if {[catch {set paths [shellsplit $highlight_files]}]} return
- set highlight_paths [makepatterns $paths]
- highlight_filelist
- set relative_paths {}
- foreach path $paths {
- lappend relative_paths [file join $cdup $path]
- }
- set gdtargs [concat -- $relative_paths]
+ # If "exact" match then convert backslashes to forward slashes.
+ # Most useful to support Windows-flavoured file paths.
+ if {$findtype eq [mc "Exact"]} {
+ set highlight_files [string map {"\\" "/"} $highlight_files]
+ }
+ if {[catch {set paths [shellsplit $highlight_files]}]} return
+ set highlight_paths [makepatterns $paths]
+ highlight_filelist
+ set relative_paths {}
+ foreach path $paths {
+ lappend relative_paths [file join $cdup $path]
+ }
+ set gdtargs [concat -- $relative_paths]
} elseif {$gdttype eq [mc "adding/removing string:"]} {
- set gdtargs [list "-S$highlight_files"]
+ set gdtargs [list "-S$highlight_files"]
} elseif {$gdttype eq [mc "changing lines matching:"]} {
- set gdtargs [list "-G$highlight_files"]
+ set gdtargs [list "-G$highlight_files"]
} else {
- # must be "containing:", i.e. we're searching commit info
- return
+ # must be "containing:", i.e. we're searching commit info
+ return
}
set cmd [concat | git diff-tree -r -s --stdin $gdtargs]
set filehighlight [open $cmd r+]
@@ -4821,9 +4839,9 @@ proc flushhighlights {} {
global filehighlight fhl_list
if {[info exists filehighlight]} {
- lappend fhl_list {}
- puts $filehighlight ""
- flush $filehighlight
+ lappend fhl_list {}
+ puts $filehighlight ""
+ flush $filehighlight
}
}
@@ -4840,34 +4858,34 @@ proc readfhighlight {} {
global fhl_list find_dirn
if {![info exists filehighlight]} {
- return 0
+ return 0
}
set nr 0
while {[incr nr] <= 100 && [gets $filehighlight line] >= 0} {
- set line [string trim $line]
- set i [lsearch -exact $fhl_list $line]
- if {$i < 0} continue
- for {set j 0} {$j < $i} {incr j} {
- set id [lindex $fhl_list $j]
- set fhighlights($id) 0
- }
- set fhl_list [lrange $fhl_list [expr {$i+1}] end]
- if {$line eq {}} continue
- if {![commitinview $line $curview]} continue
- if {[info exists iddrawn($line)] && ![ishighlighted $line]} {
- bolden $line mainfontbold
- }
- set fhighlights($line) 1
+ set line [string trim $line]
+ set i [lsearch -exact $fhl_list $line]
+ if {$i < 0} continue
+ for {set j 0} {$j < $i} {incr j} {
+ set id [lindex $fhl_list $j]
+ set fhighlights($id) 0
+ }
+ set fhl_list [lrange $fhl_list [expr {$i+1}] end]
+ if {$line eq {}} continue
+ if {![commitinview $line $curview]} continue
+ if {[info exists iddrawn($line)] && ![ishighlighted $line]} {
+ bolden $line mainfontbold
+ }
+ set fhighlights($line) 1
}
if {[eof $filehighlight]} {
- # strange...
- puts "oops, git diff-tree died"
- catch {close $filehighlight}
- unset filehighlight
- return 0
+ # strange...
+ puts "oops, git diff-tree died"
+ catch {close $filehighlight}
+ unset filehighlight
+ return 0
}
if {[info exists find_dirn]} {
- run findmore
+ run findmore
}
return 1
}
@@ -4876,11 +4894,11 @@ proc doesmatch {f} {
global findtype findpattern
if {$findtype eq [mc "Regexp"]} {
- return [regexp $findpattern $f]
+ return [regexp $findpattern $f]
} elseif {$findtype eq [mc "IgnCase"]} {
- return [string match -nocase $findpattern $f]
+ return [string match -nocase $findpattern $f]
} else {
- return [string match $findpattern $f]
+ return [string match $findpattern $f]
}
}
@@ -4890,32 +4908,32 @@ proc askfindhighlight {row id} {
global markingmatches
if {![info exists commitinfo($id)]} {
- getcommit $id
+ getcommit $id
}
set info $commitinfo($id)
set isbold 0
set fldtypes [list [mc Headline] [mc Author] "" [mc Committer] "" [mc Comments]]
foreach f $info ty $fldtypes {
- if {$ty eq ""} continue
- if {($findloc eq [mc "All fields"] || $findloc eq $ty) &&
- [doesmatch $f]} {
- if {$ty eq [mc "Author"]} {
- set isbold 2
- break
- }
- set isbold 1
- }
+ if {$ty eq ""} continue
+ if {($findloc eq [mc "All fields"] || $findloc eq $ty) &&
+ [doesmatch $f]} {
+ if {$ty eq [mc "Author"]} {
+ set isbold 2
+ break
+ }
+ set isbold 1
+ }
}
if {$isbold && [info exists iddrawn($id)]} {
- if {![ishighlighted $id]} {
- bolden $id mainfontbold
- if {$isbold > 1} {
- bolden_name $id mainfontbold
- }
- }
- if {$markingmatches} {
- markrowmatches $row $id
- }
+ if {![ishighlighted $id]} {
+ bolden $id mainfontbold
+ if {$isbold > 1} {
+ bolden_name $id mainfontbold
+ }
+ }
+ if {$markingmatches} {
+ markrowmatches $row $id
+ }
}
set nhighlights($id) $isbold
}
@@ -4928,18 +4946,18 @@ proc markrowmatches {row id} {
$canv delete match$row
$canv2 delete match$row
if {$findloc eq [mc "All fields"] || $findloc eq [mc "Headline"]} {
- set m [findmatches $headline]
- if {$m ne {}} {
- markmatches $canv $row $headline $linehtag($id) $m \
- [$canv itemcget $linehtag($id) -font] $row
- }
+ set m [findmatches $headline]
+ if {$m ne {}} {
+ markmatches $canv $row $headline $linehtag($id) $m \
+ [$canv itemcget $linehtag($id) -font] $row
+ }
}
if {$findloc eq [mc "All fields"] || $findloc eq [mc "Author"]} {
- set m [findmatches $author]
- if {$m ne {}} {
- markmatches $canv2 $row $author $linentag($id) $m \
- [$canv2 itemcget $linentag($id) -font] $row
- }
+ set m [findmatches $author]
+ if {$m ne {}} {
+ markmatches $canv2 $row $author $linentag($id) $m \
+ [$canv2 itemcget $linentag($id) -font] $row
+ }
}
}
@@ -4948,7 +4966,7 @@ proc vrel_change {name ix op} {
rhighlight_none
if {$highlight_related ne [mc "None"]} {
- run drawvisible
+ run drawvisible
}
}
@@ -4962,8 +4980,8 @@ proc rhighlight_sel {a} {
unset -nocomplain ancestor
set anc_todo [list $a]
if {$highlight_related ne [mc "None"]} {
- rhighlight_none
- run drawvisible
+ rhighlight_none
+ run drawvisible
}
}
@@ -4983,24 +5001,24 @@ proc is_descendent {a} {
set leftover {}
set done 0
for {set i 0} {$i < [llength $todo]} {incr i} {
- set do [lindex $todo $i]
- if {[rowofcommit $do] < $la} {
- lappend leftover $do
- continue
- }
- foreach nk $children($v,$do) {
- if {![info exists descendent($nk)]} {
- set descendent($nk) 1
- lappend todo $nk
- if {$nk eq $a} {
- set done 1
- }
- }
- }
- if {$done} {
- set desc_todo [concat $leftover [lrange $todo [expr {$i+1}] end]]
- return
- }
+ set do [lindex $todo $i]
+ if {[rowofcommit $do] < $la} {
+ lappend leftover $do
+ continue
+ }
+ foreach nk $children($v,$do) {
+ if {![info exists descendent($nk)]} {
+ set descendent($nk) 1
+ lappend todo $nk
+ if {$nk eq $a} {
+ set done 1
+ }
+ }
+ }
+ if {$done} {
+ set desc_todo [concat $leftover [lrange $todo [expr {$i+1}] end]]
+ return
+ }
}
set descendent($a) 0
set desc_todo $leftover
@@ -5015,24 +5033,24 @@ proc is_ancestor {a} {
set leftover {}
set done 0
for {set i 0} {$i < [llength $todo]} {incr i} {
- set do [lindex $todo $i]
- if {![commitinview $do $v] || [rowofcommit $do] > $la} {
- lappend leftover $do
- continue
- }
- foreach np $parents($v,$do) {
- if {![info exists ancestor($np)]} {
- set ancestor($np) 1
- lappend todo $np
- if {$np eq $a} {
- set done 1
- }
- }
- }
- if {$done} {
- set anc_todo [concat $leftover [lrange $todo [expr {$i+1}] end]]
- return
- }
+ set do [lindex $todo $i]
+ if {![commitinview $do $v] || [rowofcommit $do] > $la} {
+ lappend leftover $do
+ continue
+ }
+ foreach np $parents($v,$do) {
+ if {![info exists ancestor($np)]} {
+ set ancestor($np) 1
+ lappend todo $np
+ if {$np eq $a} {
+ set done 1
+ }
+ }
+ }
+ if {$done} {
+ set anc_todo [concat $leftover [lrange $todo [expr {$i+1}] end]]
+ return
+ }
}
set ancestor($a) 0
set anc_todo $leftover
@@ -5045,26 +5063,26 @@ proc askrelhighlight {row id} {
if {$selectedline eq {}} return
set isbold 0
if {$highlight_related eq [mc "Descendant"] ||
- $highlight_related eq [mc "Not descendant"]} {
- if {![info exists descendent($id)]} {
- is_descendent $id
- }
- if {$descendent($id) == ($highlight_related eq [mc "Descendant"])} {
- set isbold 1
- }
+ $highlight_related eq [mc "Not descendant"]} {
+ if {![info exists descendent($id)]} {
+ is_descendent $id
+ }
+ if {$descendent($id) == ($highlight_related eq [mc "Descendant"])} {
+ set isbold 1
+ }
} elseif {$highlight_related eq [mc "Ancestor"] ||
- $highlight_related eq [mc "Not ancestor"]} {
- if {![info exists ancestor($id)]} {
- is_ancestor $id
- }
- if {$ancestor($id) == ($highlight_related eq [mc "Ancestor"])} {
- set isbold 1
- }
+ $highlight_related eq [mc "Not ancestor"]} {
+ if {![info exists ancestor($id)]} {
+ is_ancestor $id
+ }
+ if {$ancestor($id) == ($highlight_related eq [mc "Ancestor"])} {
+ set isbold 1
+ }
}
if {[info exists iddrawn($id)]} {
- if {$isbold && ![ishighlighted $id]} {
- bolden $id mainfontbold
- }
+ if {$isbold && ![ishighlighted $id]} {
+ bolden $id mainfontbold
+ }
}
set rhighlights($id) $isbold
}
@@ -5074,13 +5092,13 @@ proc askrelhighlight {row id} {
proc shortids {ids} {
set res {}
foreach id $ids {
- if {[llength $id] > 1} {
- lappend res [shortids $id]
- } elseif {[regexp {^[0-9a-f]{40}$} $id]} {
- lappend res [string range $id 0 7]
- } else {
- lappend res $id
- }
+ if {[llength $id] > 1} {
+ lappend res [shortids $id]
+ } elseif {[regexp {^[0-9a-f]{40}$} $id]} {
+ lappend res [string range $id 0 7]
+ } else {
+ lappend res $id
+ }
}
return $res
}
@@ -5089,10 +5107,10 @@ proc ntimes {n o} {
set ret {}
set o [list $o]
for {set mask 1} {$mask <= $n} {incr mask $mask} {
- if {($n & $mask) != 0} {
- set ret [concat $ret $o]
- }
- set o [concat $o $o]
+ if {($n & $mask) != 0} {
+ set ret [concat $ret $o]
+ }
+ set o [concat $o $o]
}
return $ret
}
@@ -5102,41 +5120,41 @@ proc ordertoken {id} {
global nullid nullid2
if {[info exists ordertok($id)]} {
- return $ordertok($id)
+ return $ordertok($id)
}
set origid $id
set todo {}
while {1} {
- if {[info exists varcid($curview,$id)]} {
- set a $varcid($curview,$id)
- set p [lindex $varcstart($curview) $a]
- } else {
- set p [lindex $children($curview,$id) 0]
- }
- if {[info exists ordertok($p)]} {
- set tok $ordertok($p)
- break
- }
- set id [first_real_child $curview,$p]
- if {$id eq {}} {
- # it's a root
- set tok [lindex $varctok($curview) $varcid($curview,$p)]
- break
- }
- if {[llength $parents($curview,$id)] == 1} {
- lappend todo [list $p {}]
- } else {
- set j [lsearch -exact $parents($curview,$id) $p]
- if {$j < 0} {
- puts "oops didn't find [shortids $p] in parents of [shortids $id]"
- }
- lappend todo [list $p [strrep $j]]
- }
+ if {[info exists varcid($curview,$id)]} {
+ set a $varcid($curview,$id)
+ set p [lindex $varcstart($curview) $a]
+ } else {
+ set p [lindex $children($curview,$id) 0]
+ }
+ if {[info exists ordertok($p)]} {
+ set tok $ordertok($p)
+ break
+ }
+ set id [first_real_child $curview,$p]
+ if {$id eq {}} {
+ # it's a root
+ set tok [lindex $varctok($curview) $varcid($curview,$p)]
+ break
+ }
+ if {[llength $parents($curview,$id)] == 1} {
+ lappend todo [list $p {}]
+ } else {
+ set j [lsearch -exact $parents($curview,$id) $p]
+ if {$j < 0} {
+ puts "oops didn't find [shortids $p] in parents of [shortids $id]"
+ }
+ lappend todo [list $p [strrep $j]]
+ }
}
for {set i [llength $todo]} {[incr i -1] >= 0} {} {
- set p [lindex $todo $i 0]
- append tok [lindex $todo $i 1]
- set ordertok($p) $tok
+ set p [lindex $todo $i 0]
+ append tok [lindex $todo $i 1]
+ set ordertok($p) $tok
}
set ordertok($origid) $tok
return $tok
@@ -5147,19 +5165,19 @@ proc ordertoken {id} {
proc idcol {idlist id {i 0}} {
set t [ordertoken $id]
if {$i < 0} {
- set i 0
+ set i 0
}
if {$i >= [llength $idlist] || $t < [ordertoken [lindex $idlist $i]]} {
- if {$i > [llength $idlist]} {
- set i [llength $idlist]
- }
- while {[incr i -1] >= 0 && $t < [ordertoken [lindex $idlist $i]]} {}
- incr i
+ if {$i > [llength $idlist]} {
+ set i [llength $idlist]
+ }
+ while {[incr i -1] >= 0 && $t < [ordertoken [lindex $idlist $i]]} {}
+ incr i
} else {
- if {$t > [ordertoken [lindex $idlist $i]]} {
- while {[incr i] < [llength $idlist] &&
- $t >= [ordertoken [lindex $idlist $i]]} {}
- }
+ if {$t > [ordertoken [lindex $idlist $i]]} {
+ while {[incr i] < [llength $idlist] &&
+ $t >= [ordertoken [lindex $idlist $i]]} {}
+ }
}
return $i
}
@@ -5204,12 +5222,12 @@ proc visiblerows {} {
set y0 [expr {int([lindex $f 0] * $ymax)}]
set r0 [expr {int(($y0 - 3) / $linespc) - 1}]
if {$r0 < 0} {
- set r0 0
+ set r0 0
}
set y1 [expr {int([lindex $f 1] * $ymax)}]
set r1 [expr {int(($y1 - 3) / $linespc) + 1}]
if {$r1 >= $numcommits} {
- set r1 [expr {$numcommits - 1}]
+ set r1 [expr {$numcommits - 1}]
}
return [list $r0 $r1]
}
@@ -5220,13 +5238,13 @@ proc layoutmore {} {
global lastscrollset lastscrollrows
if {$lastscrollrows < 100 || $viewcomplete($curview) ||
- [clock clicks -milliseconds] - $lastscrollset > 500} {
- setcanvscroll
+ [clock clicks -milliseconds] - $lastscrollset > 500} {
+ setcanvscroll
}
if {[info exists pending_select] &&
- [commitinview $pending_select $curview]} {
- update
- selectline [rowofcommit $pending_select] 1
+ [commitinview $pending_select $curview]} {
+ update
+ selectline [rowofcommit $pending_select] 1
}
drawvisible
}
@@ -5238,13 +5256,13 @@ proc get_viewmainhead {view} {
global viewmainheadid vfilelimit viewinstances mainheadid
catch {
- set rfd [open [concat | git rev-list -1 $mainheadid \
- -- $vfilelimit($view)] r]
- set j [reg_instance $rfd]
- lappend viewinstances($view) $j
- fconfigure $rfd -blocking 0
- filerun $rfd [list getviewhead $rfd $j $view]
- set viewmainheadid($curview) {}
+ set rfd [open [concat | git rev-list -1 $mainheadid \
+ -- $vfilelimit($view)] r]
+ set j [reg_instance $rfd]
+ lappend viewinstances($view) $j
+ fconfigure $rfd -blocking 0
+ filerun $rfd [list getviewhead $rfd $j $view]
+ set viewmainheadid($curview) {}
}
}
@@ -5254,21 +5272,21 @@ proc getviewhead {fd inst view} {
set id {}
if {[gets $fd line] < 0} {
- if {![eof $fd]} {
- return 1
- }
+ if {![eof $fd]} {
+ return 1
+ }
} elseif {[string length $line] == 40 && [string is xdigit $line]} {
- set id $line
+ set id $line
}
set viewmainheadid($view) $id
close $fd
unset commfd($inst)
set i [lsearch -exact $viewinstances($view) $inst]
if {$i >= 0} {
- set viewinstances($view) [lreplace $viewinstances($view) $i $i]
+ set viewinstances($view) [lreplace $viewinstances($view) $i $i]
}
if {$showlocalchanges && $id ne {} && $view == $curview} {
- doshowlocalchanges
+ doshowlocalchanges
}
return 0
}
@@ -5278,9 +5296,9 @@ proc doshowlocalchanges {} {
if {$viewmainheadid($curview) eq {}} return
if {[commitinview $viewmainheadid($curview) $curview]} {
- dodiffindex
+ dodiffindex
} else {
- interestedin $viewmainheadid($curview) dodiffindex
+ interestedin $viewmainheadid($curview) dodiffindex
}
}
@@ -5288,10 +5306,10 @@ proc dohidelocalchanges {} {
global nullid nullid2 lserial curview
if {[commitinview $nullid $curview]} {
- removefakerow $nullid
+ removefakerow $nullid
}
if {[commitinview $nullid2 $curview]} {
- removefakerow $nullid2
+ removefakerow $nullid2
}
incr lserial
}
@@ -5304,12 +5322,12 @@ proc dodiffindex {} {
if {!$showlocalchanges || !$hasworktree} return
incr lserial
if {[package vcompare $git_version "1.7.2"] >= 0} {
- set cmd "|git diff-index --cached --ignore-submodules=dirty HEAD"
+ set cmd "|git diff-index --cached --ignore-submodules=dirty HEAD"
} else {
- set cmd "|git diff-index --cached HEAD"
+ set cmd "|git diff-index --cached HEAD"
}
if {$vfilelimit($curview) ne {}} {
- set cmd [concat $cmd -- $vfilelimit($curview)]
+ set cmd [concat $cmd -- $vfilelimit($curview)]
}
set fd [open $cmd r]
fconfigure $fd -blocking 0
@@ -5323,22 +5341,22 @@ proc readdiffindex {fd serial inst} {
set isdiff 1
if {[gets $fd line] < 0} {
- if {![eof $fd]} {
- return 1
- }
- set isdiff 0
+ if {![eof $fd]} {
+ return 1
+ }
+ set isdiff 0
}
# we only need to see one line and we don't really care what it says...
stop_instance $inst
if {$serial != $lserial} {
- return 0
+ return 0
}
# now see if there are any local changes not checked in to the index
set cmd "|git diff-files"
if {$vfilelimit($curview) ne {}} {
- set cmd [concat $cmd -- $vfilelimit($curview)]
+ set cmd [concat $cmd -- $vfilelimit($curview)]
}
set fd [open $cmd r]
fconfigure $fd -blocking 0
@@ -5346,19 +5364,19 @@ proc readdiffindex {fd serial inst} {
filerun $fd [list readdifffiles $fd $serial $i]
if {$isdiff && ![commitinview $nullid2 $curview]} {
- # add the line for the changes in the index to the graph
- set hl [mc "Local changes checked in to index but not committed"]
- set commitinfo($nullid2) [list $hl {} {} {} {} " $hl\n"]
- set commitdata($nullid2) "\n $hl\n"
- if {[commitinview $nullid $curview]} {
- removefakerow $nullid
- }
- insertfakerow $nullid2 $viewmainheadid($curview)
+ # add the line for the changes in the index to the graph
+ set hl [mc "Local changes checked in to index but not committed"]
+ set commitinfo($nullid2) [list $hl {} {} {} {} " $hl\n"]
+ set commitdata($nullid2) "\n $hl\n"
+ if {[commitinview $nullid $curview]} {
+ removefakerow $nullid
+ }
+ insertfakerow $nullid2 $viewmainheadid($curview)
} elseif {!$isdiff && [commitinview $nullid2 $curview]} {
- if {[commitinview $nullid $curview]} {
- removefakerow $nullid
- }
- removefakerow $nullid2
+ if {[commitinview $nullid $curview]} {
+ removefakerow $nullid
+ }
+ removefakerow $nullid2
}
return 0
}
@@ -5369,31 +5387,31 @@ proc readdifffiles {fd serial inst} {
set isdiff 1
if {[gets $fd line] < 0} {
- if {![eof $fd]} {
- return 1
- }
- set isdiff 0
+ if {![eof $fd]} {
+ return 1
+ }
+ set isdiff 0
}
# we only need to see one line and we don't really care what it says...
stop_instance $inst
if {$serial != $lserial} {
- return 0
+ return 0
}
if {$isdiff && ![commitinview $nullid $curview]} {
- # add the line for the local diff to the graph
- set hl [mc "Local uncommitted changes, not checked in to index"]
- set commitinfo($nullid) [list $hl {} {} {} {} " $hl\n"]
- set commitdata($nullid) "\n $hl\n"
- if {[commitinview $nullid2 $curview]} {
- set p $nullid2
- } else {
- set p $viewmainheadid($curview)
- }
- insertfakerow $nullid $p
+ # add the line for the local diff to the graph
+ set hl [mc "Local uncommitted changes, not checked in to index"]
+ set commitinfo($nullid) [list $hl {} {} {} {} " $hl\n"]
+ set commitdata($nullid) "\n $hl\n"
+ if {[commitinview $nullid2 $curview]} {
+ set p $nullid2
+ } else {
+ set p $viewmainheadid($curview)
+ }
+ insertfakerow $nullid $p
} elseif {!$isdiff && [commitinview $nullid $curview]} {
- removefakerow $nullid
+ removefakerow $nullid
}
return 0
}
@@ -5402,17 +5420,17 @@ proc nextuse {id row} {
global curview children
if {[info exists children($curview,$id)]} {
- foreach kid $children($curview,$id) {
- if {![commitinview $kid $curview]} {
- return -1
- }
- if {[rowofcommit $kid] > $row} {
- return [rowofcommit $kid]
- }
- }
+ foreach kid $children($curview,$id) {
+ if {![commitinview $kid $curview]} {
+ return -1
+ }
+ if {[rowofcommit $kid] > $row} {
+ return [rowofcommit $kid]
+ }
+ }
}
if {[commitinview $id $curview]} {
- return [rowofcommit $id]
+ return [rowofcommit $id]
}
return -1
}
@@ -5422,12 +5440,12 @@ proc prevuse {id row} {
set ret -1
if {[info exists children($curview,$id)]} {
- foreach kid $children($curview,$id) {
- if {![commitinview $kid $curview]} break
- if {[rowofcommit $kid] < $row} {
- set ret [rowofcommit $kid]
- }
- }
+ foreach kid $children($curview,$id) {
+ if {![commitinview $kid $curview]} break
+ if {[rowofcommit $kid] < $row} {
+ set ret [rowofcommit $kid]
+ }
+ }
}
return $ret
}
@@ -5438,70 +5456,70 @@ proc make_idlist {row} {
set r [expr {$row - $mingaplen - $downarrowlen - 1}]
if {$r < 0} {
- set r 0
+ set r 0
}
set ra [expr {$row - $downarrowlen}]
if {$ra < 0} {
- set ra 0
+ set ra 0
}
set rb [expr {$row + $uparrowlen}]
if {$rb > $commitidx($curview)} {
- set rb $commitidx($curview)
+ set rb $commitidx($curview)
}
make_disporder $r [expr {$rb + 1}]
set ids {}
for {} {$r < $ra} {incr r} {
- set nextid [lindex $displayorder [expr {$r + 1}]]
- foreach p [lindex $parentlist $r] {
- if {$p eq $nextid} continue
- set rn [nextuse $p $r]
- if {$rn >= $row &&
- $rn <= $r + $downarrowlen + $mingaplen + $uparrowlen} {
- lappend ids [list [ordertoken $p] $p]
- }
- }
+ set nextid [lindex $displayorder [expr {$r + 1}]]
+ foreach p [lindex $parentlist $r] {
+ if {$p eq $nextid} continue
+ set rn [nextuse $p $r]
+ if {$rn >= $row &&
+ $rn <= $r + $downarrowlen + $mingaplen + $uparrowlen} {
+ lappend ids [list [ordertoken $p] $p]
+ }
+ }
}
for {} {$r < $row} {incr r} {
- set nextid [lindex $displayorder [expr {$r + 1}]]
- foreach p [lindex $parentlist $r] {
- if {$p eq $nextid} continue
- set rn [nextuse $p $r]
- if {$rn < 0 || $rn >= $row} {
- lappend ids [list [ordertoken $p] $p]
- }
- }
+ set nextid [lindex $displayorder [expr {$r + 1}]]
+ foreach p [lindex $parentlist $r] {
+ if {$p eq $nextid} continue
+ set rn [nextuse $p $r]
+ if {$rn < 0 || $rn >= $row} {
+ lappend ids [list [ordertoken $p] $p]
+ }
+ }
}
set id [lindex $displayorder $row]
lappend ids [list [ordertoken $id] $id]
while {$r < $rb} {
- foreach p [lindex $parentlist $r] {
- set firstkid [lindex $children($curview,$p) 0]
- if {[rowofcommit $firstkid] < $row} {
- lappend ids [list [ordertoken $p] $p]
- }
- }
- incr r
- set id [lindex $displayorder $r]
- if {$id ne {}} {
- set firstkid [lindex $children($curview,$id) 0]
- if {$firstkid ne {} && [rowofcommit $firstkid] < $row} {
- lappend ids [list [ordertoken $id] $id]
- }
- }
+ foreach p [lindex $parentlist $r] {
+ set firstkid [lindex $children($curview,$p) 0]
+ if {[rowofcommit $firstkid] < $row} {
+ lappend ids [list [ordertoken $p] $p]
+ }
+ }
+ incr r
+ set id [lindex $displayorder $r]
+ if {$id ne {}} {
+ set firstkid [lindex $children($curview,$id) 0]
+ if {$firstkid ne {} && [rowofcommit $firstkid] < $row} {
+ lappend ids [list [ordertoken $id] $id]
+ }
+ }
}
set idlist {}
foreach idx [lsort -unique $ids] {
- lappend idlist [lindex $idx 1]
+ lappend idlist [lindex $idx 1]
}
return $idlist
}
proc rowsequal {a b} {
while {[set i [lsearch -exact $a {}]] >= 0} {
- set a [lreplace $a $i $i]
+ set a [lreplace $a $i $i]
}
while {[set i [lsearch -exact $b {}]] >= 0} {
- set b [lreplace $b $i $i]
+ set b [lreplace $b $i $i]
}
return [expr {$a eq $b}]
}
@@ -5510,20 +5528,20 @@ proc makeupline {id row rend col} {
global rowidlist uparrowlen downarrowlen mingaplen
for {set r $rend} {1} {set r $rstart} {
- set rstart [prevuse $id $r]
- if {$rstart < 0} return
- if {$rstart < $row} break
+ set rstart [prevuse $id $r]
+ if {$rstart < 0} return
+ if {$rstart < $row} break
}
if {$rstart + $uparrowlen + $mingaplen + $downarrowlen < $rend} {
- set rstart [expr {$rend - $uparrowlen - 1}]
+ set rstart [expr {$rend - $uparrowlen - 1}]
}
for {set r $rstart} {[incr r] <= $row} {} {
- set idlist [lindex $rowidlist $r]
- if {$idlist ne {} && [lsearch -exact $idlist $id] < 0} {
- set col [idcol $idlist $id $col]
- lset rowidlist $r [linsert $idlist $col $id]
- changedrow $r
- }
+ set idlist [lindex $rowidlist $r]
+ if {$idlist ne {} && [lsearch -exact $idlist $id] < 0} {
+ set col [idcol $idlist $id $col]
+ lset rowidlist $r [linsert $idlist $col $id]
+ changedrow $r
+ }
}
}
@@ -5536,100 +5554,100 @@ proc layoutrows {row endrow} {
make_disporder [expr {$row - 1}] [expr {$endrow + $uparrowlen}]
set idlist {}
if {$row > 0} {
- set rm1 [expr {$row - 1}]
- foreach id [lindex $rowidlist $rm1] {
- if {$id ne {}} {
- lappend idlist $id
- }
- }
- set final [lindex $rowfinal $rm1]
+ set rm1 [expr {$row - 1}]
+ foreach id [lindex $rowidlist $rm1] {
+ if {$id ne {}} {
+ lappend idlist $id
+ }
+ }
+ set final [lindex $rowfinal $rm1]
}
for {} {$row < $endrow} {incr row} {
- set rm1 [expr {$row - 1}]
- if {$rm1 < 0 || $idlist eq {}} {
- set idlist [make_idlist $row]
- set final 1
- } else {
- set id [lindex $displayorder $rm1]
- set col [lsearch -exact $idlist $id]
- set idlist [lreplace $idlist $col $col]
- foreach p [lindex $parentlist $rm1] {
- if {[lsearch -exact $idlist $p] < 0} {
- set col [idcol $idlist $p $col]
- set idlist [linsert $idlist $col $p]
- # if not the first child, we have to insert a line going up
- if {$id ne [lindex $children($curview,$p) 0]} {
- makeupline $p $rm1 $row $col
- }
- }
- }
- set id [lindex $displayorder $row]
- if {$row > $downarrowlen} {
- set termrow [expr {$row - $downarrowlen - 1}]
- foreach p [lindex $parentlist $termrow] {
- set i [lsearch -exact $idlist $p]
- if {$i < 0} continue
- set nr [nextuse $p $termrow]
- if {$nr < 0 || $nr >= $row + $mingaplen + $uparrowlen} {
- set idlist [lreplace $idlist $i $i]
- }
- }
- }
- set col [lsearch -exact $idlist $id]
- if {$col < 0} {
- set col [idcol $idlist $id]
- set idlist [linsert $idlist $col $id]
- if {$children($curview,$id) ne {}} {
- makeupline $id $rm1 $row $col
- }
- }
- set r [expr {$row + $uparrowlen - 1}]
- if {$r < $commitidx($curview)} {
- set x $col
- foreach p [lindex $parentlist $r] {
- if {[lsearch -exact $idlist $p] >= 0} continue
- set fk [lindex $children($curview,$p) 0]
- if {[rowofcommit $fk] < $row} {
- set x [idcol $idlist $p $x]
- set idlist [linsert $idlist $x $p]
- }
- }
- if {[incr r] < $commitidx($curview)} {
- set p [lindex $displayorder $r]
- if {[lsearch -exact $idlist $p] < 0} {
- set fk [lindex $children($curview,$p) 0]
- if {$fk ne {} && [rowofcommit $fk] < $row} {
- set x [idcol $idlist $p $x]
- set idlist [linsert $idlist $x $p]
- }
- }
- }
- }
- }
- if {$final && !$viewcomplete($curview) &&
- $row + $uparrowlen + $mingaplen + $downarrowlen
- >= $commitidx($curview)} {
- set final 0
- }
- set l [llength $rowidlist]
- if {$row == $l} {
- lappend rowidlist $idlist
- lappend rowisopt 0
- lappend rowfinal $final
- } elseif {$row < $l} {
- if {![rowsequal $idlist [lindex $rowidlist $row]]} {
- lset rowidlist $row $idlist
- changedrow $row
- }
- lset rowfinal $row $final
- } else {
- set pad [ntimes [expr {$row - $l}] {}]
- set rowidlist [concat $rowidlist $pad]
- lappend rowidlist $idlist
- set rowfinal [concat $rowfinal $pad]
- lappend rowfinal $final
- set rowisopt [concat $rowisopt [ntimes [expr {$row - $l + 1}] 0]]
- }
+ set rm1 [expr {$row - 1}]
+ if {$rm1 < 0 || $idlist eq {}} {
+ set idlist [make_idlist $row]
+ set final 1
+ } else {
+ set id [lindex $displayorder $rm1]
+ set col [lsearch -exact $idlist $id]
+ set idlist [lreplace $idlist $col $col]
+ foreach p [lindex $parentlist $rm1] {
+ if {[lsearch -exact $idlist $p] < 0} {
+ set col [idcol $idlist $p $col]
+ set idlist [linsert $idlist $col $p]
+ # if not the first child, we have to insert a line going up
+ if {$id ne [lindex $children($curview,$p) 0]} {
+ makeupline $p $rm1 $row $col
+ }
+ }
+ }
+ set id [lindex $displayorder $row]
+ if {$row > $downarrowlen} {
+ set termrow [expr {$row - $downarrowlen - 1}]
+ foreach p [lindex $parentlist $termrow] {
+ set i [lsearch -exact $idlist $p]
+ if {$i < 0} continue
+ set nr [nextuse $p $termrow]
+ if {$nr < 0 || $nr >= $row + $mingaplen + $uparrowlen} {
+ set idlist [lreplace $idlist $i $i]
+ }
+ }
+ }
+ set col [lsearch -exact $idlist $id]
+ if {$col < 0} {
+ set col [idcol $idlist $id]
+ set idlist [linsert $idlist $col $id]
+ if {$children($curview,$id) ne {}} {
+ makeupline $id $rm1 $row $col
+ }
+ }
+ set r [expr {$row + $uparrowlen - 1}]
+ if {$r < $commitidx($curview)} {
+ set x $col
+ foreach p [lindex $parentlist $r] {
+ if {[lsearch -exact $idlist $p] >= 0} continue
+ set fk [lindex $children($curview,$p) 0]
+ if {[rowofcommit $fk] < $row} {
+ set x [idcol $idlist $p $x]
+ set idlist [linsert $idlist $x $p]
+ }
+ }
+ if {[incr r] < $commitidx($curview)} {
+ set p [lindex $displayorder $r]
+ if {[lsearch -exact $idlist $p] < 0} {
+ set fk [lindex $children($curview,$p) 0]
+ if {$fk ne {} && [rowofcommit $fk] < $row} {
+ set x [idcol $idlist $p $x]
+ set idlist [linsert $idlist $x $p]
+ }
+ }
+ }
+ }
+ }
+ if {$final && !$viewcomplete($curview) &&
+ $row + $uparrowlen + $mingaplen + $downarrowlen
+ >= $commitidx($curview)} {
+ set final 0
+ }
+ set l [llength $rowidlist]
+ if {$row == $l} {
+ lappend rowidlist $idlist
+ lappend rowisopt 0
+ lappend rowfinal $final
+ } elseif {$row < $l} {
+ if {![rowsequal $idlist [lindex $rowidlist $row]]} {
+ lset rowidlist $row $idlist
+ changedrow $row
+ }
+ lset rowfinal $row $final
+ } else {
+ set pad [ntimes [expr {$row - $l}] {}]
+ set rowidlist [concat $rowidlist $pad]
+ lappend rowidlist $idlist
+ set rowfinal [concat $rowfinal $pad]
+ lappend rowfinal $final
+ set rowisopt [concat $rowisopt [ntimes [expr {$row - $l + 1}] 0]]
+ }
}
return $row
}
@@ -5639,17 +5657,17 @@ proc changedrow {row} {
set l [llength $rowisopt]
if {$row < $l} {
- lset rowisopt $row 0
- if {$row + 1 < $l} {
- lset rowisopt [expr {$row + 1}] 0
- if {$row + 2 < $l} {
- lset rowisopt [expr {$row + 2}] 0
- }
- }
+ lset rowisopt $row 0
+ if {$row + 1 < $l} {
+ lset rowisopt [expr {$row + 1}] 0
+ if {$row + 2 < $l} {
+ lset rowisopt [expr {$row + 2}] 0
+ }
+ }
}
set id [lindex $displayorder $row]
if {[info exists iddrawn($id)]} {
- set need_redisplay 1
+ set need_redisplay 1
}
}
@@ -5662,7 +5680,7 @@ proc insert_pad {row col npad} {
set aft [lrange $idlist $col end]
set i [lsearch -exact $aft {}]
if {$i > 0} {
- set aft [lreplace $aft $i $i]
+ set aft [lreplace $aft $i $i]
}
lset rowidlist $row [concat $bef $pad $aft]
changedrow $row
@@ -5672,123 +5690,123 @@ proc optimize_rows {row col endrow} {
global rowidlist rowisopt displayorder curview children
if {$row < 1} {
- set row 1
+ set row 1
}
for {} {$row < $endrow} {incr row; set col 0} {
- if {[lindex $rowisopt $row]} continue
- set haspad 0
- set y0 [expr {$row - 1}]
- set ym [expr {$row - 2}]
- set idlist [lindex $rowidlist $row]
- set previdlist [lindex $rowidlist $y0]
- if {$idlist eq {} || $previdlist eq {}} continue
- if {$ym >= 0} {
- set pprevidlist [lindex $rowidlist $ym]
- if {$pprevidlist eq {}} continue
- } else {
- set pprevidlist {}
- }
- set x0 -1
- set xm -1
- for {} {$col < [llength $idlist]} {incr col} {
- set id [lindex $idlist $col]
- if {[lindex $previdlist $col] eq $id} continue
- if {$id eq {}} {
- set haspad 1
- continue
- }
- set x0 [lsearch -exact $previdlist $id]
- if {$x0 < 0} continue
- set z [expr {$x0 - $col}]
- set isarrow 0
- set z0 {}
- if {$ym >= 0} {
- set xm [lsearch -exact $pprevidlist $id]
- if {$xm >= 0} {
- set z0 [expr {$xm - $x0}]
- }
- }
- if {$z0 eq {}} {
- # if row y0 is the first child of $id then it's not an arrow
- if {[lindex $children($curview,$id) 0] ne
- [lindex $displayorder $y0]} {
- set isarrow 1
- }
- }
- if {!$isarrow && $id ne [lindex $displayorder $row] &&
- [lsearch -exact [lindex $rowidlist [expr {$row+1}]] $id] < 0} {
- set isarrow 1
- }
- # Looking at lines from this row to the previous row,
- # make them go straight up if they end in an arrow on
- # the previous row; otherwise make them go straight up
- # or at 45 degrees.
- if {$z < -1 || ($z < 0 && $isarrow)} {
- # Line currently goes left too much;
- # insert pads in the previous row, then optimize it
- set npad [expr {-1 - $z + $isarrow}]
- insert_pad $y0 $x0 $npad
- if {$y0 > 0} {
- optimize_rows $y0 $x0 $row
- }
- set previdlist [lindex $rowidlist $y0]
- set x0 [lsearch -exact $previdlist $id]
- set z [expr {$x0 - $col}]
- if {$z0 ne {}} {
- set pprevidlist [lindex $rowidlist $ym]
- set xm [lsearch -exact $pprevidlist $id]
- set z0 [expr {$xm - $x0}]
- }
- } elseif {$z > 1 || ($z > 0 && $isarrow)} {
- # Line currently goes right too much;
- # insert pads in this line
- set npad [expr {$z - 1 + $isarrow}]
- insert_pad $row $col $npad
- set idlist [lindex $rowidlist $row]
- incr col $npad
- set z [expr {$x0 - $col}]
- set haspad 1
- }
- if {$z0 eq {} && !$isarrow && $ym >= 0} {
- # this line links to its first child on row $row-2
- set id [lindex $displayorder $ym]
- set xc [lsearch -exact $pprevidlist $id]
- if {$xc >= 0} {
- set z0 [expr {$xc - $x0}]
- }
- }
- # avoid lines jigging left then immediately right
- if {$z0 ne {} && $z < 0 && $z0 > 0} {
- insert_pad $y0 $x0 1
- incr x0
- optimize_rows $y0 $x0 $row
- set previdlist [lindex $rowidlist $y0]
- }
- }
- if {!$haspad} {
- # Find the first column that doesn't have a line going right
- for {set col [llength $idlist]} {[incr col -1] >= 0} {} {
- set id [lindex $idlist $col]
- if {$id eq {}} break
- set x0 [lsearch -exact $previdlist $id]
- if {$x0 < 0} {
- # check if this is the link to the first child
- set kid [lindex $displayorder $y0]
- if {[lindex $children($curview,$id) 0] eq $kid} {
- # it is, work out offset to child
- set x0 [lsearch -exact $previdlist $kid]
- }
- }
- if {$x0 <= $col} break
- }
- # Insert a pad at that column as long as it has a line and
- # isn't the last column
- if {$x0 >= 0 && [incr col] < [llength $idlist]} {
- set idlist [linsert $idlist $col {}]
- lset rowidlist $row $idlist
- changedrow $row
- }
- }
+ if {[lindex $rowisopt $row]} continue
+ set haspad 0
+ set y0 [expr {$row - 1}]
+ set ym [expr {$row - 2}]
+ set idlist [lindex $rowidlist $row]
+ set previdlist [lindex $rowidlist $y0]
+ if {$idlist eq {} || $previdlist eq {}} continue
+ if {$ym >= 0} {
+ set pprevidlist [lindex $rowidlist $ym]
+ if {$pprevidlist eq {}} continue
+ } else {
+ set pprevidlist {}
+ }
+ set x0 -1
+ set xm -1
+ for {} {$col < [llength $idlist]} {incr col} {
+ set id [lindex $idlist $col]
+ if {[lindex $previdlist $col] eq $id} continue
+ if {$id eq {}} {
+ set haspad 1
+ continue
+ }
+ set x0 [lsearch -exact $previdlist $id]
+ if {$x0 < 0} continue
+ set z [expr {$x0 - $col}]
+ set isarrow 0
+ set z0 {}
+ if {$ym >= 0} {
+ set xm [lsearch -exact $pprevidlist $id]
+ if {$xm >= 0} {
+ set z0 [expr {$xm - $x0}]
+ }
+ }
+ if {$z0 eq {}} {
+ # if row y0 is the first child of $id then it's not an arrow
+ if {[lindex $children($curview,$id) 0] ne
+ [lindex $displayorder $y0]} {
+ set isarrow 1
+ }
+ }
+ if {!$isarrow && $id ne [lindex $displayorder $row] &&
+ [lsearch -exact [lindex $rowidlist [expr {$row+1}]] $id] < 0} {
+ set isarrow 1
+ }
+ # Looking at lines from this row to the previous row,
+ # make them go straight up if they end in an arrow on
+ # the previous row; otherwise make them go straight up
+ # or at 45 degrees.
+ if {$z < -1 || ($z < 0 && $isarrow)} {
+ # Line currently goes left too much;
+ # insert pads in the previous row, then optimize it
+ set npad [expr {-1 - $z + $isarrow}]
+ insert_pad $y0 $x0 $npad
+ if {$y0 > 0} {
+ optimize_rows $y0 $x0 $row
+ }
+ set previdlist [lindex $rowidlist $y0]
+ set x0 [lsearch -exact $previdlist $id]
+ set z [expr {$x0 - $col}]
+ if {$z0 ne {}} {
+ set pprevidlist [lindex $rowidlist $ym]
+ set xm [lsearch -exact $pprevidlist $id]
+ set z0 [expr {$xm - $x0}]
+ }
+ } elseif {$z > 1 || ($z > 0 && $isarrow)} {
+ # Line currently goes right too much;
+ # insert pads in this line
+ set npad [expr {$z - 1 + $isarrow}]
+ insert_pad $row $col $npad
+ set idlist [lindex $rowidlist $row]
+ incr col $npad
+ set z [expr {$x0 - $col}]
+ set haspad 1
+ }
+ if {$z0 eq {} && !$isarrow && $ym >= 0} {
+ # this line links to its first child on row $row-2
+ set id [lindex $displayorder $ym]
+ set xc [lsearch -exact $pprevidlist $id]
+ if {$xc >= 0} {
+ set z0 [expr {$xc - $x0}]
+ }
+ }
+ # avoid lines jigging left then immediately right
+ if {$z0 ne {} && $z < 0 && $z0 > 0} {
+ insert_pad $y0 $x0 1
+ incr x0
+ optimize_rows $y0 $x0 $row
+ set previdlist [lindex $rowidlist $y0]
+ }
+ }
+ if {!$haspad} {
+ # Find the first column that doesn't have a line going right
+ for {set col [llength $idlist]} {[incr col -1] >= 0} {} {
+ set id [lindex $idlist $col]
+ if {$id eq {}} break
+ set x0 [lsearch -exact $previdlist $id]
+ if {$x0 < 0} {
+ # check if this is the link to the first child
+ set kid [lindex $displayorder $y0]
+ if {[lindex $children($curview,$id) 0] eq $kid} {
+ # it is, work out offset to child
+ set x0 [lsearch -exact $previdlist $kid]
+ }
+ }
+ if {$x0 <= $col} break
+ }
+ # Insert a pad at that column as long as it has a line and
+ # isn't the last column
+ if {$x0 >= 0 && [incr col] < [llength $idlist]} {
+ set idlist [linsert $idlist $col {}]
+ lset rowidlist $row $idlist
+ changedrow $row
+ }
+ }
}
}
@@ -5807,7 +5825,7 @@ proc linewidth {id} {
set wid $lthickness
if {[info exists thickerline] && $id eq $thickerline} {
- set wid [expr {2 * $lthickness}]
+ set wid [expr {2 * $lthickness}]
}
return $wid
}
@@ -5818,52 +5836,52 @@ proc rowranges {id} {
set kids $children($curview,$id)
if {$kids eq {}} {
- return {}
+ return {}
}
set ret {}
lappend kids $id
foreach child $kids {
- if {![commitinview $child $curview]} break
- set row [rowofcommit $child]
- if {![info exists prev]} {
- lappend ret [expr {$row + 1}]
- } else {
- if {$row <= $prevrow} {
- puts "oops children of [shortids $id] out of order [shortids $child] $row <= [shortids $prev] $prevrow"
- }
- # see if the line extends the whole way from prevrow to row
- if {$row > $prevrow + $uparrowlen + $downarrowlen &&
- [lsearch -exact [lindex $rowidlist \
- [expr {int(($row + $prevrow) / 2)}]] $id] < 0} {
- # it doesn't, see where it ends
- set r [expr {$prevrow + $downarrowlen}]
- if {[lsearch -exact [lindex $rowidlist $r] $id] < 0} {
- while {[incr r -1] > $prevrow &&
- [lsearch -exact [lindex $rowidlist $r] $id] < 0} {}
- } else {
- while {[incr r] <= $row &&
- [lsearch -exact [lindex $rowidlist $r] $id] >= 0} {}
- incr r -1
- }
- lappend ret $r
- # see where it starts up again
- set r [expr {$row - $uparrowlen}]
- if {[lsearch -exact [lindex $rowidlist $r] $id] < 0} {
- while {[incr r] < $row &&
- [lsearch -exact [lindex $rowidlist $r] $id] < 0} {}
- } else {
- while {[incr r -1] >= $prevrow &&
- [lsearch -exact [lindex $rowidlist $r] $id] >= 0} {}
- incr r
- }
- lappend ret $r
- }
- }
- if {$child eq $id} {
- lappend ret $row
- }
- set prev $child
- set prevrow $row
+ if {![commitinview $child $curview]} break
+ set row [rowofcommit $child]
+ if {![info exists prev]} {
+ lappend ret [expr {$row + 1}]
+ } else {
+ if {$row <= $prevrow} {
+ puts "oops children of [shortids $id] out of order [shortids $child] $row <= [shortids $prev] $prevrow"
+ }
+ # see if the line extends the whole way from prevrow to row
+ if {$row > $prevrow + $uparrowlen + $downarrowlen &&
+ [lsearch -exact [lindex $rowidlist \
+ [expr {int(($row + $prevrow) / 2)}]] $id] < 0} {
+ # it doesn't, see where it ends
+ set r [expr {$prevrow + $downarrowlen}]
+ if {[lsearch -exact [lindex $rowidlist $r] $id] < 0} {
+ while {[incr r -1] > $prevrow &&
+ [lsearch -exact [lindex $rowidlist $r] $id] < 0} {}
+ } else {
+ while {[incr r] <= $row &&
+ [lsearch -exact [lindex $rowidlist $r] $id] >= 0} {}
+ incr r -1
+ }
+ lappend ret $r
+ # see where it starts up again
+ set r [expr {$row - $uparrowlen}]
+ if {[lsearch -exact [lindex $rowidlist $r] $id] < 0} {
+ while {[incr r] < $row &&
+ [lsearch -exact [lindex $rowidlist $r] $id] < 0} {}
+ } else {
+ while {[incr r -1] >= $prevrow &&
+ [lsearch -exact [lindex $rowidlist $r] $id] >= 0} {}
+ incr r
+ }
+ lappend ret $r
+ }
+ }
+ if {$child eq $id} {
+ lappend ret $row
+ }
+ set prev $child
+ set prevrow $row
}
return $ret
}
@@ -5876,158 +5894,158 @@ proc drawlineseg {id row endrow arrowlow} {
set le [expr {$row + 1}]
set arrowhigh 1
while {1} {
- set c [lsearch -exact [lindex $rowidlist $le] $id]
- if {$c < 0} {
- incr le -1
- break
- }
- lappend cols $c
- set x [lindex $displayorder $le]
- if {$x eq $id} {
- set arrowhigh 0
- break
- }
- if {[info exists iddrawn($x)] || $le == $endrow} {
- set c [lsearch -exact [lindex $rowidlist [expr {$le+1}]] $id]
- if {$c >= 0} {
- lappend cols $c
- set arrowhigh 0
- }
- break
- }
- incr le
+ set c [lsearch -exact [lindex $rowidlist $le] $id]
+ if {$c < 0} {
+ incr le -1
+ break
+ }
+ lappend cols $c
+ set x [lindex $displayorder $le]
+ if {$x eq $id} {
+ set arrowhigh 0
+ break
+ }
+ if {[info exists iddrawn($x)] || $le == $endrow} {
+ set c [lsearch -exact [lindex $rowidlist [expr {$le+1}]] $id]
+ if {$c >= 0} {
+ lappend cols $c
+ set arrowhigh 0
+ }
+ break
+ }
+ incr le
}
if {$le <= $row} {
- return $row
+ return $row
}
set lines {}
set i 0
set joinhigh 0
if {[info exists linesegs($id)]} {
- set lines $linesegs($id)
- foreach li $lines {
- set r0 [lindex $li 0]
- if {$r0 > $row} {
- if {$r0 == $le && [lindex $li 1] - $row <= $maxlinelen} {
- set joinhigh 1
- }
- break
- }
- incr i
- }
+ set lines $linesegs($id)
+ foreach li $lines {
+ set r0 [lindex $li 0]
+ if {$r0 > $row} {
+ if {$r0 == $le && [lindex $li 1] - $row <= $maxlinelen} {
+ set joinhigh 1
+ }
+ break
+ }
+ incr i
+ }
}
set joinlow 0
if {$i > 0} {
- set li [lindex $lines [expr {$i-1}]]
- set r1 [lindex $li 1]
- if {$r1 == $row && $le - [lindex $li 0] <= $maxlinelen} {
- set joinlow 1
- }
+ set li [lindex $lines [expr {$i-1}]]
+ set r1 [lindex $li 1]
+ if {$r1 == $row && $le - [lindex $li 0] <= $maxlinelen} {
+ set joinlow 1
+ }
}
set x [lindex $cols [expr {$le - $row}]]
set xp [lindex $cols [expr {$le - 1 - $row}]]
set dir [expr {$xp - $x}]
if {$joinhigh} {
- set ith [lindex $lines $i 2]
- set coords [$canv coords $ith]
- set ah [$canv itemcget $ith -arrow]
- set arrowhigh [expr {$ah eq "first" || $ah eq "both"}]
- set x2 [lindex $cols [expr {$le + 1 - $row}]]
- if {$x2 ne {} && $x - $x2 == $dir} {
- set coords [lrange $coords 0 end-2]
- }
+ set ith [lindex $lines $i 2]
+ set coords [$canv coords $ith]
+ set ah [$canv itemcget $ith -arrow]
+ set arrowhigh [expr {$ah eq "first" || $ah eq "both"}]
+ set x2 [lindex $cols [expr {$le + 1 - $row}]]
+ if {$x2 ne {} && $x - $x2 == $dir} {
+ set coords [lrange $coords 0 end-2]
+ }
} else {
- set coords [list [xc $le $x] [yc $le]]
+ set coords [list [xc $le $x] [yc $le]]
}
if {$joinlow} {
- set itl [lindex $lines [expr {$i-1}] 2]
- set al [$canv itemcget $itl -arrow]
- set arrowlow [expr {$al eq "last" || $al eq "both"}]
+ set itl [lindex $lines [expr {$i-1}] 2]
+ set al [$canv itemcget $itl -arrow]
+ set arrowlow [expr {$al eq "last" || $al eq "both"}]
} elseif {$arrowlow} {
- if {[lsearch -exact [lindex $rowidlist [expr {$row-1}]] $id] >= 0 ||
- [lsearch -exact [lindex $parentlist [expr {$row-1}]] $id] >= 0} {
- set arrowlow 0
- }
+ if {[lsearch -exact [lindex $rowidlist [expr {$row-1}]] $id] >= 0 ||
+ [lsearch -exact [lindex $parentlist [expr {$row-1}]] $id] >= 0} {
+ set arrowlow 0
+ }
}
set arrow [lindex {none first last both} [expr {$arrowhigh + 2*$arrowlow}]]
for {set y $le} {[incr y -1] > $row} {} {
- set x $xp
- set xp [lindex $cols [expr {$y - 1 - $row}]]
- set ndir [expr {$xp - $x}]
- if {$dir != $ndir || $xp < 0} {
- lappend coords [xc $y $x] [yc $y]
- }
- set dir $ndir
+ set x $xp
+ set xp [lindex $cols [expr {$y - 1 - $row}]]
+ set ndir [expr {$xp - $x}]
+ if {$dir != $ndir || $xp < 0} {
+ lappend coords [xc $y $x] [yc $y]
+ }
+ set dir $ndir
}
if {!$joinlow} {
- if {$xp < 0} {
- # join parent line to first child
- set ch [lindex $displayorder $row]
- set xc [lsearch -exact [lindex $rowidlist $row] $ch]
- if {$xc < 0} {
- puts "oops: drawlineseg: child $ch not on row $row"
- } elseif {$xc != $x} {
- if {($arrowhigh && $le == $row + 1) || $dir == 0} {
- set d [expr {int(0.5 * $linespc)}]
- set x1 [xc $row $x]
- if {$xc < $x} {
- set x2 [expr {$x1 - $d}]
- } else {
- set x2 [expr {$x1 + $d}]
- }
- set y2 [yc $row]
- set y1 [expr {$y2 + $d}]
- lappend coords $x1 $y1 $x2 $y2
- } elseif {$xc < $x - 1} {
- lappend coords [xc $row [expr {$x-1}]] [yc $row]
- } elseif {$xc > $x + 1} {
- lappend coords [xc $row [expr {$x+1}]] [yc $row]
- }
- set x $xc
- }
- lappend coords [xc $row $x] [yc $row]
- } else {
- set xn [xc $row $xp]
- set yn [yc $row]
- lappend coords $xn $yn
- }
- if {!$joinhigh} {
- assigncolor $id
- set t [$canv create line $coords -width [linewidth $id] \
- -fill $colormap($id) -tags lines.$id -arrow $arrow]
- $canv lower $t
- bindline $t $id
- set lines [linsert $lines $i [list $row $le $t]]
- } else {
- $canv coords $ith $coords
- if {$arrow ne $ah} {
- $canv itemconf $ith -arrow $arrow
- }
- lset lines $i 0 $row
- }
+ if {$xp < 0} {
+ # join parent line to first child
+ set ch [lindex $displayorder $row]
+ set xc [lsearch -exact [lindex $rowidlist $row] $ch]
+ if {$xc < 0} {
+ puts "oops: drawlineseg: child $ch not on row $row"
+ } elseif {$xc != $x} {
+ if {($arrowhigh && $le == $row + 1) || $dir == 0} {
+ set d [expr {int(0.5 * $linespc)}]
+ set x1 [xc $row $x]
+ if {$xc < $x} {
+ set x2 [expr {$x1 - $d}]
+ } else {
+ set x2 [expr {$x1 + $d}]
+ }
+ set y2 [yc $row]
+ set y1 [expr {$y2 + $d}]
+ lappend coords $x1 $y1 $x2 $y2
+ } elseif {$xc < $x - 1} {
+ lappend coords [xc $row [expr {$x-1}]] [yc $row]
+ } elseif {$xc > $x + 1} {
+ lappend coords [xc $row [expr {$x+1}]] [yc $row]
+ }
+ set x $xc
+ }
+ lappend coords [xc $row $x] [yc $row]
+ } else {
+ set xn [xc $row $xp]
+ set yn [yc $row]
+ lappend coords $xn $yn
+ }
+ if {!$joinhigh} {
+ assigncolor $id
+ set t [$canv create line $coords -width [linewidth $id] \
+ -fill $colormap($id) -tags lines.$id -arrow $arrow]
+ $canv lower $t
+ bindline $t $id
+ set lines [linsert $lines $i [list $row $le $t]]
+ } else {
+ $canv coords $ith $coords
+ if {$arrow ne $ah} {
+ $canv itemconf $ith -arrow $arrow
+ }
+ lset lines $i 0 $row
+ }
} else {
- set xo [lsearch -exact [lindex $rowidlist [expr {$row - 1}]] $id]
- set ndir [expr {$xo - $xp}]
- set clow [$canv coords $itl]
- if {$dir == $ndir} {
- set clow [lrange $clow 2 end]
- }
- set coords [concat $coords $clow]
- if {!$joinhigh} {
- lset lines [expr {$i-1}] 1 $le
- } else {
- # coalesce two pieces
- $canv delete $ith
- set b [lindex $lines [expr {$i-1}] 0]
- set e [lindex $lines $i 1]
- set lines [lreplace $lines [expr {$i-1}] $i [list $b $e $itl]]
- }
- $canv coords $itl $coords
- if {$arrow ne $al} {
- $canv itemconf $itl -arrow $arrow
- }
+ set xo [lsearch -exact [lindex $rowidlist [expr {$row - 1}]] $id]
+ set ndir [expr {$xo - $xp}]
+ set clow [$canv coords $itl]
+ if {$dir == $ndir} {
+ set clow [lrange $clow 2 end]
+ }
+ set coords [concat $coords $clow]
+ if {!$joinhigh} {
+ lset lines [expr {$i-1}] 1 $le
+ } else {
+ # coalesce two pieces
+ $canv delete $ith
+ set b [lindex $lines [expr {$i-1}] 0]
+ set e [lindex $lines $i 1]
+ set lines [lreplace $lines [expr {$i-1}] $i [list $b $e $itl]]
+ }
+ $canv coords $itl $coords
+ if {$arrow ne $al} {
+ $canv itemconf $itl -arrow $arrow
+ }
}
set linesegs($id) $lines
@@ -6052,54 +6070,54 @@ proc drawparentlinks {id row} {
# rmx = right-most X coord used
set rmx 0
foreach p $olds {
- set i [lsearch -exact $ids $p]
- if {$i < 0} {
- puts "oops, parent $p of $id not in list"
- continue
- }
- set x2 [xc $row2 $i]
- if {$x2 > $rmx} {
- set rmx $x2
- }
- set j [lsearch -exact $rowids $p]
- if {$j < 0} {
- # drawlineseg will do this one for us
- continue
- }
- assigncolor $p
- # should handle duplicated parents here...
- set coords [list $x $y]
- if {$i != $col} {
- # if attaching to a vertical segment, draw a smaller
- # slant for visual distinctness
- if {$i == $j} {
- if {$i < $col} {
- lappend coords [expr {$x2 + $d}] $y $x2 $ymid
- } else {
- lappend coords [expr {$x2 - $d}] $y $x2 $ymid
- }
- } elseif {$i < $col && $i < $j} {
- # segment slants towards us already
- lappend coords [xc $row $j] $y
- } else {
- if {$i < $col - 1} {
- lappend coords [expr {$x2 + $linespc}] $y
- } elseif {$i > $col + 1} {
- lappend coords [expr {$x2 - $linespc}] $y
- }
- lappend coords $x2 $y2
- }
- } else {
- lappend coords $x2 $y2
- }
- set t [$canv create line $coords -width [linewidth $p] \
- -fill $colormap($p) -tags lines.$p]
- $canv lower $t
- bindline $t $p
+ set i [lsearch -exact $ids $p]
+ if {$i < 0} {
+ puts "oops, parent $p of $id not in list"
+ continue
+ }
+ set x2 [xc $row2 $i]
+ if {$x2 > $rmx} {
+ set rmx $x2
+ }
+ set j [lsearch -exact $rowids $p]
+ if {$j < 0} {
+ # drawlineseg will do this one for us
+ continue
+ }
+ assigncolor $p
+ # should handle duplicated parents here...
+ set coords [list $x $y]
+ if {$i != $col} {
+ # if attaching to a vertical segment, draw a smaller
+ # slant for visual distinctness
+ if {$i == $j} {
+ if {$i < $col} {
+ lappend coords [expr {$x2 + $d}] $y $x2 $ymid
+ } else {
+ lappend coords [expr {$x2 - $d}] $y $x2 $ymid
+ }
+ } elseif {$i < $col && $i < $j} {
+ # segment slants towards us already
+ lappend coords [xc $row $j] $y
+ } else {
+ if {$i < $col - 1} {
+ lappend coords [expr {$x2 + $linespc}] $y
+ } elseif {$i > $col + 1} {
+ lappend coords [expr {$x2 - $linespc}] $y
+ }
+ lappend coords $x2 $y2
+ }
+ } else {
+ lappend coords $x2 $y2
+ }
+ set t [$canv create line $coords -width [linewidth $p] \
+ -fill $colormap($p) -tags lines.$p]
+ $canv lower $t
+ bindline $t $p
}
if {$rmx > [lindex $idpos($id) 1]} {
- lset idpos($id) 1 $rmx
- redrawtags $id
+ lset idpos($id) 1 $rmx
+ redrawtags $id
}
}
@@ -6122,35 +6140,35 @@ proc drawcmittext {id row col} {
# listed is 0 for boundary, 1 for normal, 2 for negative, 3 for left, 4 for right
set listed $cmitlisted($curview,$id)
if {$id eq $nullid} {
- set ofill $workingfilescirclecolor
+ set ofill $workingfilescirclecolor
} elseif {$id eq $nullid2} {
- set ofill $indexcirclecolor
+ set ofill $indexcirclecolor
} elseif {$id eq $mainheadid} {
- set ofill $mainheadcirclecolor
+ set ofill $mainheadcirclecolor
} else {
- set ofill [lindex $circlecolors $listed]
+ set ofill [lindex $circlecolors $listed]
}
set x [xc $row $col]
set y [yc $row]
set orad [expr {$linespc / 3}]
if {$listed <= 2} {
- set t [$canv create oval [expr {$x - $orad}] [expr {$y - $orad}] \
- [expr {$x + $orad - 1}] [expr {$y + $orad - 1}] \
- -fill $ofill -outline $circleoutlinecolor -width 1 -tags circle]
+ set t [$canv create oval [expr {$x - $orad}] [expr {$y - $orad}] \
+ [expr {$x + $orad - 1}] [expr {$y + $orad - 1}] \
+ -fill $ofill -outline $circleoutlinecolor -width 1 -tags circle]
} elseif {$listed == 3} {
- # triangle pointing left for left-side commits
- set t [$canv create polygon \
- [expr {$x - $orad}] $y \
- [expr {$x + $orad - 1}] [expr {$y - $orad}] \
- [expr {$x + $orad - 1}] [expr {$y + $orad - 1}] \
- -fill $ofill -outline $circleoutlinecolor -width 1 -tags circle]
+ # triangle pointing left for left-side commits
+ set t [$canv create polygon \
+ [expr {$x - $orad}] $y \
+ [expr {$x + $orad - 1}] [expr {$y - $orad}] \
+ [expr {$x + $orad - 1}] [expr {$y + $orad - 1}] \
+ -fill $ofill -outline $circleoutlinecolor -width 1 -tags circle]
} else {
- # triangle pointing right for right-side commits
- set t [$canv create polygon \
- [expr {$x + $orad - 1}] $y \
- [expr {$x - $orad}] [expr {$y - $orad}] \
- [expr {$x - $orad}] [expr {$y + $orad - 1}] \
- -fill $ofill -outline $circleoutlinecolor -width 1 -tags circle]
+ # triangle pointing right for right-side commits
+ set t [$canv create polygon \
+ [expr {$x + $orad - 1}] $y \
+ [expr {$x - $orad}] [expr {$y - $orad}] \
+ [expr {$x - $orad}] [expr {$y + $orad - 1}] \
+ -fill $ofill -outline $circleoutlinecolor -width 1 -tags circle]
}
set circleitem($row) $t
$canv raise $t
@@ -6158,23 +6176,23 @@ proc drawcmittext {id row col} {
set rmx [llength [lindex $rowidlist $row]]
set olds [lindex $parentlist $row]
if {$olds ne {}} {
- set nextids [lindex $rowidlist [expr {$row + 1}]]
- foreach p $olds {
- set i [lsearch -exact $nextids $p]
- if {$i > $rmx} {
- set rmx $i
- }
- }
+ set nextids [lindex $rowidlist [expr {$row + 1}]]
+ foreach p $olds {
+ set i [lsearch -exact $nextids $p]
+ if {$i > $rmx} {
+ set rmx $i
+ }
+ }
}
set xt [xc $row $rmx]
set rowtextx($row) $xt
set idpos($id) [list $x $xt $y]
if {[info exists idtags($id)] || [info exists idheads($id)]
- || [info exists idotherrefs($id)]} {
- set xt [drawtags $id $x $xt $y]
+ || [info exists idotherrefs($id)]} {
+ set xt [drawtags $id $x $xt $y]
}
if {[lindex $commitinfo($id) 6] > 0} {
- set xt [drawnotesign $xt $y]
+ set xt [drawnotesign $xt $y]
}
set headline [lindex $commitinfo($id) 0]
set name [lindex $commitinfo($id) 1]
@@ -6184,30 +6202,30 @@ proc drawcmittext {id row col} {
set nfont mainfont
set isbold [ishighlighted $id]
if {$isbold > 0} {
- lappend boldids $id
- set font mainfontbold
- if {$isbold > 1} {
- lappend boldnameids $id
- set nfont mainfontbold
- }
+ lappend boldids $id
+ set font mainfontbold
+ if {$isbold > 1} {
+ lappend boldnameids $id
+ set nfont mainfontbold
+ }
}
set linehtag($id) [$canv create text $xt $y -anchor w -fill $fgcolor \
- -text $headline -font $font -tags text]
+ -text $headline -font $font -tags text]
$canv bind $linehtag($id) $ctxbut "rowmenu %X %Y $id"
set linentag($id) [$canv2 create text 3 $y -anchor w -fill $fgcolor \
- -text $name -font $nfont -tags text]
+ -text $name -font $nfont -tags text]
set linedtag($id) [$canv3 create text 3 $y -anchor w -fill $fgcolor \
- -text $date -font mainfont -tags text]
+ -text $date -font mainfont -tags text]
if {$selectedline == $row} {
- make_secsel $id
+ make_secsel $id
}
if {[info exists markedid] && $markedid eq $id} {
- make_idmark $id
+ make_idmark $id
}
set xr [expr {$xt + [font measure $font $headline]}]
if {$xr > $canvxmax} {
- set canvxmax $xr
- setcanvscroll
+ set canvxmax $xr
+ setcanvscroll
}
}
@@ -6223,33 +6241,33 @@ proc drawcmitrow {row} {
set id [lindex $displayorder $row]
if {[info exists hlview] && ![info exists vhighlights($id)]} {
- askvhighlight $row $id
+ askvhighlight $row $id
}
if {[info exists filehighlight] && ![info exists fhighlights($id)]} {
- askfilehighlight $row $id
+ askfilehighlight $row $id
}
if {$findpattern ne {} && ![info exists nhighlights($id)]} {
- askfindhighlight $row $id
+ askfindhighlight $row $id
}
if {$highlight_related ne [mc "None"] && ![info exists rhighlights($id)]} {
- askrelhighlight $row $id
+ askrelhighlight $row $id
}
if {![info exists iddrawn($id)]} {
- set col [lsearch -exact [lindex $rowidlist $row] $id]
- if {$col < 0} {
- puts "oops, row $row id $id not in list"
- return
- }
- if {![info exists commitinfo($id)]} {
- getcommit $id
- }
- assigncolor $id
- drawcmittext $id $row $col
- set iddrawn($id) 1
- incr nrows_drawn
+ set col [lsearch -exact [lindex $rowidlist $row] $id]
+ if {$col < 0} {
+ puts "oops, row $row id $id not in list"
+ return
+ }
+ if {![info exists commitinfo($id)]} {
+ getcommit $id
+ }
+ assigncolor $id
+ drawcmittext $id $row $col
+ set iddrawn($id) 1
+ incr nrows_drawn
}
if {$markingmatches} {
- markrowmatches $row $id
+ markrowmatches $row $id
}
}
@@ -6258,78 +6276,78 @@ proc drawcommits {row {endrow {}}} {
global parentlist rowidlist rowfinal uparrowlen downarrowlen nrows_drawn
if {$row < 0} {
- set row 0
+ set row 0
}
if {$endrow eq {}} {
- set endrow $row
+ set endrow $row
}
if {$endrow >= $numcommits} {
- set endrow [expr {$numcommits - 1}]
+ set endrow [expr {$numcommits - 1}]
}
set rl1 [expr {$row - $downarrowlen - 3}]
if {$rl1 < 0} {
- set rl1 0
+ set rl1 0
}
set ro1 [expr {$row - 3}]
if {$ro1 < 0} {
- set ro1 0
+ set ro1 0
}
set r2 [expr {$endrow + $uparrowlen + 3}]
if {$r2 > $numcommits} {
- set r2 $numcommits
+ set r2 $numcommits
}
for {set r $rl1} {$r < $r2} {incr r} {
- if {[lindex $rowidlist $r] ne {} && [lindex $rowfinal $r]} {
- if {$rl1 < $r} {
- layoutrows $rl1 $r
- }
- set rl1 [expr {$r + 1}]
- }
+ if {[lindex $rowidlist $r] ne {} && [lindex $rowfinal $r]} {
+ if {$rl1 < $r} {
+ layoutrows $rl1 $r
+ }
+ set rl1 [expr {$r + 1}]
+ }
}
if {$rl1 < $r} {
- layoutrows $rl1 $r
+ layoutrows $rl1 $r
}
optimize_rows $ro1 0 $r2
if {$need_redisplay || $nrows_drawn > 2000} {
- clear_display
+ clear_display
}
# make the lines join to already-drawn rows either side
set r [expr {$row - 1}]
if {$r < 0 || ![info exists iddrawn([lindex $displayorder $r])]} {
- set r $row
+ set r $row
}
set er [expr {$endrow + 1}]
if {$er >= $numcommits ||
- ![info exists iddrawn([lindex $displayorder $er])]} {
- set er $endrow
+ ![info exists iddrawn([lindex $displayorder $er])]} {
+ set er $endrow
}
for {} {$r <= $er} {incr r} {
- set id [lindex $displayorder $r]
- set wasdrawn [info exists iddrawn($id)]
- drawcmitrow $r
- if {$r == $er} break
- set nextid [lindex $displayorder [expr {$r + 1}]]
- if {$wasdrawn && [info exists iddrawn($nextid)]} continue
- drawparentlinks $id $r
-
- set rowids [lindex $rowidlist $r]
- foreach lid $rowids {
- if {$lid eq {}} continue
- if {[info exists lineend($lid)] && $lineend($lid) > $r} continue
- if {$lid eq $id} {
- # see if this is the first child of any of its parents
- foreach p [lindex $parentlist $r] {
- if {[lsearch -exact $rowids $p] < 0} {
- # make this line extend up to the child
- set lineend($p) [drawlineseg $p $r $er 0]
- }
- }
- } else {
- set lineend($lid) [drawlineseg $lid $r $er 1]
- }
- }
+ set id [lindex $displayorder $r]
+ set wasdrawn [info exists iddrawn($id)]
+ drawcmitrow $r
+ if {$r == $er} break
+ set nextid [lindex $displayorder [expr {$r + 1}]]
+ if {$wasdrawn && [info exists iddrawn($nextid)]} continue
+ drawparentlinks $id $r
+
+ set rowids [lindex $rowidlist $r]
+ foreach lid $rowids {
+ if {$lid eq {}} continue
+ if {[info exists lineend($lid)] && $lineend($lid) > $r} continue
+ if {$lid eq $id} {
+ # see if this is the first child of any of its parents
+ foreach p [lindex $parentlist $r] {
+ if {[lsearch -exact $rowids $p] < 0} {
+ # make this line extend up to the child
+ set lineend($p) [drawlineseg $p $r $er 0]
+ }
+ }
+ } else {
+ set lineend($lid) [drawlineseg $lid $r $er 1]
+ }
+ }
}
}
@@ -6339,15 +6357,15 @@ proc undolayout {row} {
set r [expr {$row - ($uparrowlen + $mingaplen + $downarrowlen)}]
if {$r < 0} {
- set r 0
+ set r 0
}
if {[llength $rowidlist] > $r} {
- incr r -1
- set rowidlist [lrange $rowidlist 0 $r]
- set rowfinal [lrange $rowfinal 0 $r]
- set rowisopt [lrange $rowisopt 0 $r]
- set need_redisplay 1
- run drawvisible
+ incr r -1
+ set rowidlist [lrange $rowidlist 0 $r]
+ set rowfinal [lrange $rowfinal 0 $r]
+ set rowisopt [lrange $rowisopt 0 $r]
+ set need_redisplay 1
+ run drawvisible
}
}
@@ -6364,44 +6382,44 @@ proc drawvisible {} {
set y1 [expr {int($f1 * $ymax)}]
if {[info exists targetid]} {
- if {[commitinview $targetid $curview]} {
- set r [rowofcommit $targetid]
- if {$r != $targetrow} {
- # Fix up the scrollregion and change the scrolling position
- # now that our target row has moved.
- set diff [expr {($r - $targetrow) * $linespc}]
- set targetrow $r
- setcanvscroll
- set ymax [lindex [$canv cget -scrollregion] 3]
- incr y0 $diff
- incr y1 $diff
- set f0 [expr {$y0 / $ymax}]
- set f1 [expr {$y1 / $ymax}]
- allcanvs yview moveto $f0
- $cscroll set $f0 $f1
- set need_redisplay 1
- }
- } else {
- unset targetid
- }
+ if {[commitinview $targetid $curview]} {
+ set r [rowofcommit $targetid]
+ if {$r != $targetrow} {
+ # Fix up the scrollregion and change the scrolling position
+ # now that our target row has moved.
+ set diff [expr {($r - $targetrow) * $linespc}]
+ set targetrow $r
+ setcanvscroll
+ set ymax [lindex [$canv cget -scrollregion] 3]
+ incr y0 $diff
+ incr y1 $diff
+ set f0 [expr {$y0 / $ymax}]
+ set f1 [expr {$y1 / $ymax}]
+ allcanvs yview moveto $f0
+ $cscroll set $f0 $f1
+ set need_redisplay 1
+ }
+ } else {
+ unset targetid
+ }
}
set row [expr {int(($y0 - 3) / $linespc) - 1}]
set endrow [expr {int(($y1 - 3) / $linespc) + 1}]
if {$endrow >= $vrowmod($curview)} {
- update_arcrows $curview
+ update_arcrows $curview
}
if {$selectedline ne {} &&
- $row <= $selectedline && $selectedline <= $endrow} {
- set targetrow $selectedline
+ $row <= $selectedline && $selectedline <= $endrow} {
+ set targetrow $selectedline
} elseif {[info exists targetid]} {
- set targetrow [expr {int(($row + $endrow) / 2)}]
+ set targetrow [expr {int(($row + $endrow) / 2)}]
}
if {[info exists targetrow]} {
- if {$targetrow >= $numcommits} {
- set targetrow [expr {$numcommits - 1}]
- }
- set targetid [commitonrow $targetrow]
+ if {$targetrow >= $numcommits} {
+ set targetrow [expr {$numcommits - 1}]
+ }
+ set targetid [commitonrow $targetrow]
}
drawcommits $row $endrow
}
@@ -6433,31 +6451,31 @@ proc findcrossings {id} {
set cross {}
set ccross {}
foreach {s e} [rowranges $id] {
- if {$e >= $numcommits} {
- set e [expr {$numcommits - 1}]
- }
- if {$e <= $s} continue
- for {set row $e} {[incr row -1] >= $s} {} {
- set x [lsearch -exact [lindex $rowidlist $row] $id]
- if {$x < 0} break
- set olds [lindex $parentlist $row]
- set kid [lindex $displayorder $row]
- set kidx [lsearch -exact [lindex $rowidlist $row] $kid]
- if {$kidx < 0} continue
- set nextrow [lindex $rowidlist [expr {$row + 1}]]
- foreach p $olds {
- set px [lsearch -exact $nextrow $p]
- if {$px < 0} continue
- if {($kidx < $x && $x < $px) || ($px < $x && $x < $kidx)} {
- if {[lsearch -exact $ccross $p] >= 0} continue
- if {$x == $px + ($kidx < $px? -1: 1)} {
- lappend ccross $p
- } elseif {[lsearch -exact $cross $p] < 0} {
- lappend cross $p
- }
- }
- }
- }
+ if {$e >= $numcommits} {
+ set e [expr {$numcommits - 1}]
+ }
+ if {$e <= $s} continue
+ for {set row $e} {[incr row -1] >= $s} {} {
+ set x [lsearch -exact [lindex $rowidlist $row] $id]
+ if {$x < 0} break
+ set olds [lindex $parentlist $row]
+ set kid [lindex $displayorder $row]
+ set kidx [lsearch -exact [lindex $rowidlist $row] $kid]
+ if {$kidx < 0} continue
+ set nextrow [lindex $rowidlist [expr {$row + 1}]]
+ foreach p $olds {
+ set px [lsearch -exact $nextrow $p]
+ if {$px < 0} continue
+ if {($kidx < $x && $x < $px) || ($px < $x && $x < $kidx)} {
+ if {[lsearch -exact $ccross $p] >= 0} continue
+ if {$x == $px + ($kidx < $px? -1: 1)} {
+ lappend ccross $p
+ } elseif {[lsearch -exact $cross $p] < 0} {
+ lappend cross $p
+ }
+ }
+ }
+ }
}
return [concat $ccross {{}} $cross]
}
@@ -6469,58 +6487,58 @@ proc assigncolor {id} {
if {[info exists colormap($id)]} return
set ncolors [llength $colors]
if {[info exists children($curview,$id)]} {
- set kids $children($curview,$id)
+ set kids $children($curview,$id)
} else {
- set kids {}
+ set kids {}
}
if {[llength $kids] == 1} {
- set child [lindex $kids 0]
- if {[info exists colormap($child)]
- && [llength $parents($curview,$child)] == 1} {
- set colormap($id) $colormap($child)
- return
- }
+ set child [lindex $kids 0]
+ if {[info exists colormap($child)]
+ && [llength $parents($curview,$child)] == 1} {
+ set colormap($id) $colormap($child)
+ return
+ }
}
set badcolors {}
set origbad {}
foreach x [findcrossings $id] {
- if {$x eq {}} {
- # delimiter between corner crossings and other crossings
- if {[llength $badcolors] >= $ncolors - 1} break
- set origbad $badcolors
- }
- if {[info exists colormap($x)]
- && [lsearch -exact $badcolors $colormap($x)] < 0} {
- lappend badcolors $colormap($x)
- }
+ if {$x eq {}} {
+ # delimiter between corner crossings and other crossings
+ if {[llength $badcolors] >= $ncolors - 1} break
+ set origbad $badcolors
+ }
+ if {[info exists colormap($x)]
+ && [lsearch -exact $badcolors $colormap($x)] < 0} {
+ lappend badcolors $colormap($x)
+ }
}
if {[llength $badcolors] >= $ncolors} {
- set badcolors $origbad
+ set badcolors $origbad
}
set origbad $badcolors
if {[llength $badcolors] < $ncolors - 1} {
- foreach child $kids {
- if {[info exists colormap($child)]
- && [lsearch -exact $badcolors $colormap($child)] < 0} {
- lappend badcolors $colormap($child)
- }
- foreach p $parents($curview,$child) {
- if {[info exists colormap($p)]
- && [lsearch -exact $badcolors $colormap($p)] < 0} {
- lappend badcolors $colormap($p)
- }
- }
- }
- if {[llength $badcolors] >= $ncolors} {
- set badcolors $origbad
- }
+ foreach child $kids {
+ if {[info exists colormap($child)]
+ && [lsearch -exact $badcolors $colormap($child)] < 0} {
+ lappend badcolors $colormap($child)
+ }
+ foreach p $parents($curview,$child) {
+ if {[info exists colormap($p)]
+ && [lsearch -exact $badcolors $colormap($p)] < 0} {
+ lappend badcolors $colormap($p)
+ }
+ }
+ }
+ if {[llength $badcolors] >= $ncolors} {
+ set badcolors $origbad
+ }
}
for {set i 0} {$i <= $ncolors} {incr i} {
- set c [lindex $colors $nextcolor]
- if {[incr nextcolor] >= $ncolors} {
- set nextcolor 0
- }
- if {[lsearch -exact $badcolors $c]} break
+ set c [lindex $colors $nextcolor]
+ if {[incr nextcolor] >= $ncolors} {
+ set nextcolor 0
+ }
+ if {[lsearch -exact $badcolors $c]} break
}
set colormap($id) $c
}
@@ -6538,9 +6556,9 @@ proc graph_pane_width {} {
global use_ttk
if {$use_ttk} {
- set g [.tf.histframe.pwclist sashpos 0]
+ set g [.tf.histframe.pwclist sashpos 0]
} else {
- set g [.tf.histframe.pwclist sash coord 0]
+ set g [.tf.histframe.pwclist sash coord 0]
}
return [lindex $g 0]
}
@@ -6548,7 +6566,7 @@ proc graph_pane_width {} {
proc totalwidth {l font extra} {
set tot 0
foreach str $l {
- set tot [expr {$tot + [font measure $font $str] + $extra}]
+ set tot [expr {$tot + [font measure $font $str] + $extra}]
}
return $tot
}
@@ -6572,29 +6590,29 @@ proc drawtags {id x xt y1} {
set extra [expr {$delta + $lthickness + $linespc}]
if {[info exists idtags($id)]} {
- set marks $idtags($id)
- set ntags [llength $marks]
- if {$ntags > $maxtags ||
- [totalwidth $marks mainfont $extra] > $maxwidth} {
- # show just a single "n tags..." tag
- set singletag 1
- if {$ntags == 1} {
- set marks [list "tag..."]
- } else {
- set marks [list [format "%d tags..." $ntags]]
- }
- set ntags 1
- }
+ set marks $idtags($id)
+ set ntags [llength $marks]
+ if {$ntags > $maxtags ||
+ [totalwidth $marks mainfont $extra] > $maxwidth} {
+ # show just a single "n tags..." tag
+ set singletag 1
+ if {$ntags == 1} {
+ set marks [list "tag..."]
+ } else {
+ set marks [list [format "%d tags..." $ntags]]
+ }
+ set ntags 1
+ }
}
if {[info exists idheads($id)]} {
- set marks [concat $marks $idheads($id)]
- set nheads [llength $idheads($id)]
+ set marks [concat $marks $idheads($id)]
+ set nheads [llength $idheads($id)]
}
if {[info exists idotherrefs($id)]} {
- set marks [concat $marks $idotherrefs($id)]
+ set marks [concat $marks $idotherrefs($id)]
}
if {$marks eq {}} {
- return $xt
+ return $xt
}
set yt [expr {$y1 - 0.5 * $linespc}]
@@ -6603,66 +6621,66 @@ proc drawtags {id x xt y1} {
set wvals {}
set i -1
foreach tag $marks {
- incr i
- if {$i >= $ntags && $i < $ntags + $nheads && $tag eq $mainhead} {
- set wid [font measure mainfontbold $tag]
- } else {
- set wid [font measure mainfont $tag]
- }
- lappend xvals $xt
- lappend wvals $wid
- set xt [expr {$xt + $wid + $extra}]
+ incr i
+ if {$i >= $ntags && $i < $ntags + $nheads && $tag eq $mainhead} {
+ set wid [font measure mainfontbold $tag]
+ } else {
+ set wid [font measure mainfont $tag]
+ }
+ lappend xvals $xt
+ lappend wvals $wid
+ set xt [expr {$xt + $wid + $extra}]
}
set t [$canv create line $x $y1 [lindex $xvals end] $y1 \
- -width $lthickness -fill $reflinecolor -tags tag.$id]
+ -width $lthickness -fill $reflinecolor -tags tag.$id]
$canv lower $t
foreach tag $marks x $xvals wid $wvals {
- set tag_quoted [string map {% %%} $tag]
- set xl [expr {$x + $delta}]
- set xr [expr {$x + $delta + $wid + $lthickness}]
- set font mainfont
- if {[incr ntags -1] >= 0} {
- # draw a tag
- set t [$canv create polygon $x [expr {$yt + $delta}] $xl $yt \
- $xr $yt $xr $yb $xl $yb $x [expr {$yb - $delta}] \
- -width 1 -outline $tagoutlinecolor -fill $tagbgcolor \
- -tags tag.$id]
- if {$singletag} {
- set tagclick [list showtags $id 1]
- } else {
- set tagclick [list showtag $tag_quoted 1]
- }
- $canv bind $t <1> $tagclick
- set rowtextx([rowofcommit $id]) [expr {$xr + $linespc}]
- } else {
- # draw a head or other ref
- if {[incr nheads -1] >= 0} {
- set col $headbgcolor
- if {$tag eq $mainhead} {
- set font mainfontbold
- }
- } else {
- set col "#ddddff"
- }
- set xl [expr {$xl - $delta/2}]
- $canv create polygon $x $yt $xr $yt $xr $yb $x $yb \
- -width 1 -outline black -fill $col -tags tag.$id
- if {[regexp {^(remotes/.*/|remotes/)} $tag match remoteprefix]} {
- set rwid [font measure mainfont $remoteprefix]
- set xi [expr {$x + 1}]
- set yti [expr {$yt + 1}]
- set xri [expr {$x + $rwid}]
- $canv create polygon $xi $yti $xri $yti $xri $yb $xi $yb \
- -width 0 -fill $remotebgcolor -tags tag.$id
- }
- }
- set t [$canv create text $xl $y1 -anchor w -text $tag -fill $headfgcolor \
- -font $font -tags [list tag.$id text]]
- if {$ntags >= 0} {
- $canv bind $t <1> $tagclick
- } elseif {$nheads >= 0} {
- $canv bind $t $ctxbut [list headmenu %X %Y $id $tag_quoted]
- }
+ set tag_quoted [string map {% %%} $tag]
+ set xl [expr {$x + $delta}]
+ set xr [expr {$x + $delta + $wid + $lthickness}]
+ set font mainfont
+ if {[incr ntags -1] >= 0} {
+ # draw a tag
+ set t [$canv create polygon $x [expr {$yt + $delta}] $xl $yt \
+ $xr $yt $xr $yb $xl $yb $x [expr {$yb - $delta}] \
+ -width 1 -outline $tagoutlinecolor -fill $tagbgcolor \
+ -tags tag.$id]
+ if {$singletag} {
+ set tagclick [list showtags $id 1]
+ } else {
+ set tagclick [list showtag $tag_quoted 1]
+ }
+ $canv bind $t <1> $tagclick
+ set rowtextx([rowofcommit $id]) [expr {$xr + $linespc}]
+ } else {
+ # draw a head or other ref
+ if {[incr nheads -1] >= 0} {
+ set col $headbgcolor
+ if {$tag eq $mainhead} {
+ set font mainfontbold
+ }
+ } else {
+ set col "#ddddff"
+ }
+ set xl [expr {$xl - $delta/2}]
+ $canv create polygon $x $yt $xr $yt $xr $yb $x $yb \
+ -width 1 -outline black -fill $col -tags tag.$id
+ if {[regexp {^(remotes/.*/|remotes/)} $tag match remoteprefix]} {
+ set rwid [font measure mainfont $remoteprefix]
+ set xi [expr {$x + 1}]
+ set yti [expr {$yt + 1}]
+ set xri [expr {$x + $rwid}]
+ $canv create polygon $xi $yti $xri $yti $xri $yb $xi $yb \
+ -width 0 -fill $remotebgcolor -tags tag.$id
+ }
+ }
+ set t [$canv create text $xl $y1 -anchor w -text $tag -fill $headfgcolor \
+ -font $font -tags [list tag.$id text]]
+ if {$ntags >= 0} {
+ $canv bind $t <1> $tagclick
+ } elseif {$nheads >= 0} {
+ $canv bind $t $ctxbut [list headmenu %X %Y $id $tag_quoted]
+ }
}
return $xt
}
@@ -6672,8 +6690,8 @@ proc drawnotesign {xt y} {
set orad [expr {$linespc / 3}]
set t [$canv create rectangle [expr {$xt - $orad}] [expr {$y - $orad}] \
- [expr {$xt + $orad - 1}] [expr {$y + $orad - 1}] \
- -fill yellow -outline $fgcolor -width 1 -tags circle]
+ [expr {$xt + $orad - 1}] [expr {$y + $orad - 1}] \
+ -fill yellow -outline $fgcolor -width 1 -tags circle]
set xt [expr {$xt + $orad * 3}]
return $xt
}
@@ -6683,9 +6701,9 @@ proc xcoord {i level ln} {
set x [expr {$canvx0 + $i * $xspc1($ln)}]
if {$i > 0 && $i == $level} {
- set x [expr {$x + 0.5 * ($xspc2 - $xspc1($ln))}]
+ set x [expr {$x + 0.5 * ($xspc2 - $xspc1($ln))}]
} elseif {$i > $level} {
- set x [expr {$x + $xspc2 - $xspc1($ln)}]
+ set x [expr {$x + $xspc2 - $xspc1($ln)}]
}
return $x
}
@@ -6696,7 +6714,7 @@ proc show_status {msg} {
clear_display
set_window_title
$canv create text 3 3 -anchor nw -text $msg -font mainfont \
- -tags text -fill $fgcolor
+ -tags text -fill $fgcolor
}
# Don't change the text pane cursor if it is currently the hand cursor,
@@ -6705,7 +6723,7 @@ proc settextcursor {c} {
global ctext curtextcursor
if {[$ctext cget -cursor] == $curtextcursor} {
- $ctext config -cursor $c
+ $ctext config -cursor $c
}
set curtextcursor $c
}
@@ -6714,13 +6732,13 @@ proc nowbusy {what {name {}}} {
global isbusy busyname statusw
if {[array names isbusy] eq {}} {
- . config -cursor watch
- settextcursor watch
+ . config -cursor watch
+ settextcursor watch
}
set isbusy($what) 1
set busyname($what) $name
if {$name ne {}} {
- $statusw conf -text $name
+ $statusw conf -text $name
}
}
@@ -6728,35 +6746,35 @@ proc notbusy {what} {
global isbusy maincursor textcursor busyname statusw
catch {
- unset isbusy($what)
- if {$busyname($what) ne {} &&
- [$statusw cget -text] eq $busyname($what)} {
- $statusw conf -text {}
- }
+ unset isbusy($what)
+ if {$busyname($what) ne {} &&
+ [$statusw cget -text] eq $busyname($what)} {
+ $statusw conf -text {}
+ }
}
if {[array names isbusy] eq {}} {
- . config -cursor $maincursor
- settextcursor $textcursor
+ . config -cursor $maincursor
+ settextcursor $textcursor
}
}
proc findmatches {f} {
global findtype findstring
if {$findtype == [mc "Regexp"]} {
- set matches [regexp -indices -all -inline $findstring $f]
+ set matches [regexp -indices -all -inline $findstring $f]
} else {
- set fs $findstring
- if {$findtype == [mc "IgnCase"]} {
- set f [string tolower $f]
- set fs [string tolower $fs]
- }
- set matches {}
- set i 0
- set l [string length $fs]
- while {[set j [string first $fs $f $i]] >= 0} {
- lappend matches [list $j [expr {$j+$l-1}]]
- set i [expr {$j + $l}]
- }
+ set fs $findstring
+ if {$findtype == [mc "IgnCase"]} {
+ set f [string tolower $f]
+ set fs [string tolower $fs]
+ }
+ set matches {}
+ set i 0
+ set l [string length $fs]
+ while {[set j [string first $fs $f $i]] >= 0} {
+ lappend matches [list $j [expr {$j+$l-1}]]
+ set i [expr {$j + $l}]
+ }
}
return $matches
}
@@ -6766,21 +6784,21 @@ proc dofind {{dirn 1} {wrap 1}} {
global gdttype filehighlight fh_serial find_dirn findallowwrap
if {[info exists find_dirn]} {
- if {$find_dirn == $dirn} return
- stopfinding
+ if {$find_dirn == $dirn} return
+ stopfinding
}
focus .
if {$findstring eq {} || $numcommits == 0} return
if {$selectedline eq {}} {
- set findstartline [lindex [visiblerows] [expr {$dirn < 0}]]
+ set findstartline [lindex [visiblerows] [expr {$dirn < 0}]]
} else {
- set findstartline $selectedline
+ set findstartline $selectedline
}
set findcurline $findstartline
nowbusy finding [mc "Searching"]
if {$gdttype ne [mc "containing:"] && ![info exists filehighlight]} {
- after cancel do_file_hl $fh_serial
- do_file_hl $fh_serial
+ after cancel do_file_hl $fh_serial
+ do_file_hl $fh_serial
}
set find_dirn $dirn
set findallowwrap $wrap
@@ -6791,11 +6809,11 @@ proc stopfinding {} {
global find_dirn findcurline fprogcoord
if {[info exists find_dirn]} {
- unset find_dirn
- unset findcurline
- notbusy finding
- set fprogcoord 0
- adjustprogress
+ unset find_dirn
+ unset findcurline
+ notbusy finding
+ set fprogcoord 0
+ adjustprogress
}
stopblaming
}
@@ -6807,41 +6825,41 @@ proc findmore {} {
global curview varcorder vrownum varccommits vrowmod
if {![info exists find_dirn]} {
- return 0
+ return 0
}
set fldtypes [list [mc "Headline"] [mc "Author"] "" [mc "Committer"] "" [mc "Comments"]]
set l $findcurline
set moretodo 0
if {$find_dirn > 0} {
- incr l
- if {$l >= $numcommits} {
- set l 0
- }
- if {$l <= $findstartline} {
- set lim [expr {$findstartline + 1}]
- } else {
- set lim $numcommits
- set moretodo $findallowwrap
- }
+ incr l
+ if {$l >= $numcommits} {
+ set l 0
+ }
+ if {$l <= $findstartline} {
+ set lim [expr {$findstartline + 1}]
+ } else {
+ set lim $numcommits
+ set moretodo $findallowwrap
+ }
} else {
- if {$l == 0} {
- set l $numcommits
- }
- incr l -1
- if {$l >= $findstartline} {
- set lim [expr {$findstartline - 1}]
- } else {
- set lim -1
- set moretodo $findallowwrap
- }
+ if {$l == 0} {
+ set l $numcommits
+ }
+ incr l -1
+ if {$l >= $findstartline} {
+ set lim [expr {$findstartline - 1}]
+ } else {
+ set lim -1
+ set moretodo $findallowwrap
+ }
}
set n [expr {($lim - $l) * $find_dirn}]
if {$n > 500} {
- set n 500
- set moretodo 1
+ set n 500
+ set moretodo 1
}
if {$l + ($find_dirn > 0? $n: 1) > $vrowmod($curview)} {
- update_arcrows $curview
+ update_arcrows $curview
}
set found 0
set domore 1
@@ -6851,81 +6869,81 @@ proc findmore {} {
set ids [lindex $varccommits($curview,$a)]
set arowend [expr {$arow + [llength $ids]}]
if {$gdttype eq [mc "containing:"]} {
- for {} {$n > 0} {incr n -1; incr l $find_dirn} {
- if {$l < $arow || $l >= $arowend} {
- incr ai $find_dirn
- set a [lindex $varcorder($curview) $ai]
- set arow [lindex $vrownum($curview) $ai]
- set ids [lindex $varccommits($curview,$a)]
- set arowend [expr {$arow + [llength $ids]}]
- }
- set id [lindex $ids [expr {$l - $arow}]]
- # shouldn't happen unless git log doesn't give all the commits...
- if {![info exists commitdata($id)] ||
- ![doesmatch $commitdata($id)]} {
- continue
- }
- if {![info exists commitinfo($id)]} {
- getcommit $id
- }
- set info $commitinfo($id)
- foreach f $info ty $fldtypes {
- if {$ty eq ""} continue
- if {($findloc eq [mc "All fields"] || $findloc eq $ty) &&
- [doesmatch $f]} {
- set found 1
- break
- }
- }
- if {$found} break
- }
+ for {} {$n > 0} {incr n -1; incr l $find_dirn} {
+ if {$l < $arow || $l >= $arowend} {
+ incr ai $find_dirn
+ set a [lindex $varcorder($curview) $ai]
+ set arow [lindex $vrownum($curview) $ai]
+ set ids [lindex $varccommits($curview,$a)]
+ set arowend [expr {$arow + [llength $ids]}]
+ }
+ set id [lindex $ids [expr {$l - $arow}]]
+ # shouldn't happen unless git log doesn't give all the commits...
+ if {![info exists commitdata($id)] ||
+ ![doesmatch $commitdata($id)]} {
+ continue
+ }
+ if {![info exists commitinfo($id)]} {
+ getcommit $id
+ }
+ set info $commitinfo($id)
+ foreach f $info ty $fldtypes {
+ if {$ty eq ""} continue
+ if {($findloc eq [mc "All fields"] || $findloc eq $ty) &&
+ [doesmatch $f]} {
+ set found 1
+ break
+ }
+ }
+ if {$found} break
+ }
} else {
- for {} {$n > 0} {incr n -1; incr l $find_dirn} {
- if {$l < $arow || $l >= $arowend} {
- incr ai $find_dirn
- set a [lindex $varcorder($curview) $ai]
- set arow [lindex $vrownum($curview) $ai]
- set ids [lindex $varccommits($curview,$a)]
- set arowend [expr {$arow + [llength $ids]}]
- }
- set id [lindex $ids [expr {$l - $arow}]]
- if {![info exists fhighlights($id)]} {
- # this sets fhighlights($id) to -1
- askfilehighlight $l $id
- }
- if {$fhighlights($id) > 0} {
- set found $domore
- break
- }
- if {$fhighlights($id) < 0} {
- if {$domore} {
- set domore 0
- set findcurline [expr {$l - $find_dirn}]
- }
- }
- }
+ for {} {$n > 0} {incr n -1; incr l $find_dirn} {
+ if {$l < $arow || $l >= $arowend} {
+ incr ai $find_dirn
+ set a [lindex $varcorder($curview) $ai]
+ set arow [lindex $vrownum($curview) $ai]
+ set ids [lindex $varccommits($curview,$a)]
+ set arowend [expr {$arow + [llength $ids]}]
+ }
+ set id [lindex $ids [expr {$l - $arow}]]
+ if {![info exists fhighlights($id)]} {
+ # this sets fhighlights($id) to -1
+ askfilehighlight $l $id
+ }
+ if {$fhighlights($id) > 0} {
+ set found $domore
+ break
+ }
+ if {$fhighlights($id) < 0} {
+ if {$domore} {
+ set domore 0
+ set findcurline [expr {$l - $find_dirn}]
+ }
+ }
+ }
}
if {$found || ($domore && !$moretodo)} {
- unset findcurline
- unset find_dirn
- notbusy finding
- set fprogcoord 0
- adjustprogress
- if {$found} {
- findselectline $l
- } else {
- bell
- }
- return 0
+ unset findcurline
+ unset find_dirn
+ notbusy finding
+ set fprogcoord 0
+ adjustprogress
+ if {$found} {
+ findselectline $l
+ } else {
+ bell
+ }
+ return 0
}
if {!$domore} {
- flushhighlights
+ flushhighlights
} else {
- set findcurline [expr {$l - $find_dirn}]
+ set findcurline [expr {$l - $find_dirn}]
}
set n [expr {($findcurline - $findstartline) * $find_dirn - 1}]
if {$n < 0} {
- incr n $numcommits
+ incr n $numcommits
}
set fprogcoord [expr {$n * 1.0 / $numcommits}]
adjustprogress
@@ -6939,15 +6957,15 @@ proc findselectline {l} {
set findcurline $l
selectline $l 1
if {$markingmatches &&
- ($findloc eq [mc "All fields"] || $findloc eq [mc "Comments"])} {
- # highlight the matches in the comments
- set f [$ctext get 1.0 $commentend]
- set matches [findmatches $f]
- foreach match $matches {
- set start [lindex $match 0]
- set end [expr {[lindex $match 1] + 1}]
- $ctext tag add found "1.0 + $start c" "1.0 + $end c"
- }
+ ($findloc eq [mc "All fields"] || $findloc eq [mc "Comments"])} {
+ # highlight the matches in the comments
+ set f [$ctext get 1.0 $commentend]
+ set matches [findmatches $f]
+ foreach match $matches {
+ set start [lindex $match 0]
+ set end [expr {[lindex $match 1] + 1}]
+ $ctext tag add found "1.0 + $start c" "1.0 + $end c"
+ }
}
drawvisible
}
@@ -6961,18 +6979,18 @@ proc markmatches {canv l str tag matches font row} {
set y0 [lindex $bbox 1]
set y1 [lindex $bbox 3]
foreach match $matches {
- set start [lindex $match 0]
- set end [lindex $match 1]
- if {$start > $end} continue
- set xoff [font measure $font [string range $str 0 [expr {$start-1}]]]
- set xlen [font measure $font [string range $str 0 [expr {$end}]]]
- set t [$canv create rect [expr {$x0+$xoff}] $y0 \
- [expr {$x0+$xlen+2}] $y1 \
- -outline {} -tags [list match$l matches] -fill yellow]
- $canv lower $t
- if {$row == $selectedline} {
- $canv raise $t secsel
- }
+ set start [lindex $match 0]
+ set end [lindex $match 1]
+ if {$start > $end} continue
+ set xoff [font measure $font [string range $str 0 [expr {$start-1}]]]
+ set xlen [font measure $font [string range $str 0 [expr {$end}]]]
+ set t [$canv create rect [expr {$x0+$xoff}] $y0 \
+ [expr {$x0+$xlen+2}] $y1 \
+ -outline {} -tags [list match$l matches] -fill yellow]
+ $canv lower $t
+ if {$row == $selectedline} {
+ $canv raise $t secsel
+ }
}
}
@@ -6993,12 +7011,12 @@ proc selcanvline {w x y} {
set y [expr {$y + $yfrac * $ymax}]
set l [expr {int(($y - $canvy0) / $linespc + 0.5)}]
if {$l < 0} {
- set l 0
+ set l 0
}
if {$w eq $canv} {
- set xmax [lindex [$canv cget -scrollregion] 2]
- set xleft [expr {[lindex [$canv xview] 0] * $xmax}]
- if {![info exists rowtextx($l)] || $xleft + $x < $rowtextx($l)} return
+ set xmax [lindex [$canv cget -scrollregion] 2]
+ set xleft [expr {[lindex [$canv xview] 0] * $xmax}]
+ if {![info exists rowtextx($l)] || $xleft + $x < $rowtextx($l)} return
}
unmarkmatches
selectline $l 1
@@ -7007,11 +7025,11 @@ proc selcanvline {w x y} {
proc commit_descriptor {p} {
global commitinfo
if {![info exists commitinfo($p)]} {
- getcommit $p
+ getcommit $p
}
set l "..."
if {[llength $commitinfo($p)] > 1} {
- set l [lindex $commitinfo($p) 0]
+ set l [lindex $commitinfo($p) 0]
}
return "$p ($l)\n"
}
@@ -7026,26 +7044,26 @@ proc appendwithlinks {text tags} {
$ctext insert end $text $tags
set links [regexp -indices -all -inline {(?:\m|-g)[0-9a-f]{6,40}\M} $text]
foreach l $links {
- set s [lindex $l 0]
- set e [lindex $l 1]
- set linkid [string range $text $s $e]
- incr e
- $ctext tag delete link$linknum
- $ctext tag add link$linknum "$start + $s c" "$start + $e c"
- setlink $linkid link$linknum
- incr linknum
+ set s [lindex $l 0]
+ set e [lindex $l 1]
+ set linkid [string range $text $s $e]
+ incr e
+ $ctext tag delete link$linknum
+ $ctext tag add link$linknum "$start + $s c" "$start + $e c"
+ setlink $linkid link$linknum
+ incr linknum
}
set wlinks [regexp -indices -all -inline -line \
- {https?://[^[:space:]]+} $text]
+ {https?://[^[:space:]]+} $text]
foreach l $wlinks {
- set s2 [lindex $l 0]
- set e2 [lindex $l 1]
- set url [string range $text $s2 $e2]
- incr e2
- $ctext tag delete link$linknum
- $ctext tag add link$linknum "$start + $s2 c" "$start + $e2 c"
- setwlink $url link$linknum
- incr linknum
+ set s2 [lindex $l 0]
+ set e2 [lindex $l 1]
+ set url [string range $text $s2 $e2]
+ incr e2
+ $ctext tag delete link$linknum
+ $ctext tag add link$linknum "$start + $s2 c" "$start + $e2 c"
+ setwlink $url link$linknum
+ incr linknum
}
}
@@ -7059,23 +7077,23 @@ proc setlink {id lk} {
set known 0
if {[string length $id] < 40} {
- set matches [longid $id]
- if {[llength $matches] > 0} {
- if {[llength $matches] > 1} return
- set known 1
- set id [lindex $matches 0]
- }
+ set matches [longid $id]
+ if {[llength $matches] > 0} {
+ if {[llength $matches] > 1} return
+ set known 1
+ set id [lindex $matches 0]
+ }
} else {
- set known [commitinview $id $curview]
+ set known [commitinview $id $curview]
}
if {$known} {
- $ctext tag conf $lk -foreground $linkfgcolor -underline 1
- $ctext tag bind $lk <1> [list selbyid $id]
- $ctext tag bind $lk <Enter> {linkcursor %W 1}
- $ctext tag bind $lk <Leave> {linkcursor %W -1}
+ $ctext tag conf $lk -foreground $linkfgcolor -underline 1
+ $ctext tag bind $lk <1> [list selbyid $id]
+ $ctext tag bind $lk <Enter> {linkcursor %W 1}
+ $ctext tag bind $lk <Leave> {linkcursor %W -1}
} else {
- lappend pendinglinks($id) $lk
- interestedin $id {makelink %P}
+ lappend pendinglinks($id) $lk
+ interestedin $id {makelink %P}
}
}
@@ -7107,7 +7125,7 @@ proc makelink {id} {
if {![info exists pendinglinks($id)]} return
foreach lk $pendinglinks($id) {
- setlink $id $lk
+ setlink $id $lk
}
unset pendinglinks($id)
}
@@ -7116,12 +7134,12 @@ proc linkcursor {w inc} {
global linkentercount curtextcursor
if {[incr linkentercount $inc] > 0} {
- $w configure -cursor hand2
+ $w configure -cursor hand2
} else {
- $w configure -cursor $curtextcursor
- if {$linkentercount < 0} {
- set linkentercount 0
- }
+ $w configure -cursor $curtextcursor
+ if {$linkentercount < 0} {
+ set linkentercount 0
+ }
}
}
@@ -7131,7 +7149,7 @@ proc browseweb {url} {
if {$web_browser eq {}} return
# Use eval here in case $web_browser is a command plus some arguments
if {[catch {eval exec $web_browser [list $url] &} err]} {
- error_popup "[mc "Error starting web browser:"] $err"
+ error_popup "[mc "Error starting web browser:"] $err"
}
}
@@ -7144,9 +7162,9 @@ proc viewnextline {dir} {
set wtop [expr {[lindex $wnow 0] * $ymax}]
set newtop [expr {$wtop + $dir * $linespc}]
if {$newtop < 0} {
- set newtop 0
+ set newtop 0
} elseif {$newtop > $ymax} {
- set newtop $ymax
+ set newtop $ymax
}
allcanvs yview moveto [expr {$newtop * 1.0 / $ymax}]
}
@@ -7157,15 +7175,15 @@ proc appendrefs {pos ids var} {
global ctext linknum curview $var maxrefs visiblerefs mainheadid
if {[catch {$ctext index $pos}]} {
- return 0
+ return 0
}
$ctext conf -state normal
$ctext delete $pos "$pos lineend"
set tags {}
foreach id $ids {
- foreach tag [set $var\($id\)] {
- lappend tags [list $tag $id]
- }
+ foreach tag [set $var\($id\)] {
+ lappend tags [list $tag $id]
+ }
}
set sep {}
@@ -7173,44 +7191,44 @@ proc appendrefs {pos ids var} {
set nutags 0
if {[llength $tags] > $maxrefs} {
- # If we are displaying heads, and there are too many,
- # see if there are some important heads to display.
- # Currently that are the current head and heads listed in $visiblerefs option
- set itags {}
- if {$var eq "idheads"} {
- set utags {}
- foreach ti $tags {
- set hname [lindex $ti 0]
- set id [lindex $ti 1]
- if {([lsearch -exact $visiblerefs $hname] != -1 || $id eq $mainheadid) &&
- [llength $itags] < $maxrefs} {
- lappend itags $ti
- } else {
- lappend utags $ti
- }
- }
- set tags $utags
- }
- if {$itags ne {}} {
- set str [mc "and many more"]
- set sep " "
- } else {
- set str [mc "many"]
- }
- $ctext insert $pos "$str ([llength $tags])"
- set nutags [llength $tags]
- set tags $itags
+ # If we are displaying heads, and there are too many,
+ # see if there are some important heads to display.
+ # Currently that are the current head and heads listed in $visiblerefs option
+ set itags {}
+ if {$var eq "idheads"} {
+ set utags {}
+ foreach ti $tags {
+ set hname [lindex $ti 0]
+ set id [lindex $ti 1]
+ if {([lsearch -exact $visiblerefs $hname] != -1 || $id eq $mainheadid) &&
+ [llength $itags] < $maxrefs} {
+ lappend itags $ti
+ } else {
+ lappend utags $ti
+ }
+ }
+ set tags $utags
+ }
+ if {$itags ne {}} {
+ set str [mc "and many more"]
+ set sep " "
+ } else {
+ set str [mc "many"]
+ }
+ $ctext insert $pos "$str ([llength $tags])"
+ set nutags [llength $tags]
+ set tags $itags
}
foreach ti $tags {
- set id [lindex $ti 1]
- set lk link$linknum
- incr linknum
- $ctext tag delete $lk
- $ctext insert $pos $sep
- $ctext insert $pos [lindex $ti 0] $lk
- setlink $id $lk
- set sep ", "
+ set id [lindex $ti 1]
+ set lk link$linknum
+ incr linknum
+ $ctext tag delete $lk
+ $ctext insert $pos $sep
+ $ctext insert $pos [lindex $ti 0] $lk
+ setlink $id $lk
+ set sep ", "
}
$ctext tag add wwrap "$pos linestart" "$pos lineend"
$ctext conf -state disabled
@@ -7224,11 +7242,11 @@ proc dispneartags {delay} {
if {$selectedline eq {} || !$showneartags} return
after cancel dispnexttag
if {$delay} {
- after 200 dispnexttag
- set tagphase -1
+ after 200 dispnexttag
+ set tagphase -1
} else {
- after idle dispnexttag
- set tagphase 0
+ after idle dispnexttag
+ set tagphase 0
}
}
@@ -7237,33 +7255,33 @@ proc dispnexttag {} {
if {$selectedline eq {} || !$showneartags} return
switch -- $tagphase {
- 0 {
- set dtags [desctags $currentid]
- if {$dtags ne {}} {
- appendrefs precedes $dtags idtags
- }
- }
- 1 {
- set atags [anctags $currentid]
- if {$atags ne {}} {
- appendrefs follows $atags idtags
- }
- }
- 2 {
- set dheads [descheads $currentid]
- if {$dheads ne {}} {
- if {[appendrefs branch $dheads idheads] > 1
- && [$ctext get "branch -3c"] eq "h"} {
- # turn "Branch" into "Branches"
- $ctext conf -state normal
- $ctext insert "branch -2c" "es"
- $ctext conf -state disabled
- }
- }
- }
+ 0 {
+ set dtags [desctags $currentid]
+ if {$dtags ne {}} {
+ appendrefs precedes $dtags idtags
+ }
+ }
+ 1 {
+ set atags [anctags $currentid]
+ if {$atags ne {}} {
+ appendrefs follows $atags idtags
+ }
+ }
+ 2 {
+ set dheads [descheads $currentid]
+ if {$dheads ne {}} {
+ if {[appendrefs branch $dheads idheads] > 1
+ && [$ctext get "branch -3c"] eq "h"} {
+ # turn "Branch" into "Branches"
+ $ctext conf -state normal
+ $ctext insert "branch -2c" "es"
+ $ctext conf -state disabled
+ }
+ }
+ }
}
if {[incr tagphase] <= 2} {
- after idle dispnexttag
+ after idle dispnexttag
}
}
@@ -7273,15 +7291,15 @@ proc make_secsel {id} {
if {![info exists linehtag($id)]} return
$canv delete secsel
set t [eval $canv create rect [$canv bbox $linehtag($id)] -outline {{}} \
- -tags secsel -fill [$canv cget -selectbackground]]
+ -tags secsel -fill [$canv cget -selectbackground]]
$canv lower $t
$canv2 delete secsel
set t [eval $canv2 create rect [$canv2 bbox $linentag($id)] -outline {{}} \
- -tags secsel -fill [$canv2 cget -selectbackground]]
+ -tags secsel -fill [$canv2 cget -selectbackground]]
$canv2 lower $t
$canv3 delete secsel
set t [eval $canv3 create rect [$canv3 bbox $linedtag($id)] -outline {{}} \
- -tags secsel -fill [$canv3 cget -selectbackground]]
+ -tags secsel -fill [$canv3 cget -selectbackground]]
$canv3 lower $t
}
@@ -7291,7 +7309,7 @@ proc make_idmark {id} {
if {![info exists linehtag($id)]} return
$canv delete markid
set t [eval $canv create rect [$canv bbox $linehtag($id)] \
- -tags markid -outline $fgcolor]
+ -tags markid -outline $fgcolor]
$canv raise $t
}
@@ -7318,7 +7336,7 @@ proc selectline {l isnew {desired_loc {}} {switch_to_patch 0}} {
set selectedline $l
set currentid $id
if {$lastscrollrows < $numcommits} {
- setcanvscroll
+ setcanvscroll
}
if {$cmitmode ne "patch" && $switch_to_patch} {
@@ -7335,42 +7353,42 @@ proc selectline {l isnew {desired_loc {}} {switch_to_patch 0}} {
set wh [expr {$wbot - $wtop}]
set newtop $wtop
if {$ytop < $wtop} {
- if {$ybot < $wtop} {
- set newtop [expr {$y - $wh / 2.0}]
- } else {
- set newtop $ytop
- if {$newtop > $wtop - $linespc} {
- set newtop [expr {$wtop - $linespc}]
- }
- }
+ if {$ybot < $wtop} {
+ set newtop [expr {$y - $wh / 2.0}]
+ } else {
+ set newtop $ytop
+ if {$newtop > $wtop - $linespc} {
+ set newtop [expr {$wtop - $linespc}]
+ }
+ }
} elseif {$ybot > $wbot} {
- if {$ytop > $wbot} {
- set newtop [expr {$y - $wh / 2.0}]
- } else {
- set newtop [expr {$ybot - $wh}]
- if {$newtop < $wtop + $linespc} {
- set newtop [expr {$wtop + $linespc}]
- }
- }
+ if {$ytop > $wbot} {
+ set newtop [expr {$y - $wh / 2.0}]
+ } else {
+ set newtop [expr {$ybot - $wh}]
+ if {$newtop < $wtop + $linespc} {
+ set newtop [expr {$wtop + $linespc}]
+ }
+ }
}
if {$newtop != $wtop} {
- if {$newtop < 0} {
- set newtop 0
- }
- allcanvs yview moveto [expr {$newtop * 1.0 / $ymax}]
- drawvisible
+ if {$newtop < 0} {
+ set newtop 0
+ }
+ allcanvs yview moveto [expr {$newtop * 1.0 / $ymax}]
+ drawvisible
}
make_secsel $id
if {$isnew} {
- addtohistory [list selbyid $id 0] savecmitpos
+ addtohistory [list selbyid $id 0] savecmitpos
}
$sha1entry delete 0 end
$sha1entry insert 0 $id
if {$autoselect} {
- $sha1entry selection range 0 $autosellen
+ $sha1entry selection range 0 $autosellen
}
rhighlight_sel $id
@@ -7378,7 +7396,7 @@ proc selectline {l isnew {desired_loc {}} {switch_to_patch 0}} {
clear_ctext
set linknum 0
if {![info exists commitinfo($id)]} {
- getcommit $id
+ getcommit $id
}
set info $commitinfo($id)
set date [formatdate [lindex $info 2]]
@@ -7386,59 +7404,59 @@ proc selectline {l isnew {desired_loc {}} {switch_to_patch 0}} {
set date [formatdate [lindex $info 4]]
$ctext insert end "[mc "Committer"]: [lindex $info 3] $date\n"
if {[info exists idtags($id)]} {
- $ctext insert end [mc "Tags:"]
- foreach tag $idtags($id) {
- $ctext insert end " $tag"
- }
- $ctext insert end "\n"
+ $ctext insert end [mc "Tags:"]
+ foreach tag $idtags($id) {
+ $ctext insert end " $tag"
+ }
+ $ctext insert end "\n"
}
set headers {}
set olds $parents($curview,$id)
if {[llength $olds] > 1} {
- set np 0
- foreach p $olds {
- if {$np >= $mergemax} {
- set tag mmax
- } else {
- set tag m$np
- }
- $ctext insert end "[mc "Parent"]: " $tag
- appendwithlinks [commit_descriptor $p] {}
- incr np
- }
+ set np 0
+ foreach p $olds {
+ if {$np >= $mergemax} {
+ set tag mmax
+ } else {
+ set tag m$np
+ }
+ $ctext insert end "[mc "Parent"]: " $tag
+ appendwithlinks [commit_descriptor $p] {}
+ incr np
+ }
} else {
- foreach p $olds {
- append headers "[mc "Parent"]: [commit_descriptor $p]"
- }
+ foreach p $olds {
+ append headers "[mc "Parent"]: [commit_descriptor $p]"
+ }
}
foreach c $children($curview,$id) {
- append headers "[mc "Child"]: [commit_descriptor $c]"
+ append headers "[mc "Child"]: [commit_descriptor $c]"
}
# make anything that looks like a SHA1 ID be a clickable link
appendwithlinks $headers {}
if {$showneartags} {
- if {![info exists allcommits]} {
- getallcommits
- }
- $ctext insert end "[mc "Branch"]: "
- $ctext mark set branch "end -1c"
- $ctext mark gravity branch left
- $ctext insert end "\n[mc "Follows"]: "
- $ctext mark set follows "end -1c"
- $ctext mark gravity follows left
- $ctext insert end "\n[mc "Precedes"]: "
- $ctext mark set precedes "end -1c"
- $ctext mark gravity precedes left
- $ctext insert end "\n"
- dispneartags 1
+ if {![info exists allcommits]} {
+ getallcommits
+ }
+ $ctext insert end "[mc "Branch"]: "
+ $ctext mark set branch "end -1c"
+ $ctext mark gravity branch left
+ $ctext insert end "\n[mc "Follows"]: "
+ $ctext mark set follows "end -1c"
+ $ctext mark gravity follows left
+ $ctext insert end "\n[mc "Precedes"]: "
+ $ctext mark set precedes "end -1c"
+ $ctext mark gravity precedes left
+ $ctext insert end "\n"
+ dispneartags 1
}
$ctext insert end "\n"
set comment [lindex $info 5]
if {[string first "\r" $comment] >= 0} {
- set comment [string map {"\r" "\n "} $comment]
+ set comment [string map {"\r" "\n "} $comment]
}
appendwithlinks $comment {comment}
@@ -7449,13 +7467,13 @@ proc selectline {l isnew {desired_loc {}} {switch_to_patch 0}} {
set jump_to_here $desired_loc
init_flist [mc "Comments"]
if {$cmitmode eq "tree"} {
- gettree $id
+ gettree $id
} elseif {$vinlinediff($curview) == 1} {
- showinlinediff $id
+ showinlinediff $id
} elseif {[llength $olds] <= 1} {
- startdiff $id
+ startdiff $id
} else {
- mergediff $id
+ mergediff $id
}
}
@@ -7485,14 +7503,14 @@ proc selnextpage {dir} {
set lpp [expr {([winfo height $canv] - 2) / $linespc}]
if {$lpp < 1} {
- set lpp 1
+ set lpp 1
}
allcanvs yview scroll [expr {$dir * $lpp}] units
drawvisible
if {$selectedline eq {}} return
set l [expr {$selectedline + $dir * $lpp}]
if {$l < 0} {
- set l 0
+ set l 0
} elseif {$l >= $numcommits} {
set l [expr $numcommits - 1]
}
@@ -7513,7 +7531,7 @@ proc reselectline {} {
global selectedline
if {$selectedline ne {}} {
- selectline $selectedline 0
+ selectline $selectedline 0
}
}
@@ -7524,20 +7542,20 @@ proc addtohistory {cmd {saveproc {}}} {
save_position
set elt [list $curview $cmd $saveproc {}]
if {$historyindex > 0
- && [lindex $history [expr {$historyindex - 1}]] == $elt} {
- return
+ && [lindex $history [expr {$historyindex - 1}]] == $elt} {
+ return
}
if {$historyindex < [llength $history]} {
- set history [lreplace $history $historyindex end $elt]
+ set history [lreplace $history $historyindex end $elt]
} else {
- lappend history $elt
+ lappend history $elt
}
incr historyindex
if {$historyindex > 1} {
- .tf.bar.leftbut conf -state normal
+ .tf.bar.leftbut conf -state normal
} else {
- .tf.bar.leftbut conf -state disabled
+ .tf.bar.leftbut conf -state disabled
}
.tf.bar.rightbut conf -state disabled
}
@@ -7550,7 +7568,7 @@ proc save_position {} {
set hi [expr {$historyindex - 1}]
set fn [lindex $history $hi 2]
if {$fn ne {}} {
- lset history $hi 3 [eval $fn]
+ lset history $hi 3 [eval $fn]
}
}
@@ -7558,11 +7576,11 @@ proc unset_posvars {} {
global last_posvars
if {[info exists last_posvars]} {
- foreach {var val} $last_posvars {
- global $var
- unset -nocomplain $var
- }
- unset last_posvars
+ foreach {var val} $last_posvars {
+ global $var
+ unset -nocomplain $var
+ }
+ unset last_posvars
}
}
@@ -7573,12 +7591,12 @@ proc godo {elt} {
set cmd [lindex $elt 1]
set pv [lindex $elt 3]
if {$curview != $view} {
- showview $view
+ showview $view
}
unset_posvars
foreach {var val} $pv {
- global $var
- set $var $val
+ global $var
+ set $var $val
}
set last_posvars $pv
eval $cmd
@@ -7589,13 +7607,13 @@ proc goback {} {
focus .
if {$historyindex > 1} {
- save_position
- incr historyindex -1
- godo [lindex $history [expr {$historyindex - 1}]]
- .tf.bar.rightbut conf -state normal
+ save_position
+ incr historyindex -1
+ godo [lindex $history [expr {$historyindex - 1}]]
+ .tf.bar.rightbut conf -state normal
}
if {$historyindex <= 1} {
- .tf.bar.leftbut conf -state disabled
+ .tf.bar.leftbut conf -state disabled
}
}
@@ -7604,14 +7622,14 @@ proc goforw {} {
focus .
if {$historyindex < [llength $history]} {
- save_position
- set cmd [lindex $history $historyindex]
- incr historyindex
- godo $cmd
- .tf.bar.leftbut conf -state normal
+ save_position
+ set cmd [lindex $history $historyindex]
+ incr historyindex
+ godo $cmd
+ .tf.bar.leftbut conf -state normal
}
if {$historyindex >= [llength $history]} {
- .tf.bar.rightbut conf -state disabled
+ .tf.bar.rightbut conf -state disabled
}
}
@@ -7619,7 +7637,7 @@ proc go_to_parent {i} {
global parents curview targetid
set ps $parents($curview,$targetid)
if {[llength $ps] >= $i} {
- selbyid [lindex $ps [expr $i - 1]]
+ selbyid [lindex $ps [expr $i - 1]]
}
}
@@ -7630,25 +7648,25 @@ proc gettree {id} {
set diffids $id
unset -nocomplain diffmergeid
if {![info exists treefilelist($id)]} {
- if {![info exists treepending]} {
- if {$id eq $nullid} {
- set cmd [list | git ls-files]
- } elseif {$id eq $nullid2} {
- set cmd [list | git ls-files --stage -t]
- } else {
- set cmd [list | git ls-tree -r $id]
- }
- if {[catch {set gtf [open $cmd r]}]} {
- return
- }
- set treepending $id
- set treefilelist($id) {}
- set treeidlist($id) {}
- fconfigure $gtf -blocking 0 -encoding binary
- filerun $gtf [list gettreeline $gtf $id]
- }
+ if {![info exists treepending]} {
+ if {$id eq $nullid} {
+ set cmd [list | git ls-files]
+ } elseif {$id eq $nullid2} {
+ set cmd [list | git ls-files --stage -t]
+ } else {
+ set cmd [list | git ls-tree -r $id]
+ }
+ if {[catch {set gtf [open $cmd r]}]} {
+ return
+ }
+ set treepending $id
+ set treefilelist($id) {}
+ set treeidlist($id) {}
+ fconfigure $gtf -blocking 0 -encoding binary
+ filerun $gtf [list gettreeline $gtf $id]
+ }
} else {
- setfilelist $id
+ setfilelist $id
}
}
@@ -7657,36 +7675,36 @@ proc gettreeline {gtf id} {
set nl 0
while {[incr nl] <= 1000 && [gets $gtf line] >= 0} {
- if {$diffids eq $nullid} {
- set fname $line
- } else {
- set i [string first "\t" $line]
- if {$i < 0} continue
- set fname [string range $line [expr {$i+1}] end]
- set line [string range $line 0 [expr {$i-1}]]
- if {$diffids ne $nullid2 && [lindex $line 1] ne "blob"} continue
- set sha1 [lindex $line 2]
- lappend treeidlist($id) $sha1
- }
- if {[string index $fname 0] eq "\""} {
- set fname [lindex $fname 0]
- }
- set fname [encoding convertfrom $fname]
- lappend treefilelist($id) $fname
+ if {$diffids eq $nullid} {
+ set fname $line
+ } else {
+ set i [string first "\t" $line]
+ if {$i < 0} continue
+ set fname [string range $line [expr {$i+1}] end]
+ set line [string range $line 0 [expr {$i-1}]]
+ if {$diffids ne $nullid2 && [lindex $line 1] ne "blob"} continue
+ set sha1 [lindex $line 2]
+ lappend treeidlist($id) $sha1
+ }
+ if {[string index $fname 0] eq "\""} {
+ set fname [lindex $fname 0]
+ }
+ set fname [encoding convertfrom $fname]
+ lappend treefilelist($id) $fname
}
if {![eof $gtf]} {
- return [expr {$nl >= 1000? 2: 1}]
+ return [expr {$nl >= 1000? 2: 1}]
}
close $gtf
unset treepending
if {$cmitmode ne "tree"} {
- if {![info exists diffmergeid]} {
- gettreediffs $diffids
- }
+ if {![info exists diffmergeid]} {
+ gettreediffs $diffids
+ }
} elseif {$id ne $diffids} {
- gettree $diffids
+ gettree $diffids
} else {
- setfilelist $id
+ setfilelist $id
}
return 0
}
@@ -7698,20 +7716,20 @@ proc showfile {f} {
set i [lsearch -exact $treefilelist($diffids) $f]
if {$i < 0} {
- puts "oops, $f not in list for id $diffids"
- return
+ puts "oops, $f not in list for id $diffids"
+ return
}
if {$diffids eq $nullid} {
- if {[catch {set bf [open $f r]} err]} {
- puts "oops, can't read $f: $err"
- return
- }
+ if {[catch {set bf [open $f r]} err]} {
+ puts "oops, can't read $f: $err"
+ return
+ }
} else {
- set blob [lindex $treeidlist($diffids) $i]
- if {[catch {set bf [open [concat | git cat-file blob $blob] r]} err]} {
- puts "oops, error reading blob $blob: $err"
- return
- }
+ set blob [lindex $treeidlist($diffids) $i]
+ if {[catch {set bf [open [concat | git cat-file blob $blob] r]} err]} {
+ puts "oops, error reading blob $blob: $err"
+ return
+ }
}
fconfigure $bf -blocking 0 -encoding [get_path_encoding $f]
filerun $bf [list getblobline $bf $diffids]
@@ -7730,28 +7748,28 @@ proc getblobline {bf id} {
global diffids cmitmode ctext
if {$id ne $diffids || $cmitmode ne "tree"} {
- catch {close $bf}
- return 0
+ catch {close $bf}
+ return 0
}
$ctext config -state normal
set nl 0
while {[incr nl] <= 1000 && [gets $bf line] >= 0} {
- $ctext insert end "$line\n"
+ $ctext insert end "$line\n"
}
if {[eof $bf]} {
- global jump_to_here ctext_file_names commentend
-
- # delete last newline
- $ctext delete "end - 2c" "end - 1c"
- close $bf
- if {$jump_to_here ne {} &&
- [lindex $jump_to_here 0] eq [lindex $ctext_file_names 0]} {
- set lnum [expr {[lindex $jump_to_here 1] +
- [lindex [split $commentend .] 0]}]
- mark_ctext_line $lnum
- }
- $ctext config -state disabled
- return 0
+ global jump_to_here ctext_file_names commentend
+
+ # delete last newline
+ $ctext delete "end - 2c" "end - 1c"
+ close $bf
+ if {$jump_to_here ne {} &&
+ [lindex $jump_to_here 0] eq [lindex $ctext_file_names 0]} {
+ set lnum [expr {[lindex $jump_to_here 1] +
+ [lindex [split $commentend .] 0]}]
+ mark_ctext_line $lnum
+ }
+ $ctext config -state disabled
+ return 0
}
$ctext config -state disabled
return [expr {$nl >= 1000? 2: 1}]
@@ -7786,13 +7804,13 @@ proc startdiff {ids} {
set diffids $ids
unset -nocomplain diffmergeid
if {![info exists treediffs($ids)] ||
- [lsearch -exact $ids $nullid] >= 0 ||
- [lsearch -exact $ids $nullid2] >= 0} {
- if {![info exists treepending]} {
- gettreediffs $ids
- }
+ [lsearch -exact $ids $nullid] >= 0 ||
+ [lsearch -exact $ids $nullid2] >= 0} {
+ if {![info exists treepending]} {
+ gettreediffs $ids
+ }
} else {
- addtocflist $ids
+ addtocflist $ids
}
}
@@ -7809,13 +7827,13 @@ proc showinlinediff {ids} {
set inhdr 0
foreach line $difflines {
- if {![string compare -length 5 "diff " $line]} {
- set inhdr 1
- } elseif {$inhdr && ![string compare -length 4 "+++ " $line]} {
- # offset also accounts for the b/ prefix
- lappend treediff [string range $line 6 end]
- set inhdr 0
- }
+ if {![string compare -length 5 "diff " $line]} {
+ set inhdr 1
+ } elseif {$inhdr && ![string compare -length 4 "+++ " $line]} {
+ # offset also accounts for the b/ prefix
+ lappend treediff [string range $line 6 end]
+ set inhdr 0
+ }
}
set treediffs($ids) $treediff
@@ -7823,7 +7841,7 @@ proc showinlinediff {ids} {
$ctext conf -state normal
foreach line $difflines {
- parseblobdiffline $ids $line
+ parseblobdiffline $ids $line
}
maybe_scroll_ctext 1
$ctext conf -state disabled
@@ -7834,11 +7852,11 @@ proc showinlinediff {ids} {
proc path_filter {filter name} {
set worktree [gitworktree]
foreach p $filter {
- set fq_p [file normalize $p]
- set fq_n [file normalize [file join $worktree $name]]
- if {[string match [file normalize $fq_p]* $fq_n]} {
- return 1
- }
+ set fq_p [file normalize $p]
+ set fq_n [file normalize [file join $worktree $name]]
+ if {[string match [file normalize $fq_p]* $fq_n]} {
+ return 1
+ }
}
return 0
}
@@ -7856,42 +7874,42 @@ proc diffcmd {ids flags} {
set i [lsearch -exact $ids $nullid]
set j [lsearch -exact $ids $nullid2]
if {$i >= 0} {
- if {[llength $ids] > 1 && $j < 0} {
- # comparing working directory with some specific revision
- set cmd [concat | git diff-index $flags]
- if {$i == 0} {
- lappend cmd -R [lindex $ids 1]
- } else {
- lappend cmd [lindex $ids 0]
- }
- } else {
- # comparing working directory with index
- set cmd [concat | git diff-files $flags]
- if {$j == 1} {
- lappend cmd -R
- }
- }
+ if {[llength $ids] > 1 && $j < 0} {
+ # comparing working directory with some specific revision
+ set cmd [concat | git diff-index $flags]
+ if {$i == 0} {
+ lappend cmd -R [lindex $ids 1]
+ } else {
+ lappend cmd [lindex $ids 0]
+ }
+ } else {
+ # comparing working directory with index
+ set cmd [concat | git diff-files $flags]
+ if {$j == 1} {
+ lappend cmd -R
+ }
+ }
} elseif {$j >= 0} {
- if {[package vcompare $git_version "1.7.2"] >= 0} {
- set flags "$flags --ignore-submodules=dirty"
- }
- set cmd [concat | git diff-index --cached $flags]
- if {[llength $ids] > 1} {
- # comparing index with specific revision
- if {$j == 0} {
- lappend cmd -R [lindex $ids 1]
- } else {
- lappend cmd [lindex $ids 0]
- }
- } else {
- # comparing index with HEAD
- lappend cmd HEAD
- }
+ if {[package vcompare $git_version "1.7.2"] >= 0} {
+ set flags "$flags --ignore-submodules=dirty"
+ }
+ set cmd [concat | git diff-index --cached $flags]
+ if {[llength $ids] > 1} {
+ # comparing index with specific revision
+ if {$j == 0} {
+ lappend cmd -R [lindex $ids 1]
+ } else {
+ lappend cmd [lindex $ids 0]
+ }
+ } else {
+ # comparing index with HEAD
+ lappend cmd HEAD
+ }
} else {
- if {$log_showroot} {
- lappend flags --root
- }
- set cmd [concat | git diff-tree -r $flags $ids]
+ if {$log_showroot} {
+ lappend flags --root
+ }
+ set cmd [concat | git diff-tree -r $flags $ids]
}
return $cmd
}
@@ -7901,7 +7919,7 @@ proc gettreediffs {ids} {
set cmd [diffcmd $ids {--no-commit-id}]
if {$limitdiffs && $vfilelimit($curview) ne {}} {
- set cmd [concat $cmd -- $vfilelimit($curview)]
+ set cmd [concat $cmd -- $vfilelimit($curview)]
}
if {[catch {set gdtf [open $cmd r]}]} return
@@ -7919,44 +7937,44 @@ proc gettreediffline {gdtf ids} {
set sublist {}
set max 1000
if {$perfile_attrs} {
- # cache_gitattr is slow, and even slower on win32 where we
- # have to invoke it for only about 30 paths at a time
- set max 500
- if {[tk windowingsystem] == "win32"} {
- set max 120
- }
+ # cache_gitattr is slow, and even slower on win32 where we
+ # have to invoke it for only about 30 paths at a time
+ set max 500
+ if {[tk windowingsystem] == "win32"} {
+ set max 120
+ }
}
while {[incr nr] <= $max && [gets $gdtf line] >= 0} {
- set i [string first "\t" $line]
- if {$i >= 0} {
- set file [string range $line [expr {$i+1}] end]
- if {[string index $file 0] eq "\""} {
- set file [lindex $file 0]
- }
- set file [encoding convertfrom $file]
- if {$file ne [lindex $treediff end]} {
- lappend treediff $file
- lappend sublist $file
- }
- }
+ set i [string first "\t" $line]
+ if {$i >= 0} {
+ set file [string range $line [expr {$i+1}] end]
+ if {[string index $file 0] eq "\""} {
+ set file [lindex $file 0]
+ }
+ set file [encoding convertfrom $file]
+ if {$file ne [lindex $treediff end]} {
+ lappend treediff $file
+ lappend sublist $file
+ }
+ }
}
if {$perfile_attrs} {
- cache_gitattr encoding $sublist
+ cache_gitattr encoding $sublist
}
if {![eof $gdtf]} {
- return [expr {$nr >= $max? 2: 1}]
+ return [expr {$nr >= $max? 2: 1}]
}
close $gdtf
set treediffs($ids) $treediff
unset treepending
if {$cmitmode eq "tree" && [llength $diffids] == 1} {
- gettree $diffids
+ gettree $diffids
} elseif {$ids != $diffids} {
- if {![info exists diffmergeid]} {
- gettreediffs $diffids
- }
+ if {![info exists diffmergeid]} {
+ gettreediffs $diffids
+ }
} else {
- addtocflist $ids
+ addtocflist $ids
}
return 0
}
@@ -7970,10 +7988,10 @@ proc diffcontextchange {n1 n2 op} {
global diffcontextstring diffcontext
if {[string is integer -strict $diffcontextstring]} {
- if {$diffcontextstring >= 0} {
- set diffcontext $diffcontextstring
- reselectline
- }
+ if {$diffcontextstring >= 0} {
+ set diffcontext $diffcontextstring
+ reselectline
+ }
}
}
@@ -8007,25 +8025,25 @@ proc getblobdiffs {ids} {
set textconv {}
if {[package vcompare $git_version "1.6.1"] >= 0} {
- set textconv "--textconv"
+ set textconv "--textconv"
}
set submodule {}
if {[package vcompare $git_version "1.6.6"] >= 0} {
- set submodule "--submodule"
+ set submodule "--submodule"
}
set cmd [diffcmd $ids "-p $textconv $submodule -C --cc --no-commit-id -U$diffcontext"]
if {$ignorespace} {
- append cmd " -w"
+ append cmd " -w"
}
if {$worddiff ne [mc "Line diff"]} {
- append cmd " --word-diff=porcelain"
+ append cmd " --word-diff=porcelain"
}
if {$limitdiffs && $vfilelimit($curview) ne {}} {
- set cmd [concat $cmd -- $vfilelimit($curview)]
+ set cmd [concat $cmd -- $vfilelimit($curview)]
}
if {[catch {set bdf [open $cmd r]} err]} {
- error_popup [mc "Error getting diffs: %s" $err]
- return
+ error_popup [mc "Error getting diffs: %s" $err]
+ return
}
fconfigure $bdf -blocking 0 -encoding binary -eofchar {}
set blobdifffd($ids) $bdf
@@ -8037,7 +8055,7 @@ proc savecmitpos {} {
global ctext cmitmode
if {$cmitmode eq "tree"} {
- return {}
+ return {}
}
return [list target_scrollpos [$ctext index @0,0]]
}
@@ -8053,9 +8071,9 @@ proc maybe_scroll_ctext {ateof} {
if {![info exists target_scrollpos]} return
if {!$ateof} {
- set nlines [expr {[winfo height $ctext]
- / [font metrics textfont -linespace]}]
- if {[$ctext compare "$target_scrollpos + $nlines lines" <= end]} return
+ set nlines [expr {[winfo height $ctext]
+ / [font metrics textfont -linespace]}]
+ if {[$ctext compare "$target_scrollpos + $nlines lines" <= end]} return
}
$ctext yview $target_scrollpos
unset target_scrollpos
@@ -8065,12 +8083,12 @@ proc setinlist {var i val} {
global $var
while {[llength [set $var]] < $i} {
- lappend $var {}
+ lappend $var {}
}
if {[llength [set $var]] == $i} {
- lappend $var $val
+ lappend $var $val
} else {
- lset $var $i $val
+ lset $var $i $val
}
}
@@ -8082,7 +8100,7 @@ proc makediffhdr {fname ids} {
set diffencoding [get_path_encoding $fname]
set i [lsearch -exact $treediffs($ids) $fname]
if {$i >= 0} {
- setinlist difffilestart $i $curdiffstart
+ setinlist difffilestart $i $curdiffstart
}
lset ctext_file_names end $fname
set l [expr {(78 - [string length $fname]) / 2}]
@@ -8090,7 +8108,7 @@ proc makediffhdr {fname ids} {
$ctext insert $curdiffstart "$pad $fname $pad" filesep
set targetline {}
if {$jump_to_here ne {} && [lindex $jump_to_here 0] eq $fname} {
- set targetline [lindex $jump_to_here 1]
+ set targetline [lindex $jump_to_here 1]
}
set diffline 0
}
@@ -8098,7 +8116,7 @@ proc makediffhdr {fname ids} {
proc blobdiffmaybeseehere {ateof} {
global diffseehere
if {$diffseehere >= 0} {
- mark_ctext_line [lindex [split $diffseehere .] 0]
+ mark_ctext_line [lindex [split $diffseehere .] 0]
}
maybe_scroll_ctext $ateof
}
@@ -8110,22 +8128,22 @@ proc getblobdiffline {bdf ids} {
set nr 0
$ctext conf -state normal
while {[incr nr] <= 1000 && [gets $bdf line] >= 0} {
- if {$ids != $diffids || $bdf != $blobdifffd($ids)} {
- # Older diff read. Abort it.
- catch {close $bdf}
- if {$ids != $diffids} {
- array unset blobdifffd $ids
- }
- return 0
- }
- parseblobdiffline $ids $line
+ if {$ids != $diffids || $bdf != $blobdifffd($ids)} {
+ # Older diff read. Abort it.
+ catch {close $bdf}
+ if {$ids != $diffids} {
+ array unset blobdifffd $ids
+ }
+ return 0
+ }
+ parseblobdiffline $ids $line
}
$ctext conf -state disabled
blobdiffmaybeseehere [eof $bdf]
if {[eof $bdf]} {
- catch {close $bdf}
- array unset blobdifffd $ids
- return 0
+ catch {close $bdf}
+ array unset blobdifffd $ids
+ return 0
}
return [expr {$nr >= 1000? 2: 1}]
}
@@ -8139,199 +8157,199 @@ proc parseblobdiffline {ids line} {
global worddiff diffseehere
if {![string compare -length 5 "diff " $line]} {
- if {![regexp {^diff (--cc|--git) } $line m type]} {
- set line [encoding convertfrom $line]
- $ctext insert end "$line\n" hunksep
- continue
- }
- # start of a new file
- set diffinhdr 1
- $ctext insert end "\n"
- set curdiffstart [$ctext index "end - 1c"]
- lappend ctext_file_names ""
- lappend ctext_file_lines [lindex [split $curdiffstart "."] 0]
- $ctext insert end "\n" filesep
-
- if {$type eq "--cc"} {
- # start of a new file in a merge diff
- set fname [string range $line 10 end]
- if {[lsearch -exact $treediffs($ids) $fname] < 0} {
- lappend treediffs($ids) $fname
- add_flist [list $fname]
- }
-
- } else {
- set line [string range $line 11 end]
- # If the name hasn't changed the length will be odd,
- # the middle char will be a space, and the two bits either
- # side will be a/name and b/name, or "a/name" and "b/name".
- # If the name has changed we'll get "rename from" and
- # "rename to" or "copy from" and "copy to" lines following
- # this, and we'll use them to get the filenames.
- # This complexity is necessary because spaces in the
- # filename(s) don't get escaped.
- set l [string length $line]
- set i [expr {$l / 2}]
- if {!(($l & 1) && [string index $line $i] eq " " &&
- [string range $line 2 [expr {$i - 1}]] eq \
- [string range $line [expr {$i + 3}] end])} {
- return
- }
- # unescape if quoted and chop off the a/ from the front
- if {[string index $line 0] eq "\""} {
- set fname [string range [lindex $line 0] 2 end]
- } else {
- set fname [string range $line 2 [expr {$i - 1}]]
- }
- }
- makediffhdr $fname $ids
+ if {![regexp {^diff (--cc|--git) } $line m type]} {
+ set line [encoding convertfrom $line]
+ $ctext insert end "$line\n" hunksep
+ continue
+ }
+ # start of a new file
+ set diffinhdr 1
+ set currdiffsubmod ""
+
+ $ctext insert end "\n"
+ set curdiffstart [$ctext index "end - 1c"]
+ lappend ctext_file_names ""
+ lappend ctext_file_lines [lindex [split $curdiffstart "."] 0]
+ $ctext insert end "\n" filesep
+
+ if {$type eq "--cc"} {
+ # start of a new file in a merge diff
+ set fname [string range $line 10 end]
+ if {[lsearch -exact $treediffs($ids) $fname] < 0} {
+ lappend treediffs($ids) $fname
+ add_flist [list $fname]
+ }
+
+ } else {
+ set line [string range $line 11 end]
+ # If the name hasn't changed the length will be odd,
+ # the middle char will be a space, and the two bits either
+ # side will be a/name and b/name, or "a/name" and "b/name".
+ # If the name has changed we'll get "rename from" and
+ # "rename to" or "copy from" and "copy to" lines following
+ # this, and we'll use them to get the filenames.
+ # This complexity is necessary because spaces in the
+ # filename(s) don't get escaped.
+ set l [string length $line]
+ set i [expr {$l / 2}]
+ if {!(($l & 1) && [string index $line $i] eq " " &&
+ [string range $line 2 [expr {$i - 1}]] eq \
+ [string range $line [expr {$i + 3}] end])} {
+ return
+ }
+ # unescape if quoted and chop off the a/ from the front
+ if {[string index $line 0] eq "\""} {
+ set fname [string range [lindex $line 0] 2 end]
+ } else {
+ set fname [string range $line 2 [expr {$i - 1}]]
+ }
+ }
+ makediffhdr $fname $ids
} elseif {![string compare -length 16 "* Unmerged path " $line]} {
- set fname [encoding convertfrom [string range $line 16 end]]
- $ctext insert end "\n"
- set curdiffstart [$ctext index "end - 1c"]
- lappend ctext_file_names $fname
- lappend ctext_file_lines [lindex [split $curdiffstart "."] 0]
- $ctext insert end "$line\n" filesep
- set i [lsearch -exact $treediffs($ids) $fname]
- if {$i >= 0} {
- setinlist difffilestart $i $curdiffstart
- }
+ set fname [encoding convertfrom [string range $line 16 end]]
+ $ctext insert end "\n"
+ set curdiffstart [$ctext index "end - 1c"]
+ lappend ctext_file_names $fname
+ lappend ctext_file_lines [lindex [split $curdiffstart "."] 0]
+ $ctext insert end "$line\n" filesep
+ set i [lsearch -exact $treediffs($ids) $fname]
+ if {$i >= 0} {
+ setinlist difffilestart $i $curdiffstart
+ }
} elseif {![string compare -length 2 "@@" $line]} {
- regexp {^@@+} $line ats
- set line [encoding convertfrom $diffencoding $line]
- $ctext insert end "$line\n" hunksep
- if {[regexp { \+(\d+),\d+ @@} $line m nl]} {
- set diffline $nl
- }
- set diffnparents [expr {[string length $ats] - 1}]
- set diffinhdr 0
+ regexp {^@@+} $line ats
+ set line [encoding convertfrom $diffencoding $line]
+ $ctext insert end "$line\n" hunksep
+ if {[regexp { \+(\d+),\d+ @@} $line m nl]} {
+ set diffline $nl
+ }
+ set diffnparents [expr {[string length $ats] - 1}]
+ set diffinhdr 0
} elseif {![string compare -length 10 "Submodule " $line]} {
- # start of a new submodule
- if {[regexp -indices "\[0-9a-f\]+\\.\\." $line nameend]} {
- set fname [string range $line 10 [expr [lindex $nameend 0] - 2]]
- } else {
- set fname [string range $line 10 [expr [string first "contains " $line] - 2]]
- }
- if {$currdiffsubmod != $fname} {
- $ctext insert end "\n"; # Add newline after commit message
- }
- set curdiffstart [$ctext index "end - 1c"]
- lappend ctext_file_names ""
- if {$currdiffsubmod != $fname} {
- lappend ctext_file_lines $fname
- makediffhdr $fname $ids
- set currdiffsubmod $fname
- $ctext insert end "\n$line\n" filesep
- } else {
- $ctext insert end "$line\n" filesep
- }
+ # start of a new submodule
+ if {[regexp -indices "\[0-9a-f\]+\\.\\." $line nameend]} {
+ set fname [string range $line 10 [expr [lindex $nameend 0] - 2]]
+ } else {
+ set fname [string range $line 10 [expr [string first "contains " $line] - 2]]
+ }
+ if {$currdiffsubmod != $fname} {
+ $ctext insert end "\n"; # Add newline after commit message
+ }
+ if {$currdiffsubmod != $fname} {
+ set curdiffstart [$ctext index "end - 1c"]
+ lappend ctext_file_names ""
+ lappend ctext_file_lines [lindex [split $curdiffstart "."] 0]
+ makediffhdr $fname $ids
+ set currdiffsubmod $fname
+ $ctext insert end "\n$line\n" filesep
+ } else {
+ $ctext insert end "$line\n" filesep
+ }
} elseif {$currdiffsubmod != "" && ![string compare -length 3 " >" $line]} {
- set $currdiffsubmod ""
- set line [encoding convertfrom $diffencoding $line]
- $ctext insert end "$line\n" dresult
+ set line [encoding convertfrom $diffencoding $line]
+ $ctext insert end "$line\n" dresult
} elseif {$currdiffsubmod != "" && ![string compare -length 3 " <" $line]} {
- set $currdiffsubmod ""
- set line [encoding convertfrom $diffencoding $line]
- $ctext insert end "$line\n" d0
+ set line [encoding convertfrom $diffencoding $line]
+ $ctext insert end "$line\n" d0
} elseif {$diffinhdr} {
- if {![string compare -length 12 "rename from " $line]} {
- set fname [string range $line [expr 6 + [string first " from " $line] ] end]
- if {[string index $fname 0] eq "\""} {
- set fname [lindex $fname 0]
- }
- set fname [encoding convertfrom $fname]
- set i [lsearch -exact $treediffs($ids) $fname]
- if {$i >= 0} {
- setinlist difffilestart $i $curdiffstart
- }
- } elseif {![string compare -length 10 $line "rename to "] ||
- ![string compare -length 8 $line "copy to "]} {
- set fname [string range $line [expr 4 + [string first " to " $line] ] end]
- if {[string index $fname 0] eq "\""} {
- set fname [lindex $fname 0]
- }
- makediffhdr $fname $ids
- } elseif {[string compare -length 3 $line "---"] == 0} {
- # do nothing
- return
- } elseif {[string compare -length 3 $line "+++"] == 0} {
- set diffinhdr 0
- return
- }
- $ctext insert end "$line\n" filesep
+ if {![string compare -length 12 "rename from " $line]} {
+ set fname [string range $line [expr 6 + [string first " from " $line] ] end]
+ if {[string index $fname 0] eq "\""} {
+ set fname [lindex $fname 0]
+ }
+ set fname [encoding convertfrom $fname]
+ set i [lsearch -exact $treediffs($ids) $fname]
+ if {$i >= 0} {
+ setinlist difffilestart $i $curdiffstart
+ }
+ } elseif {![string compare -length 10 $line "rename to "] ||
+ ![string compare -length 8 $line "copy to "]} {
+ set fname [string range $line [expr 4 + [string first " to " $line] ] end]
+ if {[string index $fname 0] eq "\""} {
+ set fname [lindex $fname 0]
+ }
+ makediffhdr $fname $ids
+ } elseif {[string compare -length 3 $line "---"] == 0} {
+ # do nothing
+ return
+ } elseif {[string compare -length 3 $line "+++"] == 0} {
+ set diffinhdr 0
+ return
+ }
+ $ctext insert end "$line\n" filesep
} else {
- set line [string map {\x1A ^Z} \
- [encoding convertfrom $diffencoding $line]]
- # parse the prefix - one ' ', '-' or '+' for each parent
- set prefix [string range $line 0 [expr {$diffnparents - 1}]]
- set tag [expr {$diffnparents > 1? "m": "d"}]
- set dowords [expr {$worddiff ne [mc "Line diff"] && $diffnparents == 1}]
- set words_pre_markup ""
- set words_post_markup ""
- if {[string trim $prefix " -+"] eq {}} {
- # prefix only has " ", "-" and "+" in it: normal diff line
- set num [string first "-" $prefix]
- if {$dowords} {
- set line [string range $line 1 end]
- }
- if {$num >= 0} {
- # removed line, first parent with line is $num
- if {$num >= $mergemax} {
- set num "max"
- }
- if {$dowords && $worddiff eq [mc "Markup words"]} {
- $ctext insert end "\[-$line-\]" $tag$num
- } else {
- $ctext insert end "$line" $tag$num
- }
- if {!$dowords} {
- $ctext insert end "\n" $tag$num
- }
- } else {
- set tags {}
- if {[string first "+" $prefix] >= 0} {
- # added line
- lappend tags ${tag}result
- if {$diffnparents > 1} {
- set num [string first " " $prefix]
- if {$num >= 0} {
- if {$num >= $mergemax} {
- set num "max"
- }
- lappend tags m$num
- }
- }
- set words_pre_markup "{+"
- set words_post_markup "+}"
- }
- if {$targetline ne {}} {
- if {$diffline == $targetline} {
- set diffseehere [$ctext index "end - 1 chars"]
- set targetline {}
- } else {
- incr diffline
- }
- }
- if {$dowords && $worddiff eq [mc "Markup words"]} {
- $ctext insert end "$words_pre_markup$line$words_post_markup" $tags
- } else {
- $ctext insert end "$line" $tags
- }
- if {!$dowords} {
- $ctext insert end "\n" $tags
- }
- }
- } elseif {$dowords && $prefix eq "~"} {
- $ctext insert end "\n" {}
- } else {
- # "\ No newline at end of file",
- # or something else we don't recognize
- $ctext insert end "$line\n" hunksep
- }
+ set line [string map {\x1A ^Z} \
+ [encoding convertfrom $diffencoding $line]]
+ # parse the prefix - one ' ', '-' or '+' for each parent
+ set prefix [string range $line 0 [expr {$diffnparents - 1}]]
+ set tag [expr {$diffnparents > 1? "m": "d"}]
+ set dowords [expr {$worddiff ne [mc "Line diff"] && $diffnparents == 1}]
+ set words_pre_markup ""
+ set words_post_markup ""
+ if {[string trim $prefix " -+"] eq {}} {
+ # prefix only has " ", "-" and "+" in it: normal diff line
+ set num [string first "-" $prefix]
+ if {$dowords} {
+ set line [string range $line 1 end]
+ }
+ if {$num >= 0} {
+ # removed line, first parent with line is $num
+ if {$num >= $mergemax} {
+ set num "max"
+ }
+ if {$dowords && $worddiff eq [mc "Markup words"]} {
+ $ctext insert end "\[-$line-\]" $tag$num
+ } else {
+ $ctext insert end "$line" $tag$num
+ }
+ if {!$dowords} {
+ $ctext insert end "\n" $tag$num
+ }
+ } else {
+ set tags {}
+ if {[string first "+" $prefix] >= 0} {
+ # added line
+ lappend tags ${tag}result
+ if {$diffnparents > 1} {
+ set num [string first " " $prefix]
+ if {$num >= 0} {
+ if {$num >= $mergemax} {
+ set num "max"
+ }
+ lappend tags m$num
+ }
+ }
+ set words_pre_markup "{+"
+ set words_post_markup "+}"
+ }
+ if {$targetline ne {}} {
+ if {$diffline == $targetline} {
+ set diffseehere [$ctext index "end - 1 chars"]
+ set targetline {}
+ } else {
+ incr diffline
+ }
+ }
+ if {$dowords && $worddiff eq [mc "Markup words"]} {
+ $ctext insert end "$words_pre_markup$line$words_post_markup" $tags
+ } else {
+ $ctext insert end "$line" $tags
+ }
+ if {!$dowords} {
+ $ctext insert end "\n" $tags
+ }
+ }
+ } elseif {$dowords && $prefix eq "~"} {
+ $ctext insert end "\n" {}
+ } else {
+ # "\ No newline at end of file",
+ # or something else we don't recognize
+ $ctext insert end "$line\n" hunksep
+ }
}
}
@@ -8361,9 +8379,9 @@ proc highlightfile_for_scrollpos {topidx} {
set top [lindex [split $topidx .] 0]
if {$difffilestart eq {} || $top < [lindex $difffilestart 0]} {
- highlightfile 0
+ highlightfile 0
} else {
- highlightfile [expr {[bsearch $difffilestart $top] + 2}]
+ highlightfile [expr {[bsearch $difffilestart $top] + 2}]
}
}
@@ -8374,11 +8392,11 @@ proc prevfile {} {
set prev 0.0
set here [$ctext index @0,0]
foreach loc $difffilestart {
- if {[$ctext compare $loc >= $here]} {
- $ctext yview $prev
- return
- }
- set prev $loc
+ if {[$ctext compare $loc >= $here]} {
+ $ctext yview $prev
+ return
+ }
+ set prev $loc
}
$ctext yview $prev
}
@@ -8389,10 +8407,10 @@ proc nextfile {} {
if {$cmitmode eq "tree"} return
set here [$ctext index @0,0]
foreach loc $difffilestart {
- if {[$ctext compare $loc > $here]} {
- $ctext yview $loc
- return
- }
+ if {[$ctext compare $loc > $here]} {
+ $ctext yview $loc
+ return
+ }
}
}
@@ -8403,14 +8421,14 @@ proc clear_ctext {{first 1.0}} {
set l [lindex [split $first .] 0]
if {![info exists smarktop] || [$ctext compare $first < $smarktop.0]} {
- set smarktop $l
+ set smarktop $l
}
if {![info exists smarkbot] || [$ctext compare $first < $smarkbot.0]} {
- set smarkbot $l
+ set smarkbot $l
}
$ctext delete $first end
if {$first eq "1.0"} {
- unset -nocomplain pendinglinks
+ unset -nocomplain pendinglinks
}
set ctext_file_names {}
set ctext_file_lines {}
@@ -8420,16 +8438,16 @@ proc settabs {{firstab {}}} {
global firsttabstop tabstop ctext have_tk85
if {$firstab ne {} && $have_tk85} {
- set firsttabstop $firstab
+ set firsttabstop $firstab
}
set w [font measure textfont "0"]
if {$firsttabstop != 0} {
- $ctext conf -tabs [list [expr {($firsttabstop + $tabstop) * $w}] \
- [expr {($firsttabstop + 2 * $tabstop) * $w}]]
+ $ctext conf -tabs [list [expr {($firsttabstop + $tabstop) * $w}] \
+ [expr {($firsttabstop + 2 * $tabstop) * $w}]]
} elseif {$have_tk85 || $tabstop != 8} {
- $ctext conf -tabs [expr {$tabstop * $w}]
+ $ctext conf -tabs [expr {$tabstop * $w}]
} else {
- $ctext conf -tabs {}
+ $ctext conf -tabs {}
}
}
@@ -8437,26 +8455,26 @@ proc incrsearch {name ix op} {
global ctext searchstring searchdirn
if {[catch {$ctext index anchor}]} {
- # no anchor set, use start of selection, or of visible area
- set sel [$ctext tag ranges sel]
- if {$sel ne {}} {
- $ctext mark set anchor [lindex $sel 0]
- } elseif {$searchdirn eq "-forwards"} {
- $ctext mark set anchor @0,0
- } else {
- $ctext mark set anchor @0,[winfo height $ctext]
- }
+ # no anchor set, use start of selection, or of visible area
+ set sel [$ctext tag ranges sel]
+ if {$sel ne {}} {
+ $ctext mark set anchor [lindex $sel 0]
+ } elseif {$searchdirn eq "-forwards"} {
+ $ctext mark set anchor @0,0
+ } else {
+ $ctext mark set anchor @0,[winfo height $ctext]
+ }
}
if {$searchstring ne {}} {
- set here [$ctext search -count mlen $searchdirn -- $searchstring anchor]
- if {$here ne {}} {
- $ctext see $here
- set mend "$here + $mlen c"
- $ctext tag remove sel 1.0 end
- $ctext tag add sel $here $mend
- suppress_highlighting_file_for_current_scrollpos
- highlightfile_for_scrollpos $here
- }
+ set here [$ctext search -count mlen $searchdirn -- $searchstring anchor]
+ if {$here ne {}} {
+ $ctext see $here
+ set mend "$here + $mlen c"
+ $ctext tag remove sel 1.0 end
+ $ctext tag add sel $here $mend
+ suppress_highlighting_file_for_current_scrollpos
+ highlightfile_for_scrollpos $here
+ }
}
rehighlight_search_results
}
@@ -8468,25 +8486,25 @@ proc dosearch {} {
$sstring icursor end
set searchdirn -forwards
if {$searchstring ne {}} {
- set sel [$ctext tag ranges sel]
- if {$sel ne {}} {
- set start "[lindex $sel 0] + 1c"
- } elseif {[catch {set start [$ctext index anchor]}]} {
- set start "@0,0"
- }
- set match [$ctext search -count mlen -- $searchstring $start]
- $ctext tag remove sel 1.0 end
- if {$match eq {}} {
- bell
- return
- }
- $ctext see $match
- suppress_highlighting_file_for_current_scrollpos
- highlightfile_for_scrollpos $match
- set mend "$match + $mlen c"
- $ctext tag add sel $match $mend
- $ctext mark unset anchor
- rehighlight_search_results
+ set sel [$ctext tag ranges sel]
+ if {$sel ne {}} {
+ set start "[lindex $sel 0] + 1c"
+ } elseif {[catch {set start [$ctext index anchor]}]} {
+ set start "@0,0"
+ }
+ set match [$ctext search -count mlen -- $searchstring $start]
+ $ctext tag remove sel 1.0 end
+ if {$match eq {}} {
+ bell
+ return
+ }
+ $ctext see $match
+ suppress_highlighting_file_for_current_scrollpos
+ highlightfile_for_scrollpos $match
+ set mend "$match + $mlen c"
+ $ctext tag add sel $match $mend
+ $ctext mark unset anchor
+ rehighlight_search_results
}
}
@@ -8497,25 +8515,25 @@ proc dosearchback {} {
$sstring icursor end
set searchdirn -backwards
if {$searchstring ne {}} {
- set sel [$ctext tag ranges sel]
- if {$sel ne {}} {
- set start [lindex $sel 0]
- } elseif {[catch {set start [$ctext index anchor]}]} {
- set start @0,[winfo height $ctext]
- }
- set match [$ctext search -backwards -count ml -- $searchstring $start]
- $ctext tag remove sel 1.0 end
- if {$match eq {}} {
- bell
- return
- }
- $ctext see $match
- suppress_highlighting_file_for_current_scrollpos
- highlightfile_for_scrollpos $match
- set mend "$match + $ml c"
- $ctext tag add sel $match $mend
- $ctext mark unset anchor
- rehighlight_search_results
+ set sel [$ctext tag ranges sel]
+ if {$sel ne {}} {
+ set start [lindex $sel 0]
+ } elseif {[catch {set start [$ctext index anchor]}]} {
+ set start @0,[winfo height $ctext]
+ }
+ set match [$ctext search -backwards -count ml -- $searchstring $start]
+ $ctext tag remove sel 1.0 end
+ if {$match eq {}} {
+ bell
+ return
+ }
+ $ctext see $match
+ suppress_highlighting_file_for_current_scrollpos
+ highlightfile_for_scrollpos $match
+ set mend "$match + $ml c"
+ $ctext tag add sel $match $mend
+ $ctext mark unset anchor
+ rehighlight_search_results
}
}
@@ -8526,7 +8544,7 @@ proc rehighlight_search_results {} {
$ctext tag remove currentsearchhit 1.0 end
if {$searchstring ne {}} {
- searchmarkvisible 1
+ searchmarkvisible 1
}
}
@@ -8537,14 +8555,14 @@ proc searchmark {first last} {
set mend $first.0
while {1} {
- set match [$ctext search -count mlen -- $searchstring $mend $last.end]
- if {$match eq {}} break
- set mend "$match + $mlen c"
- if {$sel ne {} && [$ctext compare $match == [lindex $sel 0]]} {
- $ctext tag add currentsearchhit $match $mend
- } else {
- $ctext tag add found $match $mend
- }
+ set match [$ctext search -count mlen -- $searchstring $mend $last.end]
+ if {$match eq {}} break
+ set mend "$match + $mlen c"
+ if {$sel ne {} && [$ctext compare $match == [lindex $sel 0]]} {
+ $ctext tag add currentsearchhit $match $mend
+ } else {
+ $ctext tag add found $match $mend
+ }
}
}
@@ -8554,19 +8572,19 @@ proc searchmarkvisible {doall} {
set topline [lindex [split [$ctext index @0,0] .] 0]
set botline [lindex [split [$ctext index @0,[winfo height $ctext]] .] 0]
if {$doall || $botline < $smarktop || $topline > $smarkbot} {
- # no overlap with previous
- searchmark $topline $botline
- set smarktop $topline
- set smarkbot $botline
+ # no overlap with previous
+ searchmark $topline $botline
+ set smarktop $topline
+ set smarkbot $botline
} else {
- if {$topline < $smarktop} {
- searchmark $topline [expr {$smarktop-1}]
- set smarktop $topline
- }
- if {$botline > $smarkbot} {
- searchmark [expr {$smarkbot+1}] $botline
- set smarkbot $botline
- }
+ if {$topline < $smarktop} {
+ searchmark $topline [expr {$smarktop-1}]
+ set smarktop $topline
+ }
+ if {$botline > $smarkbot} {
+ searchmark [expr {$smarkbot+1}] $botline
+ set smarkbot $botline
+ }
}
}
@@ -8582,15 +8600,15 @@ proc scrolltext {f0 f1} {
set topidx [$ctext index @0,0]
if {![info exists suppress_highlighting_file_for_this_scrollpos]
- || $topidx ne $suppress_highlighting_file_for_this_scrollpos} {
- highlightfile_for_scrollpos $topidx
+ || $topidx ne $suppress_highlighting_file_for_this_scrollpos} {
+ highlightfile_for_scrollpos $topidx
}
unset -nocomplain suppress_highlighting_file_for_this_scrollpos
.bleft.bottom.sb set $f0 $f1
if {$searchstring ne {}} {
- searchmarkvisible 0
+ searchmarkvisible 0
}
}
@@ -8619,8 +8637,8 @@ proc redisplay {} {
allcanvs yview moveto [lindex $span 0]
drawvisible
if {$selectedline ne {}} {
- selectline $selectedline 0
- allcanvs yview moveto [lindex $span 0]
+ selectline $selectedline 0
+ allcanvs yview moveto [lindex $span 0]
}
}
@@ -8630,20 +8648,20 @@ proc parsefont {f n} {
set fontattr($f,family) [lindex $n 0]
set s [lindex $n 1]
if {$s eq {} || $s == 0} {
- set s 10
+ set s 10
} elseif {$s < 0} {
- set s [expr {int(-$s / [winfo fpixels . 1p] + 0.5)}]
+ set s [expr {int(-$s / [winfo fpixels . 1p] + 0.5)}]
}
set fontattr($f,size) $s
set fontattr($f,weight) normal
set fontattr($f,slant) roman
foreach style [lrange $n 2 end] {
- switch -- $style {
- "normal" -
- "bold" {set fontattr($f,weight) $style}
- "roman" -
- "italic" {set fontattr($f,slant) $style}
- }
+ switch -- $style {
+ "normal" -
+ "bold" {set fontattr($f,weight) $style}
+ "roman" -
+ "italic" {set fontattr($f,slant) $style}
+ }
}
}
@@ -8651,8 +8669,8 @@ proc fontflags {f {isbold 0}} {
global fontattr
return [list -family $fontattr($f,family) -size $fontattr($f,size) \
- -weight [expr {$isbold? "bold": $fontattr($f,weight)}] \
- -slant $fontattr($f,slant)]
+ -weight [expr {$isbold? "bold": $fontattr($f,weight)}] \
+ -slant $fontattr($f,slant)]
}
proc fontname {f} {
@@ -8660,10 +8678,10 @@ proc fontname {f} {
set n [list $fontattr($f,family) $fontattr($f,size)]
if {$fontattr($f,weight) eq "bold"} {
- lappend n "bold"
+ lappend n "bold"
}
if {$fontattr($f,slant) eq "italic"} {
- lappend n "italic"
+ lappend n "italic"
}
return $n
}
@@ -8676,7 +8694,7 @@ proc incrfont {inc} {
set s $fontattr(mainfont,size)
incr s $inc
if {$s < 1} {
- set s 1
+ set s 1
}
set fontattr(mainfont,size) $s
font config mainfont -size $s
@@ -8685,7 +8703,7 @@ proc incrfont {inc} {
set s $fontattr(textfont,size)
incr s $inc
if {$s < 1} {
- set s 1
+ set s 1
}
set fontattr(textfont,size) $s
font config textfont -size $s
@@ -8699,23 +8717,23 @@ proc incrfont {inc} {
proc clearsha1 {} {
global sha1entry sha1string
if {[string length $sha1string] == 40} {
- $sha1entry delete 0 end
+ $sha1entry delete 0 end
}
}
proc sha1change {n1 n2 op} {
global sha1string currentid sha1but
if {$sha1string == {}
- || ([info exists currentid] && $sha1string == $currentid)} {
- set state disabled
+ || ([info exists currentid] && $sha1string == $currentid)} {
+ set state disabled
} else {
- set state normal
+ set state normal
}
if {[$sha1but cget -state] == $state} return
if {$state == "normal"} {
- $sha1but conf -state normal -relief raised -text "[mc "Goto:"] "
+ $sha1but conf -state normal -relief raised -text "[mc "Goto:"] "
} else {
- $sha1but conf -state disabled -relief flat -text "[mc "SHA1 ID:"] "
+ $sha1but conf -state disabled -relief flat -text "[mc "SHA1 ID:"] "
}
}
@@ -8723,37 +8741,37 @@ proc gotocommit {} {
global sha1string tagids headids curview varcid
if {$sha1string == {}
- || ([info exists currentid] && $sha1string == $currentid)} return
+ || ([info exists currentid] && $sha1string == $currentid)} return
if {[info exists tagids($sha1string)]} {
- set id $tagids($sha1string)
+ set id $tagids($sha1string)
} elseif {[info exists headids($sha1string)]} {
- set id $headids($sha1string)
+ set id $headids($sha1string)
} else {
- set id [string tolower $sha1string]
- if {[regexp {^[0-9a-f]{4,39}$} $id]} {
- set matches [longid $id]
- if {$matches ne {}} {
- if {[llength $matches] > 1} {
- error_popup [mc "Short SHA1 id %s is ambiguous" $id]
- return
- }
- set id [lindex $matches 0]
- }
- } else {
- if {[catch {set id [exec git rev-parse --verify $sha1string]}]} {
- error_popup [mc "Revision %s is not known" $sha1string]
- return
- }
- }
+ set id [string tolower $sha1string]
+ if {[regexp {^[0-9a-f]{4,39}$} $id]} {
+ set matches [longid $id]
+ if {$matches ne {}} {
+ if {[llength $matches] > 1} {
+ error_popup [mc "Short SHA1 id %s is ambiguous" $id]
+ return
+ }
+ set id [lindex $matches 0]
+ }
+ } else {
+ if {[catch {set id [exec git rev-parse --verify $sha1string]}]} {
+ error_popup [mc "Revision %s is not known" $sha1string]
+ return
+ }
+ }
}
if {[commitinview $id $curview]} {
- selectline [rowofcommit $id] 1
- return
+ selectline [rowofcommit $id] 1
+ return
}
if {[regexp {^[0-9a-fA-F]{4,}$} $sha1string]} {
- set msg [mc "SHA1 id %s is not known" $sha1string]
+ set msg [mc "SHA1 id %s is not known" $sha1string]
} else {
- set msg [mc "Revision %s is not in the current view" $sha1string]
+ set msg [mc "Revision %s is not in the current view" $sha1string]
}
error_popup $msg
}
@@ -8767,7 +8785,7 @@ proc lineenter {x y id} {
set hovery $y
set hoverid $id
if {[info exists hovertimer]} {
- after cancel $hovertimer
+ after cancel $hovertimer
}
set hovertimer [after 500 linehover]
$canv delete hover
@@ -8777,12 +8795,12 @@ proc linemotion {x y id} {
global hoverx hovery hoverid hovertimer
if {[info exists hoverid] && $id == $hoverid} {
- set hoverx $x
- set hovery $y
- if {[info exists hovertimer]} {
- after cancel $hovertimer
- }
- set hovertimer [after 500 linehover]
+ set hoverx $x
+ set hovery $y
+ if {[info exists hovertimer]} {
+ after cancel $hovertimer
+ }
+ set hovertimer [after 500 linehover]
}
}
@@ -8790,12 +8808,12 @@ proc lineleave {id} {
global hoverid hovertimer canv
if {[info exists hoverid] && $id == $hoverid} {
- $canv delete hover
- if {[info exists hovertimer]} {
- after cancel $hovertimer
- unset hovertimer
- }
- unset hoverid
+ $canv delete hover
+ if {[info exists hovertimer]} {
+ after cancel $hovertimer
+ unset hovertimer
+ }
+ unset hoverid
}
}
@@ -8817,11 +8835,11 @@ proc linehover {} {
set x1 [expr {$x + [font measure mainfont $text] + 2 * $lthickness}]
set y1 [expr {$y + $linespc + 2 * $lthickness}]
set t [$canv create rectangle $x0 $y0 $x1 $y1 \
- -fill $linehoverbgcolor -outline $linehoveroutlinecolor \
- -width 1 -tags hover]
+ -fill $linehoverbgcolor -outline $linehoveroutlinecolor \
+ -width 1 -tags hover]
$canv raise $t
set t [$canv create text $x $y -anchor nw -text $text -tags hover \
- -font mainfont -fill $linehoverfgcolor]
+ -font mainfont -fill $linehoverfgcolor]
$canv raise $t
}
@@ -8832,10 +8850,10 @@ proc clickisonarrow {id y} {
set thresh [expr {2 * $lthickness + 6}]
set n [expr {[llength $ranges] - 1}]
for {set i 1} {$i < $n} {incr i} {
- set row [lindex $ranges $i]
- if {abs([yc $row] - $y) < $thresh} {
- return $i
- }
+ set row [lindex $ranges $i]
+ if {abs([yc $row] - $y) < $thresh} {
+ return $i
+ }
}
return {}
}
@@ -8853,7 +8871,7 @@ proc arrowjump {id n y} {
set yspan [expr {[lindex $view 1] - [lindex $view 0]}]
set yfrac [expr {$yt / $ymax - $yspan / 2}]
if {$yfrac < 0} {
- set yfrac 0
+ set yfrac 0
}
allcanvs yview moveto $yfrac
}
@@ -8870,19 +8888,19 @@ proc lineclick {x y id isnew} {
set thickerline $id
drawlines $id
if {$isnew} {
- set ymax [lindex [$canv cget -scrollregion] 3]
- if {$ymax eq {}} return
- set yfrac [lindex [$canv yview] 0]
- set y [expr {$y + $yfrac * $ymax}]
+ set ymax [lindex [$canv cget -scrollregion] 3]
+ if {$ymax eq {}} return
+ set yfrac [lindex [$canv yview] 0]
+ set y [expr {$y + $yfrac * $ymax}]
}
set dirn [clickisonarrow $id $y]
if {$dirn ne {}} {
- arrowjump $id $dirn $y
- return
+ arrowjump $id $dirn $y
+ return
}
if {$isnew} {
- addtohistory [list lineclick $x $y $id 0] savectextpos
+ addtohistory [list lineclick $x $y $id 0] savectextpos
}
# fill the details pane with info about this line
$ctext conf -state normal
@@ -8898,20 +8916,20 @@ proc lineclick {x y id isnew} {
$ctext insert end "\t[mc "Date"]:\t$date\n"
set kids $children($curview,$id)
if {$kids ne {}} {
- $ctext insert end "\n[mc "Children"]:"
- set i 0
- foreach child $kids {
- incr i
- if {![info exists commitinfo($child)] && ![getcommit $child]} continue
- set info $commitinfo($child)
- $ctext insert end "\n\t"
- $ctext insert end $child link$i
- setlink $child link$i
- $ctext insert end "\n\t[lindex $info 0]"
- $ctext insert end "\n\t[mc "Author"]:\t[lindex $info 1]"
- set date [formatdate [lindex $info 2]]
- $ctext insert end "\n\t[mc "Date"]:\t$date\n"
- }
+ $ctext insert end "\n[mc "Children"]:"
+ set i 0
+ foreach child $kids {
+ incr i
+ if {![info exists commitinfo($child)] && ![getcommit $child]} continue
+ set info $commitinfo($child)
+ $ctext insert end "\n\t"
+ $ctext insert end $child link$i
+ setlink $child link$i
+ $ctext insert end "\n\t[lindex $info 0]"
+ $ctext insert end "\n\t[mc "Author"]:\t[lindex $info 1]"
+ set date [formatdate [lindex $info 2]]
+ $ctext insert end "\n\t[mc "Date"]:\t$date\n"
+ }
}
maybe_scroll_ctext 1
$ctext conf -state disabled
@@ -8921,23 +8939,23 @@ proc lineclick {x y id isnew} {
proc normalline {} {
global thickerline
if {[info exists thickerline]} {
- set id $thickerline
- unset thickerline
- drawlines $id
+ set id $thickerline
+ unset thickerline
+ drawlines $id
}
}
proc selbyid {id {isnew 1}} {
global curview
if {[commitinview $id $curview]} {
- selectline [rowofcommit $id] $isnew
+ selectline [rowofcommit $id] $isnew
}
}
proc mstime {} {
global startmstime
if {![info exists startmstime]} {
- set startmstime [clock clicks -milliseconds]
+ set startmstime [clock clicks -milliseconds]
}
return [format "%.3f" [expr {([clock click -milliseconds] - $startmstime) / 1000.0}]]
}
@@ -8949,27 +8967,27 @@ proc rowmenu {x y id} {
stopfinding
set rowmenuid $id
if {$selectedline eq {} || [rowofcommit $id] eq $selectedline} {
- set state disabled
+ set state disabled
} else {
- set state normal
+ set state normal
}
if {[info exists markedid] && $markedid ne $id} {
- set mstate normal
+ set mstate normal
} else {
- set mstate disabled
+ set mstate disabled
}
if {$id ne $nullid && $id ne $nullid2} {
- set menu $rowctxmenu
- if {$mainhead ne {}} {
- $menu entryconfigure 8 -label [mc "Reset %s branch to here" $mainhead] -state normal
- } else {
- $menu entryconfigure 8 -label [mc "Detached head: can't reset" $mainhead] -state disabled
- }
- $menu entryconfigure 10 -state $mstate
- $menu entryconfigure 11 -state $mstate
- $menu entryconfigure 12 -state $mstate
+ set menu $rowctxmenu
+ if {$mainhead ne {}} {
+ $menu entryconfigure 8 -label [mc "Reset %s branch to here" $mainhead] -state normal
+ } else {
+ $menu entryconfigure 8 -label [mc "Detached head: can't reset" $mainhead] -state disabled
+ }
+ $menu entryconfigure 10 -state $mstate
+ $menu entryconfigure 11 -state $mstate
+ $menu entryconfigure 12 -state $mstate
} else {
- set menu $fakerowmenu
+ set menu $fakerowmenu
}
$menu entryconfigure [mca "Diff this -> selected"] -state $state
$menu entryconfigure [mca "Diff selected -> this"] -state $state
@@ -8990,7 +9008,7 @@ proc gotomark {} {
global markedid
if {[info exists markedid]} {
- selbyid $markedid
+ selbyid $markedid
}
}
@@ -9000,7 +9018,7 @@ proc replace_by_kids {l r} {
set id [commitonrow $r]
set l [lreplace $l 0 0]
foreach kid $children($curview,$id) {
- lappend l [rowofcommit $kid]
+ lappend l [rowofcommit $kid]
}
return [lsort -integer -decreasing -unique $l]
}
@@ -9010,23 +9028,23 @@ proc find_common_desc {} {
if {![info exists markedid]} return
if {![commitinview $markedid $curview] ||
- ![commitinview $rowmenuid $curview]} return
+ ![commitinview $rowmenuid $curview]} return
#set t1 [clock clicks -milliseconds]
set l1 [list [rowofcommit $markedid]]
set l2 [list [rowofcommit $rowmenuid]]
while 1 {
- set r1 [lindex $l1 0]
- set r2 [lindex $l2 0]
- if {$r1 eq {} || $r2 eq {}} break
- if {$r1 == $r2} {
- selectline $r1 1
- break
- }
- if {$r1 > $r2} {
- set l1 [replace_by_kids $l1 $r1]
- } else {
- set l2 [replace_by_kids $l2 $r2]
- }
+ set r1 [lindex $l1 0]
+ set r2 [lindex $l2 0]
+ if {$r1 eq {} || $r2 eq {}} break
+ if {$r1 == $r2} {
+ selectline $r1 1
+ break
+ }
+ if {$r1 > $r2} {
+ set l1 [replace_by_kids $l1 $r1]
+ } else {
+ set l2 [replace_by_kids $l2 $r2]
+ }
}
#set t2 [clock clicks -milliseconds]
#puts "took [expr {$t2-$t1}]ms"
@@ -9045,15 +9063,15 @@ proc getpatchid {id} {
global patchids
if {![info exists patchids($id)]} {
- set cmd [diffcmd [list $id] {-p --root}]
- # trim off the initial "|"
- set cmd [lrange $cmd 1 end]
- if {[catch {
- set x [eval exec $cmd | git patch-id]
- set patchids($id) [lindex $x 0]
- }]} {
- set patchids($id) "error"
- }
+ set cmd [diffcmd [list $id] {-p --root}]
+ # trim off the initial "|"
+ set cmd [lrange $cmd 1 end]
+ if {[catch {
+ set x [eval exec $cmd | git patch-id]
+ set patchids($id) [lindex $x 0]
+ }]} {
+ set patchids($id) "error"
+ }
}
return $patchids($id)
}
@@ -9065,75 +9083,75 @@ proc do_cmp_commits {a b} {
clear_ctext
init_flist {}
for {set i 0} {$i < 100} {incr i} {
- set skipa 0
- set skipb 0
- if {[llength $parents($curview,$a)] > 1} {
- appendshortlink $a [mc "Skipping merge commit "] "\n"
- set skipa 1
- } else {
- set patcha [getpatchid $a]
- }
- if {[llength $parents($curview,$b)] > 1} {
- appendshortlink $b [mc "Skipping merge commit "] "\n"
- set skipb 1
- } else {
- set patchb [getpatchid $b]
- }
- if {!$skipa && !$skipb} {
- set heada [lindex $commitinfo($a) 0]
- set headb [lindex $commitinfo($b) 0]
- if {$patcha eq "error"} {
- appendshortlink $a [mc "Error getting patch ID for "] \
- [mc " - stopping\n"]
- break
- }
- if {$patchb eq "error"} {
- appendshortlink $b [mc "Error getting patch ID for "] \
- [mc " - stopping\n"]
- break
- }
- if {$patcha eq $patchb} {
- if {$heada eq $headb} {
- appendshortlink $a [mc "Commit "]
- appendshortlink $b " == " " $heada\n"
- } else {
- appendshortlink $a [mc "Commit "] " $heada\n"
- appendshortlink $b [mc " is the same patch as\n "] \
- " $headb\n"
- }
- set skipa 1
- set skipb 1
- } else {
- $ctext insert end "\n"
- appendshortlink $a [mc "Commit "] " $heada\n"
- appendshortlink $b [mc " differs from\n "] \
- " $headb\n"
- $ctext insert end [mc "Diff of commits:\n\n"]
- $ctext conf -state disabled
- update
- diffcommits $a $b
- return
- }
- }
- if {$skipa} {
- set kids [real_children $curview,$a]
- if {[llength $kids] != 1} {
- $ctext insert end "\n"
- appendshortlink $a [mc "Commit "] \
- [mc " has %s children - stopping\n" [llength $kids]]
- break
- }
- set a [lindex $kids 0]
- }
- if {$skipb} {
- set kids [real_children $curview,$b]
- if {[llength $kids] != 1} {
- appendshortlink $b [mc "Commit "] \
- [mc " has %s children - stopping\n" [llength $kids]]
- break
- }
- set b [lindex $kids 0]
- }
+ set skipa 0
+ set skipb 0
+ if {[llength $parents($curview,$a)] > 1} {
+ appendshortlink $a [mc "Skipping merge commit "] "\n"
+ set skipa 1
+ } else {
+ set patcha [getpatchid $a]
+ }
+ if {[llength $parents($curview,$b)] > 1} {
+ appendshortlink $b [mc "Skipping merge commit "] "\n"
+ set skipb 1
+ } else {
+ set patchb [getpatchid $b]
+ }
+ if {!$skipa && !$skipb} {
+ set heada [lindex $commitinfo($a) 0]
+ set headb [lindex $commitinfo($b) 0]
+ if {$patcha eq "error"} {
+ appendshortlink $a [mc "Error getting patch ID for "] \
+ [mc " - stopping\n"]
+ break
+ }
+ if {$patchb eq "error"} {
+ appendshortlink $b [mc "Error getting patch ID for "] \
+ [mc " - stopping\n"]
+ break
+ }
+ if {$patcha eq $patchb} {
+ if {$heada eq $headb} {
+ appendshortlink $a [mc "Commit "]
+ appendshortlink $b " == " " $heada\n"
+ } else {
+ appendshortlink $a [mc "Commit "] " $heada\n"
+ appendshortlink $b [mc " is the same patch as\n "] \
+ " $headb\n"
+ }
+ set skipa 1
+ set skipb 1
+ } else {
+ $ctext insert end "\n"
+ appendshortlink $a [mc "Commit "] " $heada\n"
+ appendshortlink $b [mc " differs from\n "] \
+ " $headb\n"
+ $ctext insert end [mc "Diff of commits:\n\n"]
+ $ctext conf -state disabled
+ update
+ diffcommits $a $b
+ return
+ }
+ }
+ if {$skipa} {
+ set kids [real_children $curview,$a]
+ if {[llength $kids] != 1} {
+ $ctext insert end "\n"
+ appendshortlink $a [mc "Commit "] \
+ [mc " has %s children - stopping\n" [llength $kids]]
+ break
+ }
+ set a [lindex $kids 0]
+ }
+ if {$skipb} {
+ set kids [real_children $curview,$b]
+ if {[llength $kids] != 1} {
+ appendshortlink $b [mc "Commit "] \
+ [mc " has %s children - stopping\n" [llength $kids]]
+ break
+ }
+ set b [lindex $kids 0]
+ }
}
$ctext conf -state disabled
}
@@ -9145,17 +9163,17 @@ proc diffcommits {a b} {
set fna [file join $tmpdir "commit-[string range $a 0 7]"]
set fnb [file join $tmpdir "commit-[string range $b 0 7]"]
if {[catch {
- exec git diff-tree -p --pretty $a >$fna
- exec git diff-tree -p --pretty $b >$fnb
+ exec git diff-tree -p --pretty $a >$fna
+ exec git diff-tree -p --pretty $b >$fnb
} err]} {
- error_popup [mc "Error writing commit to file: %s" $err]
- return
+ error_popup [mc "Error writing commit to file: %s" $err]
+ return
}
if {[catch {
- set fd [open "| diff -U$diffcontext $fna $fnb" r]
+ set fd [open "| diff -U$diffcontext $fna $fnb" r]
} err]} {
- error_popup [mc "Error diffing commits: %s" $err]
- return
+ error_popup [mc "Error diffing commits: %s" $err]
+ return
}
set diffids [list commits $a $b]
set blobdifffd($diffids) $fd
@@ -9169,11 +9187,11 @@ proc diffvssel {dirn} {
if {$selectedline eq {}} return
if {$dirn} {
- set oldid [commitonrow $selectedline]
- set newid $rowmenuid
+ set oldid [commitonrow $selectedline]
+ set newid $rowmenuid
} else {
- set oldid $rowmenuid
- set newid [commitonrow $selectedline]
+ set oldid $rowmenuid
+ set newid [commitonrow $selectedline]
}
addtohistory [list doseldiff $oldid $newid] savectextpos
doseldiff $oldid $newid
@@ -9184,11 +9202,11 @@ proc diffvsmark {dirn} {
if {![info exists markedid]} return
if {$dirn} {
- set oldid $markedid
- set newid $rowmenuid
+ set oldid $markedid
+ set newid $rowmenuid
} else {
- set oldid $rowmenuid
- set newid $markedid
+ set oldid $rowmenuid
+ set newid $markedid
}
addtohistory [list doseldiff $oldid $newid] savectextpos
doseldiff $oldid $newid
@@ -9277,11 +9295,11 @@ proc mkpatchrev {} {
set newid [$patchtop.tosha1 get]
set newhead [$patchtop.tohead get]
foreach e [list fromsha1 fromhead tosha1 tohead] \
- v [list $newid $newhead $oldid $oldhead] {
- $patchtop.$e conf -state normal
- $patchtop.$e delete 0 end
- $patchtop.$e insert 0 $v
- $patchtop.$e conf -state readonly
+ v [list $newid $newhead $oldid $oldhead] {
+ $patchtop.$e conf -state normal
+ $patchtop.$e delete 0 end
+ $patchtop.$e insert 0 $v
+ $patchtop.$e conf -state readonly
}
}
@@ -9296,7 +9314,7 @@ proc mkpatchgo {} {
set cmd [lrange $cmd 1 end]
lappend cmd >$fname &
if {[catch {eval exec $cmd} err]} {
- error_popup "[mc "Error creating patch:"] $err" $patchtop
+ error_popup "[mc "Error creating patch:"] $err" $patchtop
}
catch {destroy $patchtop}
unset patchtop
@@ -9355,22 +9373,22 @@ proc domktag {} {
set tag [$mktagtop.tag get]
set msg [$mktagtop.msg get]
if {$tag == {}} {
- error_popup [mc "No tag name specified"] $mktagtop
- return 0
+ error_popup [mc "No tag name specified"] $mktagtop
+ return 0
}
if {[info exists tagids($tag)]} {
- error_popup [mc "Tag \"%s\" already exists" $tag] $mktagtop
- return 0
+ error_popup [mc "Tag \"%s\" already exists" $tag] $mktagtop
+ return 0
}
if {[catch {
- if {$msg != {}} {
- exec git tag -a -m $msg $tag $id
- } else {
- exec git tag $tag $id
- }
+ if {$msg != {}} {
+ exec git tag -a -m $msg $tag $id
+ } else {
+ exec git tag $tag $id
+ }
} err]} {
- error_popup "[mc "Error creating tag:"] $err" $mktagtop
- return 0
+ error_popup "[mc "Error creating tag:"] $err" $mktagtop
+ return 0
}
set tagids($tag) $id
@@ -9391,9 +9409,9 @@ proc redrawtags {id} {
if {![info exists iddrawn($id)]} return
set row [rowofcommit $id]
if {$id eq $mainheadid} {
- set ofill $mainheadcirclecolor
+ set ofill $mainheadcirclecolor
} else {
- set ofill [lindex $circlecolors $cmitlisted($curview,$id)]
+ set ofill [lindex $circlecolors $cmitlisted($curview,$id)]
}
$canv itemconf $circleitem($row) -fill $ofill
$canv delete tag.$id
@@ -9403,14 +9421,14 @@ proc redrawtags {id} {
set font [$canv itemcget $linehtag($id) -font]
set xr [expr {$xt + [font measure $font $text]}]
if {$xr > $canvxmax} {
- set canvxmax $xr
- setcanvscroll
+ set canvxmax $xr
+ setcanvscroll
}
if {[info exists currentid] && $currentid == $id} {
- make_secsel $id
+ make_secsel $id
}
if {[info exists markedid] && $markedid eq $id} {
- make_idmark $id
+ make_idmark $id
}
}
@@ -9426,7 +9444,7 @@ proc mktaggo {} {
mktagcan
}
-proc copysummary {} {
+proc copyreference {} {
global rowmenuid autosellen
set format "%h (\"%s\", %ad)"
@@ -9434,10 +9452,10 @@ proc copysummary {} {
if {$autosellen < 40} {
lappend cmd --abbrev=$autosellen
}
- set summary [eval exec $cmd $rowmenuid]
+ set reference [eval exec $cmd $rowmenuid]
clipboard clear
- clipboard append $summary
+ clipboard append $reference
}
proc writecommit {} {
@@ -9485,7 +9503,7 @@ proc wrcomgo {} {
set cmd "echo $id | [$wrcomtop.cmd get]"
set fname [$wrcomtop.fname get]
if {[catch {exec sh -c $cmd >$fname &} err]} {
- error_popup "[mc "Error writing commit:"] $err" $wrcomtop
+ error_popup "[mc "Error writing commit:"] $err" $wrcomtop
}
catch {destroy $wrcomtop}
unset wrcomtop
@@ -9572,41 +9590,41 @@ proc mkbrgo {top} {
set cmdargs {}
set old_id {}
if {$name eq {}} {
- error_popup [mc "Please specify a name for the new branch"] $top
- return
+ error_popup [mc "Please specify a name for the new branch"] $top
+ return
}
if {[info exists headids($name)]} {
- if {![confirm_popup [mc \
- "Branch '%s' already exists. Overwrite?" $name] $top]} {
- return
- }
- set old_id $headids($name)
- lappend cmdargs -f
+ if {![confirm_popup [mc \
+ "Branch '%s' already exists. Overwrite?" $name] $top]} {
+ return
+ }
+ set old_id $headids($name)
+ lappend cmdargs -f
}
catch {destroy $top}
lappend cmdargs $name $id
nowbusy newbranch
update
if {[catch {
- eval exec git branch $cmdargs
+ eval exec git branch $cmdargs
} err]} {
- notbusy newbranch
- error_popup $err
+ notbusy newbranch
+ error_popup $err
} else {
- notbusy newbranch
- if {$old_id ne {}} {
- movehead $id $name
- movedhead $id $name
- redrawtags $old_id
- redrawtags $id
- } else {
- set headids($name) $id
- lappend idheads($id) $name
- addedhead $id $name
- redrawtags $id
- }
- dispneartags 0
- run refill_reflist
+ notbusy newbranch
+ if {$old_id ne {}} {
+ movehead $id $name
+ movedhead $id $name
+ redrawtags $old_id
+ redrawtags $id
+ } else {
+ set headids($name) $id
+ lappend idheads($id) $name
+ addedhead $id $name
+ redrawtags $id
+ }
+ dispneartags 0
+ run refill_reflist
}
}
@@ -9617,36 +9635,36 @@ proc mvbrgo {top prevname} {
set id [$top.sha1 get]
set cmdargs {}
if {$name eq $prevname} {
- catch {destroy $top}
- return
+ catch {destroy $top}
+ return
}
if {$name eq {}} {
- error_popup [mc "Please specify a new name for the branch"] $top
- return
+ error_popup [mc "Please specify a new name for the branch"] $top
+ return
}
catch {destroy $top}
lappend cmdargs -m $prevname $name
nowbusy renamebranch
update
if {[catch {
- eval exec git branch $cmdargs
+ eval exec git branch $cmdargs
} err]} {
- notbusy renamebranch
- error_popup $err
+ notbusy renamebranch
+ error_popup $err
} else {
- notbusy renamebranch
- removehead $id $prevname
- removedhead $id $prevname
- set headids($name) $id
- lappend idheads($id) $name
- addedhead $id $name
- if {$prevname eq $mainhead} {
- set mainhead $name
- set mainheadid $id
- }
- redrawtags $id
- dispneartags 0
- run refill_reflist
+ notbusy renamebranch
+ removehead $id $prevname
+ removedhead $id $prevname
+ set headids($name) $id
+ lappend idheads($id) $name
+ addedhead $id $name
+ if {$prevname eq $mainhead} {
+ set mainhead $name
+ set mainheadid $id
+ }
+ redrawtags $id
+ dispneartags 0
+ run refill_reflist
}
}
@@ -9656,18 +9674,18 @@ proc exec_citool {tool_args {baseid {}}} {
set save_env [array get env GIT_AUTHOR_*]
if {$baseid ne {}} {
- if {![info exists commitinfo($baseid)]} {
- getcommit $baseid
- }
- set author [lindex $commitinfo($baseid) 1]
- set date [lindex $commitinfo($baseid) 2]
- if {[regexp {^\s*(\S.*\S|\S)\s*<(.*)>\s*$} \
- $author author name email]
- && $date ne {}} {
- set env(GIT_AUTHOR_NAME) $name
- set env(GIT_AUTHOR_EMAIL) $email
- set env(GIT_AUTHOR_DATE) $date
- }
+ if {![info exists commitinfo($baseid)]} {
+ getcommit $baseid
+ }
+ set author [lindex $commitinfo($baseid) 1]
+ set date [lindex $commitinfo($baseid) 2]
+ if {[regexp {^\s*(\S.*\S|\S)\s*<(.*)>\s*$} \
+ $author author name email]
+ && $date ne {}} {
+ set env(GIT_AUTHOR_NAME) $name
+ set env(GIT_AUTHOR_EMAIL) $email
+ set env(GIT_AUTHOR_DATE) $date
+ }
}
eval exec git citool $tool_args &
@@ -9684,57 +9702,57 @@ proc cherrypick {} {
set oldhead [exec git rev-parse HEAD]
set dheads [descheads $rowmenuid]
if {$dheads ne {} && [lsearch -exact $dheads $oldhead] >= 0} {
- set ok [confirm_popup [mc "Commit %s is already\
- included in branch %s -- really re-apply it?" \
- [string range $rowmenuid 0 7] $mainhead]]
- if {!$ok} return
+ set ok [confirm_popup [mc "Commit %s is already\
+ included in branch %s -- really re-apply it?" \
+ [string range $rowmenuid 0 7] $mainhead]]
+ if {!$ok} return
}
nowbusy cherrypick [mc "Cherry-picking"]
update
# Unfortunately git-cherry-pick writes stuff to stderr even when
# no error occurs, and exec takes that as an indication of error...
if {[catch {exec sh -c "git cherry-pick -r $rowmenuid 2>&1"} err]} {
- notbusy cherrypick
- if {[regexp -line \
- {Entry '(.*)' (would be overwritten by merge|not uptodate)} \
- $err msg fname]} {
- error_popup [mc "Cherry-pick failed because of local changes\
- to file '%s'.\nPlease commit, reset or stash\
- your changes and try again." $fname]
- } elseif {[regexp -line \
- {^(CONFLICT \(.*\):|Automatic cherry-pick failed|error: could not apply)} \
- $err]} {
- if {[confirm_popup [mc "Cherry-pick failed because of merge\
- conflict.\nDo you wish to run git citool to\
- resolve it?"]]} {
- # Force citool to read MERGE_MSG
- file delete [file join $gitdir "GITGUI_MSG"]
- exec_citool {} $rowmenuid
- }
- } else {
- error_popup $err
- }
- run updatecommits
- return
+ notbusy cherrypick
+ if {[regexp -line \
+ {Entry '(.*)' (would be overwritten by merge|not uptodate)} \
+ $err msg fname]} {
+ error_popup [mc "Cherry-pick failed because of local changes\
+ to file '%s'.\nPlease commit, reset or stash\
+ your changes and try again." $fname]
+ } elseif {[regexp -line \
+ {^(CONFLICT \(.*\):|Automatic cherry-pick failed|error: could not apply)} \
+ $err]} {
+ if {[confirm_popup [mc "Cherry-pick failed because of merge\
+ conflict.\nDo you wish to run git citool to\
+ resolve it?"]]} {
+ # Force citool to read MERGE_MSG
+ file delete [file join $gitdir "GITGUI_MSG"]
+ exec_citool {} $rowmenuid
+ }
+ } else {
+ error_popup $err
+ }
+ run updatecommits
+ return
}
set newhead [exec git rev-parse HEAD]
if {$newhead eq $oldhead} {
- notbusy cherrypick
- error_popup [mc "No changes committed"]
- return
+ notbusy cherrypick
+ error_popup [mc "No changes committed"]
+ return
}
addnewchild $newhead $oldhead
if {[commitinview $oldhead $curview]} {
- # XXX this isn't right if we have a path limit...
- insertrow $newhead $oldhead $curview
- if {$mainhead ne {}} {
- movehead $newhead $mainhead
- movedhead $newhead $mainhead
- }
- set mainheadid $newhead
- redrawtags $oldhead
- redrawtags $newhead
- selbyid $newhead
+ # XXX this isn't right if we have a path limit...
+ insertrow $newhead $oldhead $curview
+ if {$mainhead ne {}} {
+ movehead $newhead $mainhead
+ movedhead $newhead $mainhead
+ }
+ set mainheadid $newhead
+ redrawtags $oldhead
+ redrawtags $newhead
+ selbyid $newhead
}
notbusy cherrypick
}
@@ -9809,18 +9827,18 @@ proc resethead {} {
make_transient $w .
wm title $w [mc "Confirm reset"]
${NS}::label $w.m -text \
- [mc "Reset branch %s to %s?" $mainhead [string range $rowmenuid 0 7]]
+ [mc "Reset branch %s to %s?" $mainhead [string range $rowmenuid 0 7]]
pack $w.m -side top -fill x -padx 20 -pady 20
${NS}::labelframe $w.f -text [mc "Reset type:"]
set resettype mixed
${NS}::radiobutton $w.f.soft -value soft -variable resettype \
- -text [mc "Soft: Leave working tree and index untouched"]
+ -text [mc "Soft: Leave working tree and index untouched"]
grid $w.f.soft -sticky w
${NS}::radiobutton $w.f.mixed -value mixed -variable resettype \
- -text [mc "Mixed: Leave working tree untouched, reset index"]
+ -text [mc "Mixed: Leave working tree untouched, reset index"]
grid $w.f.mixed -sticky w
${NS}::radiobutton $w.f.hard -value hard -variable resettype \
- -text [mc "Hard: Reset working tree and index\n(discard ALL local changes)"]
+ -text [mc "Hard: Reset working tree and index\n(discard ALL local changes)"]
grid $w.f.hard -sticky w
pack $w.f -side top -fill x -padx 4
${NS}::button $w.ok -text [mc OK] -command "set confirm_ok 1; destroy $w"
@@ -9832,13 +9850,13 @@ proc resethead {} {
tkwait window $w
if {!$confirm_ok} return
if {[catch {set fd [open \
- [list | git reset --$resettype $rowmenuid 2>@1] r]} err]} {
- error_popup $err
+ [list | git reset --$resettype $rowmenuid 2>@1] r]} err]} {
+ error_popup $err
} else {
- dohidelocalchanges
- filerun $fd [list readresetstat $fd]
- nowbusy reset [mc "Resetting"]
- selbyid $rowmenuid
+ dohidelocalchanges
+ filerun $fd [list readresetstat $fd]
+ nowbusy reset [mc "Resetting"]
+ selbyid $rowmenuid
}
}
@@ -9846,29 +9864,29 @@ proc readresetstat {fd} {
global mainhead mainheadid showlocalchanges rprogcoord
if {[gets $fd line] >= 0} {
- if {[regexp {([0-9]+)% \(([0-9]+)/([0-9]+)\)} $line match p m n]} {
- set rprogcoord [expr {1.0 * $m / $n}]
- adjustprogress
- }
- return 1
+ if {[regexp {([0-9]+)% \(([0-9]+)/([0-9]+)\)} $line match p m n]} {
+ set rprogcoord [expr {1.0 * $m / $n}]
+ adjustprogress
+ }
+ return 1
}
set rprogcoord 0
adjustprogress
notbusy reset
if {[catch {close $fd} err]} {
- error_popup $err
+ error_popup $err
}
set oldhead $mainheadid
set newhead [exec git rev-parse HEAD]
if {$newhead ne $oldhead} {
- movehead $newhead $mainhead
- movedhead $newhead $mainhead
- set mainheadid $newhead
- redrawtags $oldhead
- redrawtags $newhead
+ movehead $newhead $mainhead
+ movedhead $newhead $mainhead
+ set mainheadid $newhead
+ redrawtags $oldhead
+ redrawtags $newhead
}
if {$showlocalchanges} {
- doshowlocalchanges
+ doshowlocalchanges
}
return 0
}
@@ -9882,17 +9900,17 @@ proc headmenu {x y id head} {
set headmenuhead $head
array set state {0 normal 1 normal 2 normal}
if {[string match "remotes/*" $head]} {
- set localhead [string range $head [expr [string last / $head] + 1] end]
- if {[info exists headids($localhead)]} {
- set state(0) disabled
- }
- array set state {1 disabled 2 disabled}
+ set localhead [string range $head [expr [string last / $head] + 1] end]
+ if {[info exists headids($localhead)]} {
+ set state(0) disabled
+ }
+ array set state {1 disabled 2 disabled}
}
if {$head eq $mainhead} {
- array set state {0 disabled 2 disabled}
+ array set state {0 disabled 2 disabled}
}
foreach i {0 1 2} {
- $headctxmenu entryconfigure $i -state $state($i)
+ $headctxmenu entryconfigure $i -state $state($i)
}
tk_popup $headctxmenu $x $y
}
@@ -9905,32 +9923,32 @@ proc cobranch {} {
set newhead $headmenuhead
set command [list | git checkout]
if {[string match "remotes/*" $newhead]} {
- set remote $newhead
- set newhead [string range $newhead [expr [string last / $newhead] + 1] end]
- # The following check is redundant - the menu option should
- # be disabled to begin with...
- if {[info exists headids($newhead)]} {
- error_popup [mc "A local branch named %s exists already" $newhead]
- return
- }
- lappend command -b $newhead --track $remote
+ set remote $newhead
+ set newhead [string range $newhead [expr [string last / $newhead] + 1] end]
+ # The following check is redundant - the menu option should
+ # be disabled to begin with...
+ if {[info exists headids($newhead)]} {
+ error_popup [mc "A local branch named %s exists already" $newhead]
+ return
+ }
+ lappend command -b $newhead --track $remote
} else {
- lappend command $newhead
+ lappend command $newhead
}
lappend command 2>@1
nowbusy checkout [mc "Checking out"]
update
dohidelocalchanges
if {[catch {
- set fd [open $command r]
+ set fd [open $command r]
} err]} {
- notbusy checkout
- error_popup $err
- if {$showlocalchanges} {
- dodiffindex
- }
+ notbusy checkout
+ error_popup $err
+ if {$showlocalchanges} {
+ dodiffindex
+ }
} else {
- filerun $fd [list readcheckoutstat $fd $newhead $headmenuid]
+ filerun $fd [list readcheckoutstat $fd $newhead $headmenuid]
}
}
@@ -9939,24 +9957,24 @@ proc readcheckoutstat {fd newhead newheadid} {
global viewmainheadid curview
if {[gets $fd line] >= 0} {
- if {[regexp {([0-9]+)% \(([0-9]+)/([0-9]+)\)} $line match p m n]} {
- set progresscoords [list 0 [expr {1.0 * $m / $n}]]
- adjustprogress
- }
- return 1
+ if {[regexp {([0-9]+)% \(([0-9]+)/([0-9]+)\)} $line match p m n]} {
+ set progresscoords [list 0 [expr {1.0 * $m / $n}]]
+ adjustprogress
+ }
+ return 1
}
set progresscoords {0 0}
adjustprogress
notbusy checkout
if {[catch {close $fd} err]} {
- error_popup $err
- return
+ error_popup $err
+ return
}
set oldmainid $mainheadid
if {! [info exists headids($newhead)]} {
- set headids($newhead) $newheadid
- lappend idheads($newheadid) $newhead
- addedhead $newheadid $newhead
+ set headids($newhead) $newheadid
+ lappend idheads($newheadid) $newhead
+ addedhead $newheadid $newhead
}
set mainhead $newhead
set mainheadid $newheadid
@@ -9965,7 +9983,7 @@ proc readcheckoutstat {fd newhead newheadid} {
redrawtags $newheadid
selbyid $newheadid
if {$showlocalchanges} {
- dodiffindex
+ dodiffindex
}
}
@@ -9977,21 +9995,21 @@ proc rmbranch {} {
set id $headmenuid
# this check shouldn't be needed any more...
if {$head eq $mainhead} {
- error_popup [mc "Cannot delete the currently checked-out branch"]
- return
+ error_popup [mc "Cannot delete the currently checked-out branch"]
+ return
}
set dheads [descheads $id]
if {[llength $dheads] == 1 && $idheads($dheads) eq $head} {
- # the stuff on this branch isn't on any other branch
- if {![confirm_popup [mc "The commits on branch %s aren't on any other\
- branch.\nReally delete branch %s?" $head $head]]} return
+ # the stuff on this branch isn't on any other branch
+ if {![confirm_popup [mc "The commits on branch %s aren't on any other\
+ branch.\nReally delete branch %s?" $head $head]]} return
}
nowbusy rmbranch
update
if {[catch {exec git branch -D $head} err]} {
- notbusy rmbranch
- error_popup $err
- return
+ notbusy rmbranch
+ error_popup $err
+ return
}
removehead $id $head
removedhead $id $head
@@ -10009,22 +10027,22 @@ proc showrefs {} {
set top .showrefs
set showrefstop $top
if {[winfo exists $top]} {
- raise $top
- refill_reflist
- return
+ raise $top
+ refill_reflist
+ return
}
ttk_toplevel $top
wm title $top [mc "Tags and heads: %s" [file tail [pwd]]]
make_transient $top .
text $top.list -background $bgcolor -foreground $fgcolor \
- -selectbackground $selectbgcolor -font mainfont \
- -xscrollcommand "$top.xsb set" -yscrollcommand "$top.ysb set" \
- -width 30 -height 20 -cursor $maincursor \
- -spacing1 1 -spacing3 1 -state disabled
+ -selectbackground $selectbgcolor -font mainfont \
+ -xscrollcommand "$top.xsb set" -yscrollcommand "$top.ysb set" \
+ -width 30 -height 20 -cursor $maincursor \
+ -spacing1 1 -spacing3 1 -state disabled
$top.list tag configure highlight -background $selectbgcolor
if {![lsearch -exact $bglist $top.list]} {
- lappend bglist $top.list
- lappend fglist $top.list
+ lappend bglist $top.list
+ lappend fglist $top.list
}
${NS}::scrollbar $top.ysb -command "$top.list yview" -orient vertical
${NS}::scrollbar $top.xsb -command "$top.list xview" -orient horizontal
@@ -10058,10 +10076,10 @@ proc sel_reflist {w x y} {
set ref [lindex $reflist [expr {$l-1}]]
set n [lindex $ref 0]
switch -- [lindex $ref 1] {
- "H" {selbyid $headids($n)}
- "R" {selbyid $headids($n)}
- "T" {selbyid $tagids($n)}
- "o" {selbyid $otherrefids($n)}
+ "H" {selbyid $headids($n)}
+ "R" {selbyid $headids($n)}
+ "T" {selbyid $tagids($n)}
+ "o" {selbyid $otherrefids($n)}
}
$showrefstop.list tag add highlight $l.0 "$l.0 lineend"
}
@@ -10087,35 +10105,35 @@ proc refill_reflist {} {
if {![info exists showrefstop] || ![winfo exists $showrefstop]} return
set refs {}
foreach n [array names headids] {
- if {[string match $reflistfilter $n]} {
- if {[commitinview $headids($n) $curview]} {
- if {[string match "remotes/*" $n]} {
- lappend refs [list $n R]
- } else {
- lappend refs [list $n H]
- }
- } else {
- interestedin $headids($n) {run refill_reflist}
- }
- }
+ if {[string match $reflistfilter $n]} {
+ if {[commitinview $headids($n) $curview]} {
+ if {[string match "remotes/*" $n]} {
+ lappend refs [list $n R]
+ } else {
+ lappend refs [list $n H]
+ }
+ } else {
+ interestedin $headids($n) {run refill_reflist}
+ }
+ }
}
foreach n [array names tagids] {
- if {[string match $reflistfilter $n]} {
- if {[commitinview $tagids($n) $curview]} {
- lappend refs [list $n T]
- } else {
- interestedin $tagids($n) {run refill_reflist}
- }
- }
+ if {[string match $reflistfilter $n]} {
+ if {[commitinview $tagids($n) $curview]} {
+ lappend refs [list $n T]
+ } else {
+ interestedin $tagids($n) {run refill_reflist}
+ }
+ }
}
foreach n [array names otherrefids] {
- if {[string match $reflistfilter $n]} {
- if {[commitinview $otherrefids($n) $curview]} {
- lappend refs [list $n o]
- } else {
- interestedin $otherrefids($n) {run refill_reflist}
- }
- }
+ if {[string match $reflistfilter $n]} {
+ if {[commitinview $otherrefids($n) $curview]} {
+ lappend refs [list $n o]
+ } else {
+ interestedin $otherrefids($n) {run refill_reflist}
+ }
+ }
}
set refs [lsort -index 0 $refs]
if {$refs eq $reflist} return
@@ -10127,37 +10145,37 @@ proc refill_reflist {} {
set i 0
set j 0
while {$i < [llength $reflist] || $j < [llength $refs]} {
- if {$i < [llength $reflist]} {
- if {$j < [llength $refs]} {
- set cmp [string compare [lindex $reflist $i 0] \
- [lindex $refs $j 0]]
- if {$cmp == 0} {
- set cmp [string compare [lindex $reflist $i 1] \
- [lindex $refs $j 1]]
- }
- } else {
- set cmp -1
- }
- } else {
- set cmp 1
- }
- switch -- $cmp {
- -1 {
- $showrefstop.list delete "[expr {$j+1}].0" "[expr {$j+2}].0"
- incr i
- }
- 0 {
- incr i
- incr j
- }
- 1 {
- set l [expr {$j + 1}]
- $showrefstop.list image create $l.0 -align baseline \
- -image reficon-[lindex $refs $j 1] -padx 2
- $showrefstop.list insert $l.1 "[lindex $refs $j 0]\n"
- incr j
- }
- }
+ if {$i < [llength $reflist]} {
+ if {$j < [llength $refs]} {
+ set cmp [string compare [lindex $reflist $i 0] \
+ [lindex $refs $j 0]]
+ if {$cmp == 0} {
+ set cmp [string compare [lindex $reflist $i 1] \
+ [lindex $refs $j 1]]
+ }
+ } else {
+ set cmp -1
+ }
+ } else {
+ set cmp 1
+ }
+ switch -- $cmp {
+ -1 {
+ $showrefstop.list delete "[expr {$j+1}].0" "[expr {$j+2}].0"
+ incr i
+ }
+ 0 {
+ incr i
+ incr j
+ }
+ 1 {
+ set l [expr {$j + 1}]
+ $showrefstop.list image create $l.0 -align baseline \
+ -image reficon-[lindex $refs $j 1] -padx 2
+ $showrefstop.list insert $l.1 "[lindex $refs $j 0]\n"
+ incr j
+ }
+ }
}
set reflist $refs
# delete last newline
@@ -10172,54 +10190,54 @@ proc getallcommits {} {
global gitdir
if {![info exists allcommits]} {
- set nextarc 0
- set allcommits 0
- set seeds {}
- set allcwait 0
- set cachedarcs 0
- set allccache [file join $gitdir "gitk.cache"]
- if {![catch {
- set f [open $allccache r]
- set allcwait 1
- getcache $f
- }]} return
+ set nextarc 0
+ set allcommits 0
+ set seeds {}
+ set allcwait 0
+ set cachedarcs 0
+ set allccache [file join $gitdir "gitk.cache"]
+ if {![catch {
+ set f [open $allccache r]
+ set allcwait 1
+ getcache $f
+ }]} return
}
if {$allcwait} {
- return
+ return
}
set cmd [list | git rev-list --parents]
set allcupdate [expr {$seeds ne {}}]
if {!$allcupdate} {
- set ids "--all"
+ set ids "--all"
} else {
- set refs [concat [array names idheads] [array names idtags] \
- [array names idotherrefs]]
- set ids {}
- set tagobjs {}
- foreach name [array names tagobjid] {
- lappend tagobjs $tagobjid($name)
- }
- foreach id [lsort -unique $refs] {
- if {![info exists allparents($id)] &&
- [lsearch -exact $tagobjs $id] < 0} {
- lappend ids $id
- }
- }
- if {$ids ne {}} {
- foreach id $seeds {
- lappend ids "^$id"
- }
- }
+ set refs [concat [array names idheads] [array names idtags] \
+ [array names idotherrefs]]
+ set ids {}
+ set tagobjs {}
+ foreach name [array names tagobjid] {
+ lappend tagobjs $tagobjid($name)
+ }
+ foreach id [lsort -unique $refs] {
+ if {![info exists allparents($id)] &&
+ [lsearch -exact $tagobjs $id] < 0} {
+ lappend ids $id
+ }
+ }
+ if {$ids ne {}} {
+ foreach id $seeds {
+ lappend ids "^$id"
+ }
+ }
}
if {$ids ne {}} {
- set fd [open [concat $cmd $ids] r]
- fconfigure $fd -blocking 0
- incr allcommits
- nowbusy allcommits
- filerun $fd [list getallclines $fd]
+ set fd [open [concat $cmd $ids] r]
+ fconfigure $fd -blocking 0
+ incr allcommits
+ nowbusy allcommits
+ filerun $fd [list getallclines $fd]
} else {
- dispneartags 0
+ dispneartags 0
}
}
@@ -10245,103 +10263,103 @@ proc getallclines {fd} {
set nid 0
while {[incr nid] <= 1000 && [gets $fd line] >= 0} {
- set id [lindex $line 0]
- if {[info exists allparents($id)]} {
- # seen it already
- continue
- }
- set cachedarcs 0
- set olds [lrange $line 1 end]
- set allparents($id) $olds
- if {![info exists allchildren($id)]} {
- set allchildren($id) {}
- set arcnos($id) {}
- lappend seeds $id
- } else {
- set a $arcnos($id)
- if {[llength $olds] == 1 && [llength $a] == 1} {
- lappend arcids($a) $id
- if {[info exists idtags($id)]} {
- lappend arctags($a) $id
- }
- if {[info exists idheads($id)]} {
- lappend archeads($a) $id
- }
- if {[info exists allparents($olds)]} {
- # seen parent already
- if {![info exists arcout($olds)]} {
- splitarc $olds
- }
- lappend arcids($a) $olds
- set arcend($a) $olds
- unset growing($a)
- }
- lappend allchildren($olds) $id
- lappend arcnos($olds) $a
- continue
- }
- }
- foreach a $arcnos($id) {
- lappend arcids($a) $id
- set arcend($a) $id
- unset growing($a)
- }
-
- set ao {}
- foreach p $olds {
- lappend allchildren($p) $id
- set a [incr nextarc]
- set arcstart($a) $id
- set archeads($a) {}
- set arctags($a) {}
- set archeads($a) {}
- set arcids($a) {}
- lappend ao $a
- set growing($a) 1
- if {[info exists allparents($p)]} {
- # seen it already, may need to make a new branch
- if {![info exists arcout($p)]} {
- splitarc $p
- }
- lappend arcids($a) $p
- set arcend($a) $p
- unset growing($a)
- }
- lappend arcnos($p) $a
- }
- set arcout($id) $ao
+ set id [lindex $line 0]
+ if {[info exists allparents($id)]} {
+ # seen it already
+ continue
+ }
+ set cachedarcs 0
+ set olds [lrange $line 1 end]
+ set allparents($id) $olds
+ if {![info exists allchildren($id)]} {
+ set allchildren($id) {}
+ set arcnos($id) {}
+ lappend seeds $id
+ } else {
+ set a $arcnos($id)
+ if {[llength $olds] == 1 && [llength $a] == 1} {
+ lappend arcids($a) $id
+ if {[info exists idtags($id)]} {
+ lappend arctags($a) $id
+ }
+ if {[info exists idheads($id)]} {
+ lappend archeads($a) $id
+ }
+ if {[info exists allparents($olds)]} {
+ # seen parent already
+ if {![info exists arcout($olds)]} {
+ splitarc $olds
+ }
+ lappend arcids($a) $olds
+ set arcend($a) $olds
+ unset growing($a)
+ }
+ lappend allchildren($olds) $id
+ lappend arcnos($olds) $a
+ continue
+ }
+ }
+ foreach a $arcnos($id) {
+ lappend arcids($a) $id
+ set arcend($a) $id
+ unset growing($a)
+ }
+
+ set ao {}
+ foreach p $olds {
+ lappend allchildren($p) $id
+ set a [incr nextarc]
+ set arcstart($a) $id
+ set archeads($a) {}
+ set arctags($a) {}
+ set archeads($a) {}
+ set arcids($a) {}
+ lappend ao $a
+ set growing($a) 1
+ if {[info exists allparents($p)]} {
+ # seen it already, may need to make a new branch
+ if {![info exists arcout($p)]} {
+ splitarc $p
+ }
+ lappend arcids($a) $p
+ set arcend($a) $p
+ unset growing($a)
+ }
+ lappend arcnos($p) $a
+ }
+ set arcout($id) $ao
}
if {$nid > 0} {
- global cached_dheads cached_dtags cached_atags
- unset -nocomplain cached_dheads
- unset -nocomplain cached_dtags
- unset -nocomplain cached_atags
+ global cached_dheads cached_dtags cached_atags
+ unset -nocomplain cached_dheads
+ unset -nocomplain cached_dtags
+ unset -nocomplain cached_atags
}
if {![eof $fd]} {
- return [expr {$nid >= 1000? 2: 1}]
+ return [expr {$nid >= 1000? 2: 1}]
}
set cacheok 1
if {[catch {
- fconfigure $fd -blocking 1
- close $fd
+ fconfigure $fd -blocking 1
+ close $fd
} err]} {
- # got an error reading the list of commits
- # if we were updating, try rereading the whole thing again
- if {$allcupdate} {
- incr allcommits -1
- dropcache $err
- return
- }
- error_popup "[mc "Error reading commit topology information;\
- branch and preceding/following tag information\
- will be incomplete."]\n($err)"
- set cacheok 0
+ # got an error reading the list of commits
+ # if we were updating, try rereading the whole thing again
+ if {$allcupdate} {
+ incr allcommits -1
+ dropcache $err
+ return
+ }
+ error_popup "[mc "Error reading commit topology information;\
+ branch and preceding/following tag information\
+ will be incomplete."]\n($err)"
+ set cacheok 0
}
if {[incr allcommits -1] == 0} {
- notbusy allcommits
- if {$cacheok} {
- run savecache
- }
+ notbusy allcommits
+ if {$cacheok} {
+ run savecache
+ }
}
dispneartags 0
return 0
@@ -10353,12 +10371,12 @@ proc recalcarc {a} {
set at {}
set ah {}
foreach id [lrange $arcids($a) 0 end-1] {
- if {[info exists idtags($id)]} {
- lappend at $id
- }
- if {[info exists idheads($id)]} {
- lappend ah $id
- }
+ if {[info exists idtags($id)]} {
+ lappend at $id
+ }
+ if {[info exists idheads($id)]} {
+ lappend ah $id
+ }
}
set arctags($a) $at
set archeads($a) $ah
@@ -10370,22 +10388,22 @@ proc splitarc {p} {
set a $arcnos($p)
if {[llength $a] != 1} {
- puts "oops splitarc called but [llength $a] arcs already"
- return
+ puts "oops splitarc called but [llength $a] arcs already"
+ return
}
set a [lindex $a 0]
set i [lsearch -exact $arcids($a) $p]
if {$i < 0} {
- puts "oops splitarc $p not in arc $a"
- return
+ puts "oops splitarc $p not in arc $a"
+ return
}
set na [incr nextarc]
if {[info exists arcend($a)]} {
- set arcend($na) $arcend($a)
+ set arcend($na) $arcend($a)
} else {
- set l [lindex $allparents([lindex $arcids($a) end]) 0]
- set j [lsearch -exact $arcnos($l) $a]
- set arcnos($l) [lreplace $arcnos($l) $j $j $na]
+ set l [lindex $allparents([lindex $arcids($a) end]) 0]
+ set j [lsearch -exact $arcnos($l) $a]
+ set arcnos($l) [lreplace $arcnos($l) $j $j $na]
}
set tail [lrange $arcids($a) [expr {$i+1}] end]
set arcids($a) [lrange $arcids($a) 0 $i]
@@ -10394,26 +10412,26 @@ proc splitarc {p} {
set arcout($p) $na
set arcids($na) $tail
if {[info exists growing($a)]} {
- set growing($na) 1
- unset growing($a)
+ set growing($na) 1
+ unset growing($a)
}
foreach id $tail {
- if {[llength $arcnos($id)] == 1} {
- set arcnos($id) $na
- } else {
- set j [lsearch -exact $arcnos($id) $a]
- set arcnos($id) [lreplace $arcnos($id) $j $j $na]
- }
+ if {[llength $arcnos($id)] == 1} {
+ set arcnos($id) $na
+ } else {
+ set j [lsearch -exact $arcnos($id) $a]
+ set arcnos($id) [lreplace $arcnos($id) $j $j $na]
+ }
}
# reconstruct tags and heads lists
if {$arctags($a) ne {} || $archeads($a) ne {}} {
- recalcarc $a
- recalcarc $na
+ recalcarc $a
+ recalcarc $na
} else {
- set arctags($na) {}
- set archeads($na) {}
+ set arctags($na) {}
+ set archeads($na) {}
}
}
@@ -10437,7 +10455,7 @@ proc addnewchild {id p} {
set arcids($a) [list $p]
set arcend($a) $p
if {![info exists arcout($p)]} {
- splitarc $p
+ splitarc $p
}
lappend arcnos($p) $a
set arcout($id) [list $a]
@@ -10454,78 +10472,78 @@ proc readcache {f} {
set a $nextarc
set lim $cachedarcs
if {$lim - $a > 500} {
- set lim [expr {$a + 500}]
+ set lim [expr {$a + 500}]
}
if {[catch {
- if {$a == $lim} {
- # finish reading the cache and setting up arctags, etc.
- set line [gets $f]
- if {$line ne "1"} {error "bad final version"}
- close $f
- foreach id [array names idtags] {
- if {[info exists arcnos($id)] && [llength $arcnos($id)] == 1 &&
- [llength $allparents($id)] == 1} {
- set a [lindex $arcnos($id) 0]
- if {$arctags($a) eq {}} {
- recalcarc $a
- }
- }
- }
- foreach id [array names idheads] {
- if {[info exists arcnos($id)] && [llength $arcnos($id)] == 1 &&
- [llength $allparents($id)] == 1} {
- set a [lindex $arcnos($id) 0]
- if {$archeads($a) eq {}} {
- recalcarc $a
- }
- }
- }
- foreach id [lsort -unique $possible_seeds] {
- if {$arcnos($id) eq {}} {
- lappend seeds $id
- }
- }
- set allcwait 0
- } else {
- while {[incr a] <= $lim} {
- set line [gets $f]
- if {[llength $line] != 3} {error "bad line"}
- set s [lindex $line 0]
- set arcstart($a) $s
- lappend arcout($s) $a
- if {![info exists arcnos($s)]} {
- lappend possible_seeds $s
- set arcnos($s) {}
- }
- set e [lindex $line 1]
- if {$e eq {}} {
- set growing($a) 1
- } else {
- set arcend($a) $e
- if {![info exists arcout($e)]} {
- set arcout($e) {}
- }
- }
- set arcids($a) [lindex $line 2]
- foreach id $arcids($a) {
- lappend allparents($s) $id
- set s $id
- lappend arcnos($id) $a
- }
- if {![info exists allparents($s)]} {
- set allparents($s) {}
- }
- set arctags($a) {}
- set archeads($a) {}
- }
- set nextarc [expr {$a - 1}]
- }
+ if {$a == $lim} {
+ # finish reading the cache and setting up arctags, etc.
+ set line [gets $f]
+ if {$line ne "1"} {error "bad final version"}
+ close $f
+ foreach id [array names idtags] {
+ if {[info exists arcnos($id)] && [llength $arcnos($id)] == 1 &&
+ [llength $allparents($id)] == 1} {
+ set a [lindex $arcnos($id) 0]
+ if {$arctags($a) eq {}} {
+ recalcarc $a
+ }
+ }
+ }
+ foreach id [array names idheads] {
+ if {[info exists arcnos($id)] && [llength $arcnos($id)] == 1 &&
+ [llength $allparents($id)] == 1} {
+ set a [lindex $arcnos($id) 0]
+ if {$archeads($a) eq {}} {
+ recalcarc $a
+ }
+ }
+ }
+ foreach id [lsort -unique $possible_seeds] {
+ if {$arcnos($id) eq {}} {
+ lappend seeds $id
+ }
+ }
+ set allcwait 0
+ } else {
+ while {[incr a] <= $lim} {
+ set line [gets $f]
+ if {[llength $line] != 3} {error "bad line"}
+ set s [lindex $line 0]
+ set arcstart($a) $s
+ lappend arcout($s) $a
+ if {![info exists arcnos($s)]} {
+ lappend possible_seeds $s
+ set arcnos($s) {}
+ }
+ set e [lindex $line 1]
+ if {$e eq {}} {
+ set growing($a) 1
+ } else {
+ set arcend($a) $e
+ if {![info exists arcout($e)]} {
+ set arcout($e) {}
+ }
+ }
+ set arcids($a) [lindex $line 2]
+ foreach id $arcids($a) {
+ lappend allparents($s) $id
+ set s $id
+ lappend arcnos($id) $a
+ }
+ if {![info exists allparents($s)]} {
+ set allparents($s) {}
+ }
+ set arctags($a) {}
+ set archeads($a) {}
+ }
+ set nextarc [expr {$a - 1}]
+ }
} err]} {
- dropcache $err
- return 0
+ dropcache $err
+ return 0
}
if {!$allcwait} {
- getallcommits
+ getallcommits
}
return $allcwait
}
@@ -10534,16 +10552,16 @@ proc getcache {f} {
global nextarc cachedarcs possible_seeds
if {[catch {
- set line [gets $f]
- if {[llength $line] != 2 || [lindex $line 0] ne "1"} {error "bad version"}
- # make sure it's an integer
- set cachedarcs [expr {int([lindex $line 1])}]
- if {$cachedarcs < 0} {error "bad number of arcs"}
- set nextarc 0
- set possible_seeds {}
- run readcache $f
+ set line [gets $f]
+ if {[llength $line] != 2 || [lindex $line 0] ne "1"} {error "bad version"}
+ # make sure it's an integer
+ set cachedarcs [expr {int([lindex $line 1])}]
+ if {$cachedarcs < 0} {error "bad number of arcs"}
+ set nextarc 0
+ set possible_seeds {}
+ run readcache $f
} err]} {
- dropcache $err
+ dropcache $err
}
return 0
}
@@ -10553,9 +10571,9 @@ proc dropcache {err} {
#puts "dropping cache ($err)"
foreach v {arcnos arcout arcids arcstart arcend growing \
- arctags archeads allparents allchildren} {
- global $v
- unset -nocomplain $v
+ arctags archeads allparents allchildren} {
+ global $v
+ unset -nocomplain $v
}
set allcwait 0
set nextarc 0
@@ -10571,27 +10589,27 @@ proc writecache {f} {
set a $cachearc
set lim $cachedarcs
if {$lim - $a > 1000} {
- set lim [expr {$a + 1000}]
+ set lim [expr {$a + 1000}]
}
if {[catch {
- while {[incr a] <= $lim} {
- if {[info exists arcend($a)]} {
- puts $f [list $arcstart($a) $arcend($a) $arcids($a)]
- } else {
- puts $f [list $arcstart($a) {} $arcids($a)]
- }
- }
+ while {[incr a] <= $lim} {
+ if {[info exists arcend($a)]} {
+ puts $f [list $arcstart($a) $arcend($a) $arcids($a)]
+ } else {
+ puts $f [list $arcstart($a) {} $arcids($a)]
+ }
+ }
} err]} {
- catch {close $f}
- catch {file delete $allccache}
- #puts "writing cache failed ($err)"
- return 0
+ catch {close $f}
+ catch {file delete $allccache}
+ #puts "writing cache failed ($err)"
+ return 0
}
set cachearc [expr {$a - 1}]
if {$a > $cachedarcs} {
- puts $f "1"
- close $f
- return 0
+ puts $f "1"
+ close $f
+ return 0
}
return 1
}
@@ -10603,9 +10621,9 @@ proc savecache {} {
set cachearc 0
set cachedarcs $nextarc
catch {
- set f [open $allccache w]
- puts $f [list 1 $cachedarcs]
- run writecache $f
+ set f [open $allccache w]
+ puts $f [list 1 $cachedarcs]
+ run writecache $f
}
}
@@ -10615,92 +10633,92 @@ proc anc_or_desc {a b} {
global arcout arcstart arcend arcnos cached_isanc
if {$arcnos($a) eq $arcnos($b)} {
- # Both are on the same arc(s); either both are the same BMP,
- # or if one is not a BMP, the other is also not a BMP or is
- # the BMP at end of the arc (and it only has 1 incoming arc).
- # Or both can be BMPs with no incoming arcs.
- if {$a eq $b || $arcnos($a) eq {}} {
- return 0
- }
- # assert {[llength $arcnos($a)] == 1}
- set arc [lindex $arcnos($a) 0]
- set i [lsearch -exact $arcids($arc) $a]
- set j [lsearch -exact $arcids($arc) $b]
- if {$i < 0 || $i > $j} {
- return 1
- } else {
- return -1
- }
+ # Both are on the same arc(s); either both are the same BMP,
+ # or if one is not a BMP, the other is also not a BMP or is
+ # the BMP at end of the arc (and it only has 1 incoming arc).
+ # Or both can be BMPs with no incoming arcs.
+ if {$a eq $b || $arcnos($a) eq {}} {
+ return 0
+ }
+ # assert {[llength $arcnos($a)] == 1}
+ set arc [lindex $arcnos($a) 0]
+ set i [lsearch -exact $arcids($arc) $a]
+ set j [lsearch -exact $arcids($arc) $b]
+ if {$i < 0 || $i > $j} {
+ return 1
+ } else {
+ return -1
+ }
}
if {![info exists arcout($a)]} {
- set arc [lindex $arcnos($a) 0]
- if {[info exists arcend($arc)]} {
- set aend $arcend($arc)
- } else {
- set aend {}
- }
- set a $arcstart($arc)
+ set arc [lindex $arcnos($a) 0]
+ if {[info exists arcend($arc)]} {
+ set aend $arcend($arc)
+ } else {
+ set aend {}
+ }
+ set a $arcstart($arc)
} else {
- set aend $a
+ set aend $a
}
if {![info exists arcout($b)]} {
- set arc [lindex $arcnos($b) 0]
- if {[info exists arcend($arc)]} {
- set bend $arcend($arc)
- } else {
- set bend {}
- }
- set b $arcstart($arc)
+ set arc [lindex $arcnos($b) 0]
+ if {[info exists arcend($arc)]} {
+ set bend $arcend($arc)
+ } else {
+ set bend {}
+ }
+ set b $arcstart($arc)
} else {
- set bend $b
+ set bend $b
}
if {$a eq $bend} {
- return 1
+ return 1
}
if {$b eq $aend} {
- return -1
+ return -1
}
if {[info exists cached_isanc($a,$bend)]} {
- if {$cached_isanc($a,$bend)} {
- return 1
- }
+ if {$cached_isanc($a,$bend)} {
+ return 1
+ }
}
if {[info exists cached_isanc($b,$aend)]} {
- if {$cached_isanc($b,$aend)} {
- return -1
- }
- if {[info exists cached_isanc($a,$bend)]} {
- return 0
- }
+ if {$cached_isanc($b,$aend)} {
+ return -1
+ }
+ if {[info exists cached_isanc($a,$bend)]} {
+ return 0
+ }
}
set todo [list $a $b]
set anc($a) a
set anc($b) b
for {set i 0} {$i < [llength $todo]} {incr i} {
- set x [lindex $todo $i]
- if {$anc($x) eq {}} {
- continue
- }
- foreach arc $arcnos($x) {
- set xd $arcstart($arc)
- if {$xd eq $bend} {
- set cached_isanc($a,$bend) 1
- set cached_isanc($b,$aend) 0
- return 1
- } elseif {$xd eq $aend} {
- set cached_isanc($b,$aend) 1
- set cached_isanc($a,$bend) 0
- return -1
- }
- if {![info exists anc($xd)]} {
- set anc($xd) $anc($x)
- lappend todo $xd
- } elseif {$anc($xd) ne $anc($x)} {
- set anc($xd) {}
- }
- }
+ set x [lindex $todo $i]
+ if {$anc($x) eq {}} {
+ continue
+ }
+ foreach arc $arcnos($x) {
+ set xd $arcstart($arc)
+ if {$xd eq $bend} {
+ set cached_isanc($a,$bend) 1
+ set cached_isanc($b,$aend) 0
+ return 1
+ } elseif {$xd eq $aend} {
+ set cached_isanc($b,$aend) 1
+ set cached_isanc($a,$bend) 0
+ return -1
+ }
+ if {![info exists anc($xd)]} {
+ set anc($xd) $anc($x)
+ lappend todo $xd
+ } elseif {$anc($xd) ne $anc($x)} {
+ set anc($xd) {}
+ }
+ }
}
set cached_isanc($a,$bend) 0
set cached_isanc($b,$aend) 0
@@ -10723,90 +10741,90 @@ proc is_certain {desc anc} {
set certain {}
if {[llength $arcnos($anc)] == 1} {
- # tags on the same arc are certain
- if {$arcnos($desc) eq $arcnos($anc)} {
- return 1
- }
- if {![info exists arcout($anc)]} {
- # if $anc is partway along an arc, use the start of the arc instead
- set a [lindex $arcnos($anc) 0]
- set anc $arcstart($a)
- }
+ # tags on the same arc are certain
+ if {$arcnos($desc) eq $arcnos($anc)} {
+ return 1
+ }
+ if {![info exists arcout($anc)]} {
+ # if $anc is partway along an arc, use the start of the arc instead
+ set a [lindex $arcnos($anc) 0]
+ set anc $arcstart($a)
+ }
}
if {[llength $arcnos($desc)] > 1 || [info exists arcout($desc)]} {
- set x $desc
+ set x $desc
} else {
- set a [lindex $arcnos($desc) 0]
- set x $arcend($a)
+ set a [lindex $arcnos($desc) 0]
+ set x $arcend($a)
}
if {$x == $anc} {
- return 1
+ return 1
}
set anclist [list $x]
set dl($x) 1
set nnh 1
set ngrowanc 0
for {set i 0} {$i < [llength $anclist] && ($nnh > 0 || $ngrowanc > 0)} {incr i} {
- set x [lindex $anclist $i]
- if {$dl($x)} {
- incr nnh -1
- }
- set done($x) 1
- foreach a $arcout($x) {
- if {[info exists growing($a)]} {
- if {![info exists growanc($x)] && $dl($x)} {
- set growanc($x) 1
- incr ngrowanc
- }
- } else {
- set y $arcend($a)
- if {[info exists dl($y)]} {
- if {$dl($y)} {
- if {!$dl($x)} {
- set dl($y) 0
- if {![info exists done($y)]} {
- incr nnh -1
- }
- if {[info exists growanc($x)]} {
- incr ngrowanc -1
- }
- set xl [list $y]
- for {set k 0} {$k < [llength $xl]} {incr k} {
- set z [lindex $xl $k]
- foreach c $arcout($z) {
- if {[info exists arcend($c)]} {
- set v $arcend($c)
- if {[info exists dl($v)] && $dl($v)} {
- set dl($v) 0
- if {![info exists done($v)]} {
- incr nnh -1
- }
- if {[info exists growanc($v)]} {
- incr ngrowanc -1
- }
- lappend xl $v
- }
- }
- }
- }
- }
- }
- } elseif {$y eq $anc || !$dl($x)} {
- set dl($y) 0
- lappend anclist $y
- } else {
- set dl($y) 1
- lappend anclist $y
- incr nnh
- }
- }
- }
+ set x [lindex $anclist $i]
+ if {$dl($x)} {
+ incr nnh -1
+ }
+ set done($x) 1
+ foreach a $arcout($x) {
+ if {[info exists growing($a)]} {
+ if {![info exists growanc($x)] && $dl($x)} {
+ set growanc($x) 1
+ incr ngrowanc
+ }
+ } else {
+ set y $arcend($a)
+ if {[info exists dl($y)]} {
+ if {$dl($y)} {
+ if {!$dl($x)} {
+ set dl($y) 0
+ if {![info exists done($y)]} {
+ incr nnh -1
+ }
+ if {[info exists growanc($x)]} {
+ incr ngrowanc -1
+ }
+ set xl [list $y]
+ for {set k 0} {$k < [llength $xl]} {incr k} {
+ set z [lindex $xl $k]
+ foreach c $arcout($z) {
+ if {[info exists arcend($c)]} {
+ set v $arcend($c)
+ if {[info exists dl($v)] && $dl($v)} {
+ set dl($v) 0
+ if {![info exists done($v)]} {
+ incr nnh -1
+ }
+ if {[info exists growanc($v)]} {
+ incr ngrowanc -1
+ }
+ lappend xl $v
+ }
+ }
+ }
+ }
+ }
+ }
+ } elseif {$y eq $anc || !$dl($x)} {
+ set dl($y) 0
+ lappend anclist $y
+ } else {
+ set dl($y) 1
+ lappend anclist $y
+ incr nnh
+ }
+ }
+ }
}
foreach x [array names growanc] {
- if {$dl($x)} {
- return 0
- }
- return 0
+ if {$dl($x)} {
+ return 0
+ }
+ return 0
}
return 1
}
@@ -10817,11 +10835,11 @@ proc validate_arctags {a} {
set i -1
set na $arctags($a)
foreach id $arctags($a) {
- incr i
- if {![info exists idtags($id)]} {
- set na [lreplace $na $i $i]
- incr i -1
- }
+ incr i
+ if {![info exists idtags($id)]} {
+ set na [lreplace $na $i $i]
+ incr i -1
+ }
}
set arctags($a) $na
}
@@ -10832,11 +10850,11 @@ proc validate_archeads {a} {
set i -1
set na $archeads($a)
foreach id $archeads($a) {
- incr i
- if {![info exists idheads($id)]} {
- set na [lreplace $na $i $i]
- incr i -1
- }
+ incr i
+ if {![info exists idheads($id)]} {
+ set na [lreplace $na $i $i]
+ incr i -1
+ }
}
set archeads($a) $na
}
@@ -10848,33 +10866,33 @@ proc desctags {id} {
global growing cached_dtags
if {![info exists allparents($id)]} {
- return {}
+ return {}
}
set t1 [clock clicks -milliseconds]
set argid $id
if {[llength $arcnos($id)] == 1 && [llength $allparents($id)] == 1} {
- # part-way along an arc; check that arc first
- set a [lindex $arcnos($id) 0]
- if {$arctags($a) ne {}} {
- validate_arctags $a
- set i [lsearch -exact $arcids($a) $id]
- set tid {}
- foreach t $arctags($a) {
- set j [lsearch -exact $arcids($a) $t]
- if {$j >= $i} break
- set tid $t
- }
- if {$tid ne {}} {
- return $tid
- }
- }
- set id $arcstart($a)
- if {[info exists idtags($id)]} {
- return $id
- }
+ # part-way along an arc; check that arc first
+ set a [lindex $arcnos($id) 0]
+ if {$arctags($a) ne {}} {
+ validate_arctags $a
+ set i [lsearch -exact $arcids($a) $id]
+ set tid {}
+ foreach t $arctags($a) {
+ set j [lsearch -exact $arcids($a) $t]
+ if {$j >= $i} break
+ set tid $t
+ }
+ if {$tid ne {}} {
+ return $tid
+ }
+ }
+ set id $arcstart($a)
+ if {[info exists idtags($id)]} {
+ return $id
+ }
}
if {[info exists cached_dtags($id)]} {
- return $cached_dtags($id)
+ return $cached_dtags($id)
}
set origid $id
@@ -10882,111 +10900,111 @@ proc desctags {id} {
set queued($id) 1
set nc 1
for {set i 0} {$i < [llength $todo] && $nc > 0} {incr i} {
- set id [lindex $todo $i]
- set done($id) 1
- set ta [info exists hastaggedancestor($id)]
- if {!$ta} {
- incr nc -1
- }
- # ignore tags on starting node
- if {!$ta && $i > 0} {
- if {[info exists idtags($id)]} {
- set tagloc($id) $id
- set ta 1
- } elseif {[info exists cached_dtags($id)]} {
- set tagloc($id) $cached_dtags($id)
- set ta 1
- }
- }
- foreach a $arcnos($id) {
- set d $arcstart($a)
- if {!$ta && $arctags($a) ne {}} {
- validate_arctags $a
- if {$arctags($a) ne {}} {
- lappend tagloc($id) [lindex $arctags($a) end]
- }
- }
- if {$ta || $arctags($a) ne {}} {
- set tomark [list $d]
- for {set j 0} {$j < [llength $tomark]} {incr j} {
- set dd [lindex $tomark $j]
- if {![info exists hastaggedancestor($dd)]} {
- if {[info exists done($dd)]} {
- foreach b $arcnos($dd) {
- lappend tomark $arcstart($b)
- }
- if {[info exists tagloc($dd)]} {
- unset tagloc($dd)
- }
- } elseif {[info exists queued($dd)]} {
- incr nc -1
- }
- set hastaggedancestor($dd) 1
- }
- }
- }
- if {![info exists queued($d)]} {
- lappend todo $d
- set queued($d) 1
- if {![info exists hastaggedancestor($d)]} {
- incr nc
- }
- }
- }
+ set id [lindex $todo $i]
+ set done($id) 1
+ set ta [info exists hastaggedancestor($id)]
+ if {!$ta} {
+ incr nc -1
+ }
+ # ignore tags on starting node
+ if {!$ta && $i > 0} {
+ if {[info exists idtags($id)]} {
+ set tagloc($id) $id
+ set ta 1
+ } elseif {[info exists cached_dtags($id)]} {
+ set tagloc($id) $cached_dtags($id)
+ set ta 1
+ }
+ }
+ foreach a $arcnos($id) {
+ set d $arcstart($a)
+ if {!$ta && $arctags($a) ne {}} {
+ validate_arctags $a
+ if {$arctags($a) ne {}} {
+ lappend tagloc($id) [lindex $arctags($a) end]
+ }
+ }
+ if {$ta || $arctags($a) ne {}} {
+ set tomark [list $d]
+ for {set j 0} {$j < [llength $tomark]} {incr j} {
+ set dd [lindex $tomark $j]
+ if {![info exists hastaggedancestor($dd)]} {
+ if {[info exists done($dd)]} {
+ foreach b $arcnos($dd) {
+ lappend tomark $arcstart($b)
+ }
+ if {[info exists tagloc($dd)]} {
+ unset tagloc($dd)
+ }
+ } elseif {[info exists queued($dd)]} {
+ incr nc -1
+ }
+ set hastaggedancestor($dd) 1
+ }
+ }
+ }
+ if {![info exists queued($d)]} {
+ lappend todo $d
+ set queued($d) 1
+ if {![info exists hastaggedancestor($d)]} {
+ incr nc
+ }
+ }
+ }
}
set tags {}
foreach id [array names tagloc] {
- if {![info exists hastaggedancestor($id)]} {
- foreach t $tagloc($id) {
- if {[lsearch -exact $tags $t] < 0} {
- lappend tags $t
- }
- }
- }
+ if {![info exists hastaggedancestor($id)]} {
+ foreach t $tagloc($id) {
+ if {[lsearch -exact $tags $t] < 0} {
+ lappend tags $t
+ }
+ }
+ }
}
set t2 [clock clicks -milliseconds]
set loopix $i
# remove tags that are descendents of other tags
for {set i 0} {$i < [llength $tags]} {incr i} {
- set a [lindex $tags $i]
- for {set j 0} {$j < $i} {incr j} {
- set b [lindex $tags $j]
- set r [anc_or_desc $a $b]
- if {$r == 1} {
- set tags [lreplace $tags $j $j]
- incr j -1
- incr i -1
- } elseif {$r == -1} {
- set tags [lreplace $tags $i $i]
- incr i -1
- break
- }
- }
+ set a [lindex $tags $i]
+ for {set j 0} {$j < $i} {incr j} {
+ set b [lindex $tags $j]
+ set r [anc_or_desc $a $b]
+ if {$r == 1} {
+ set tags [lreplace $tags $j $j]
+ incr j -1
+ incr i -1
+ } elseif {$r == -1} {
+ set tags [lreplace $tags $i $i]
+ incr i -1
+ break
+ }
+ }
}
if {[array names growing] ne {}} {
- # graph isn't finished, need to check if any tag could get
- # eclipsed by another tag coming later. Simply ignore any
- # tags that could later get eclipsed.
- set ctags {}
- foreach t $tags {
- if {[is_certain $t $origid]} {
- lappend ctags $t
- }
- }
- if {$tags eq $ctags} {
- set cached_dtags($origid) $tags
- } else {
- set tags $ctags
- }
+ # graph isn't finished, need to check if any tag could get
+ # eclipsed by another tag coming later. Simply ignore any
+ # tags that could later get eclipsed.
+ set ctags {}
+ foreach t $tags {
+ if {[is_certain $t $origid]} {
+ lappend ctags $t
+ }
+ }
+ if {$tags eq $ctags} {
+ set cached_dtags($origid) $tags
+ } else {
+ set tags $ctags
+ }
} else {
- set cached_dtags($origid) $tags
+ set cached_dtags($origid) $tags
}
set t3 [clock clicks -milliseconds]
if {0 && $t3 - $t1 >= 100} {
- puts "iterating descendents ($loopix/[llength $todo] nodes) took\
- [expr {$t2-$t1}]+[expr {$t3-$t2}]ms, $nc candidates left"
+ puts "iterating descendents ($loopix/[llength $todo] nodes) took\
+ [expr {$t2-$t1}]+[expr {$t3-$t2}]ms, $nc candidates left"
}
return $tags
}
@@ -10996,33 +11014,33 @@ proc anctags {id} {
global growing cached_atags
if {![info exists allparents($id)]} {
- return {}
+ return {}
}
set t1 [clock clicks -milliseconds]
set argid $id
if {[llength $arcnos($id)] == 1 && [llength $allparents($id)] == 1} {
- # part-way along an arc; check that arc first
- set a [lindex $arcnos($id) 0]
- if {$arctags($a) ne {}} {
- validate_arctags $a
- set i [lsearch -exact $arcids($a) $id]
- foreach t $arctags($a) {
- set j [lsearch -exact $arcids($a) $t]
- if {$j > $i} {
- return $t
- }
- }
- }
- if {![info exists arcend($a)]} {
- return {}
- }
- set id $arcend($a)
- if {[info exists idtags($id)]} {
- return $id
- }
+ # part-way along an arc; check that arc first
+ set a [lindex $arcnos($id) 0]
+ if {$arctags($a) ne {}} {
+ validate_arctags $a
+ set i [lsearch -exact $arcids($a) $id]
+ foreach t $arctags($a) {
+ set j [lsearch -exact $arcids($a) $t]
+ if {$j > $i} {
+ return $t
+ }
+ }
+ }
+ if {![info exists arcend($a)]} {
+ return {}
+ }
+ set id $arcend($a)
+ if {[info exists idtags($id)]} {
+ return $id
+ }
}
if {[info exists cached_atags($id)]} {
- return $cached_atags($id)
+ return $cached_atags($id)
}
set origid $id
@@ -11031,114 +11049,114 @@ proc anctags {id} {
set taglist {}
set nc 1
for {set i 0} {$i < [llength $todo] && $nc > 0} {incr i} {
- set id [lindex $todo $i]
- set done($id) 1
- set td [info exists hastaggeddescendent($id)]
- if {!$td} {
- incr nc -1
- }
- # ignore tags on starting node
- if {!$td && $i > 0} {
- if {[info exists idtags($id)]} {
- set tagloc($id) $id
- set td 1
- } elseif {[info exists cached_atags($id)]} {
- set tagloc($id) $cached_atags($id)
- set td 1
- }
- }
- foreach a $arcout($id) {
- if {!$td && $arctags($a) ne {}} {
- validate_arctags $a
- if {$arctags($a) ne {}} {
- lappend tagloc($id) [lindex $arctags($a) 0]
- }
- }
- if {![info exists arcend($a)]} continue
- set d $arcend($a)
- if {$td || $arctags($a) ne {}} {
- set tomark [list $d]
- for {set j 0} {$j < [llength $tomark]} {incr j} {
- set dd [lindex $tomark $j]
- if {![info exists hastaggeddescendent($dd)]} {
- if {[info exists done($dd)]} {
- foreach b $arcout($dd) {
- if {[info exists arcend($b)]} {
- lappend tomark $arcend($b)
- }
- }
- if {[info exists tagloc($dd)]} {
- unset tagloc($dd)
- }
- } elseif {[info exists queued($dd)]} {
- incr nc -1
- }
- set hastaggeddescendent($dd) 1
- }
- }
- }
- if {![info exists queued($d)]} {
- lappend todo $d
- set queued($d) 1
- if {![info exists hastaggeddescendent($d)]} {
- incr nc
- }
- }
- }
+ set id [lindex $todo $i]
+ set done($id) 1
+ set td [info exists hastaggeddescendent($id)]
+ if {!$td} {
+ incr nc -1
+ }
+ # ignore tags on starting node
+ if {!$td && $i > 0} {
+ if {[info exists idtags($id)]} {
+ set tagloc($id) $id
+ set td 1
+ } elseif {[info exists cached_atags($id)]} {
+ set tagloc($id) $cached_atags($id)
+ set td 1
+ }
+ }
+ foreach a $arcout($id) {
+ if {!$td && $arctags($a) ne {}} {
+ validate_arctags $a
+ if {$arctags($a) ne {}} {
+ lappend tagloc($id) [lindex $arctags($a) 0]
+ }
+ }
+ if {![info exists arcend($a)]} continue
+ set d $arcend($a)
+ if {$td || $arctags($a) ne {}} {
+ set tomark [list $d]
+ for {set j 0} {$j < [llength $tomark]} {incr j} {
+ set dd [lindex $tomark $j]
+ if {![info exists hastaggeddescendent($dd)]} {
+ if {[info exists done($dd)]} {
+ foreach b $arcout($dd) {
+ if {[info exists arcend($b)]} {
+ lappend tomark $arcend($b)
+ }
+ }
+ if {[info exists tagloc($dd)]} {
+ unset tagloc($dd)
+ }
+ } elseif {[info exists queued($dd)]} {
+ incr nc -1
+ }
+ set hastaggeddescendent($dd) 1
+ }
+ }
+ }
+ if {![info exists queued($d)]} {
+ lappend todo $d
+ set queued($d) 1
+ if {![info exists hastaggeddescendent($d)]} {
+ incr nc
+ }
+ }
+ }
}
set t2 [clock clicks -milliseconds]
set loopix $i
set tags {}
foreach id [array names tagloc] {
- if {![info exists hastaggeddescendent($id)]} {
- foreach t $tagloc($id) {
- if {[lsearch -exact $tags $t] < 0} {
- lappend tags $t
- }
- }
- }
+ if {![info exists hastaggeddescendent($id)]} {
+ foreach t $tagloc($id) {
+ if {[lsearch -exact $tags $t] < 0} {
+ lappend tags $t
+ }
+ }
+ }
}
# remove tags that are ancestors of other tags
for {set i 0} {$i < [llength $tags]} {incr i} {
- set a [lindex $tags $i]
- for {set j 0} {$j < $i} {incr j} {
- set b [lindex $tags $j]
- set r [anc_or_desc $a $b]
- if {$r == -1} {
- set tags [lreplace $tags $j $j]
- incr j -1
- incr i -1
- } elseif {$r == 1} {
- set tags [lreplace $tags $i $i]
- incr i -1
- break
- }
- }
+ set a [lindex $tags $i]
+ for {set j 0} {$j < $i} {incr j} {
+ set b [lindex $tags $j]
+ set r [anc_or_desc $a $b]
+ if {$r == -1} {
+ set tags [lreplace $tags $j $j]
+ incr j -1
+ incr i -1
+ } elseif {$r == 1} {
+ set tags [lreplace $tags $i $i]
+ incr i -1
+ break
+ }
+ }
}
if {[array names growing] ne {}} {
- # graph isn't finished, need to check if any tag could get
- # eclipsed by another tag coming later. Simply ignore any
- # tags that could later get eclipsed.
- set ctags {}
- foreach t $tags {
- if {[is_certain $origid $t]} {
- lappend ctags $t
- }
- }
- if {$tags eq $ctags} {
- set cached_atags($origid) $tags
- } else {
- set tags $ctags
- }
+ # graph isn't finished, need to check if any tag could get
+ # eclipsed by another tag coming later. Simply ignore any
+ # tags that could later get eclipsed.
+ set ctags {}
+ foreach t $tags {
+ if {[is_certain $origid $t]} {
+ lappend ctags $t
+ }
+ }
+ if {$tags eq $ctags} {
+ set cached_atags($origid) $tags
+ } else {
+ set tags $ctags
+ }
} else {
- set cached_atags($origid) $tags
+ set cached_atags($origid) $tags
}
set t3 [clock clicks -milliseconds]
if {0 && $t3 - $t1 >= 100} {
- puts "iterating ancestors ($loopix/[llength $todo] nodes) took\
- [expr {$t2-$t1}]+[expr {$t3-$t2}]ms, $nc candidates left"
+ puts "iterating ancestors ($loopix/[llength $todo] nodes) took\
+ [expr {$t2-$t1}]+[expr {$t3-$t2}]ms, $nc candidates left"
}
return $tags
}
@@ -11150,49 +11168,49 @@ proc descheads {id} {
global allparents arcout
if {![info exists allparents($id)]} {
- return {}
+ return {}
}
set aret {}
if {![info exists arcout($id)]} {
- # part-way along an arc; check it first
- set a [lindex $arcnos($id) 0]
- if {$archeads($a) ne {}} {
- validate_archeads $a
- set i [lsearch -exact $arcids($a) $id]
- foreach t $archeads($a) {
- set j [lsearch -exact $arcids($a) $t]
- if {$j > $i} break
- lappend aret $t
- }
- }
- set id $arcstart($a)
+ # part-way along an arc; check it first
+ set a [lindex $arcnos($id) 0]
+ if {$archeads($a) ne {}} {
+ validate_archeads $a
+ set i [lsearch -exact $arcids($a) $id]
+ foreach t $archeads($a) {
+ set j [lsearch -exact $arcids($a) $t]
+ if {$j > $i} break
+ lappend aret $t
+ }
+ }
+ set id $arcstart($a)
}
set origid $id
set todo [list $id]
set seen($id) 1
set ret {}
for {set i 0} {$i < [llength $todo]} {incr i} {
- set id [lindex $todo $i]
- if {[info exists cached_dheads($id)]} {
- set ret [concat $ret $cached_dheads($id)]
- } else {
- if {[info exists idheads($id)]} {
- lappend ret $id
- }
- foreach a $arcnos($id) {
- if {$archeads($a) ne {}} {
- validate_archeads $a
- if {$archeads($a) ne {}} {
- set ret [concat $ret $archeads($a)]
- }
- }
- set d $arcstart($a)
- if {![info exists seen($d)]} {
- lappend todo $d
- set seen($d) 1
- }
- }
- }
+ set id [lindex $todo $i]
+ if {[info exists cached_dheads($id)]} {
+ set ret [concat $ret $cached_dheads($id)]
+ } else {
+ if {[info exists idheads($id)]} {
+ lappend ret $id
+ }
+ foreach a $arcnos($id) {
+ if {$archeads($a) ne {}} {
+ validate_archeads $a
+ if {$archeads($a) ne {}} {
+ set ret [concat $ret $archeads($a)]
+ }
+ }
+ set d $arcstart($a)
+ if {![info exists seen($d)]} {
+ lappend todo $d
+ set seen($d) 1
+ }
+ }
+ }
}
set ret [lsort -unique $ret]
set cached_dheads($origid) $ret
@@ -11204,7 +11222,7 @@ proc addedtag {id} {
if {![info exists arcnos($id)]} return
if {![info exists arcout($id)]} {
- recalcarc [lindex $arcnos($id) 0]
+ recalcarc [lindex $arcnos($id) 0]
}
unset -nocomplain cached_dtags
unset -nocomplain cached_atags
@@ -11215,7 +11233,7 @@ proc addedhead {hid head} {
if {![info exists arcnos($hid)]} return
if {![info exists arcout($hid)]} {
- recalcarc [lindex $arcnos($hid) 0]
+ recalcarc [lindex $arcnos($hid) 0]
}
unset -nocomplain cached_dheads
}
@@ -11231,7 +11249,7 @@ proc movedhead {hid head} {
if {![info exists arcnos($hid)]} return
if {![info exists arcout($hid)]} {
- recalcarc [lindex $arcnos($hid) 0]
+ recalcarc [lindex $arcnos($hid) 0]
}
unset -nocomplain cached_dheads
}
@@ -11241,13 +11259,13 @@ proc changedrefs {} {
global arctags archeads arcnos arcout idheads idtags
foreach id [concat [array names idheads] [array names idtags]] {
- if {[info exists arcnos($id)] && ![info exists arcout($id)]} {
- set a [lindex $arcnos($id) 0]
- if {![info exists donearc($a)]} {
- recalcarc $a
- set donearc($a) 1
- }
- }
+ if {[info exists arcnos($id)] && ![info exists arcout($id)]} {
+ set a [lindex $arcnos($id) 0]
+ if {![info exists donearc($a)]} {
+ recalcarc $a
+ set donearc($a) 1
+ }
+ }
}
unset -nocomplain cached_tagcontent
unset -nocomplain cached_dtags
@@ -11259,26 +11277,26 @@ proc rereadrefs {} {
global idtags idheads idotherrefs mainheadid
set refids [concat [array names idtags] \
- [array names idheads] [array names idotherrefs]]
+ [array names idheads] [array names idotherrefs]]
foreach id $refids {
- if {![info exists ref($id)]} {
- set ref($id) [listrefs $id]
- }
+ if {![info exists ref($id)]} {
+ set ref($id) [listrefs $id]
+ }
}
set oldmainhead $mainheadid
readrefs
changedrefs
set refids [lsort -unique [concat $refids [array names idtags] \
- [array names idheads] [array names idotherrefs]]]
+ [array names idheads] [array names idotherrefs]]]
foreach id $refids {
- set v [listrefs $id]
- if {![info exists ref($id)] || $ref($id) != $v} {
- redrawtags $id
- }
+ set v [listrefs $id]
+ if {![info exists ref($id)] || $ref($id) != $v} {
+ redrawtags $id
+ }
}
if {$oldmainhead ne $mainheadid} {
- redrawtags $oldmainhead
- redrawtags $mainheadid
+ redrawtags $oldmainhead
+ redrawtags $mainheadid
}
run refill_reflist
}
@@ -11288,15 +11306,15 @@ proc listrefs {id} {
set x {}
if {[info exists idtags($id)]} {
- set x $idtags($id)
+ set x $idtags($id)
}
set y {}
if {[info exists idheads($id)]} {
- set y $idheads($id)
+ set y $idheads($id)
}
set z {}
if {[info exists idotherrefs($id)]} {
- set z $idotherrefs($id)
+ set z $idotherrefs($id)
}
return [list $x $y $z]
}
@@ -11305,15 +11323,15 @@ proc add_tag_ctext {tag} {
global ctext cached_tagcontent tagids
if {![info exists cached_tagcontent($tag)]} {
- catch {
- set cached_tagcontent($tag) [exec git cat-file -p $tag]
- }
+ catch {
+ set cached_tagcontent($tag) [exec git cat-file -p $tag]
+ }
}
$ctext insert end "[mc "Tag"]: $tag\n" bold
if {[info exists cached_tagcontent($tag)]} {
- set text $cached_tagcontent($tag)
+ set text $cached_tagcontent($tag)
} else {
- set text "[mc "Id"]: $tagids($tag)"
+ set text "[mc "Id"]: $tagids($tag)"
}
appendwithlinks $text {}
}
@@ -11322,7 +11340,7 @@ proc showtag {tag isnew} {
global ctext cached_tagcontent tagids linknum tagobjid
if {$isnew} {
- addtohistory [list showtag $tag 0] savectextpos
+ addtohistory [list showtag $tag 0] savectextpos
}
$ctext conf -state normal
clear_ctext
@@ -11338,7 +11356,7 @@ proc showtags {id isnew} {
global idtags ctext linknum
if {$isnew} {
- addtohistory [list showtags $id 0] savectextpos
+ addtohistory [list showtags $id 0] savectextpos
}
$ctext conf -state normal
clear_ctext
@@ -11346,9 +11364,9 @@ proc showtags {id isnew} {
set linknum 0
set sep {}
foreach tag $idtags($id) {
- $ctext insert end $sep
- add_tag_ctext $tag
- set sep "\n\n"
+ $ctext insert end $sep
+ add_tag_ctext $tag
+ set sep "\n\n"
}
maybe_scroll_ctext 1
$ctext conf -state disabled
@@ -11364,7 +11382,7 @@ proc doquit {} {
destroy .
if {[info exists gitktmpdir]} {
- catch {file delete -force $gitktmpdir}
+ catch {file delete -force $gitktmpdir}
}
}
@@ -11373,9 +11391,9 @@ proc mkfontdisp {font top which} {
set fontpref($font) [set $font]
${NS}::button $top.${font}but -text $which \
- -command [list choosefont $font $which]
+ -command [list choosefont $font $which]
${NS}::label $top.$font -relief flat -font $font \
- -text $fontattr($font,family) -justify left
+ -text $fontattr($font,family) -justify left
grid x $top.${font}but $top.$font -sticky w
}
@@ -11392,58 +11410,58 @@ proc choosefont {font which} {
set top .gitkfont
set fonttop $top
if {![winfo exists $top]} {
- font create sample
- eval font config sample [font actual $font]
- ttk_toplevel $top
- make_transient $top $prefstop
- wm title $top [mc "Gitk font chooser"]
- ${NS}::label $top.l -textvariable fontparam(which)
- pack $top.l -side top
- set fontlist [lsort [font families]]
- ${NS}::frame $top.f
- listbox $top.f.fam -listvariable fontlist \
- -yscrollcommand [list $top.f.sb set]
- bind $top.f.fam <<ListboxSelect>> selfontfam
- ${NS}::scrollbar $top.f.sb -command [list $top.f.fam yview]
- pack $top.f.sb -side right -fill y
- pack $top.f.fam -side left -fill both -expand 1
- pack $top.f -side top -fill both -expand 1
- ${NS}::frame $top.g
- spinbox $top.g.size -from 4 -to 40 -width 4 \
- -textvariable fontparam(size) \
- -validatecommand {string is integer -strict %s}
- checkbutton $top.g.bold -padx 5 \
- -font {{Times New Roman} 12 bold} -text [mc "B"] -indicatoron 0 \
- -variable fontparam(weight) -onvalue bold -offvalue normal
- checkbutton $top.g.ital -padx 5 \
- -font {{Times New Roman} 12 italic} -text [mc "I"] -indicatoron 0 \
- -variable fontparam(slant) -onvalue italic -offvalue roman
- pack $top.g.size $top.g.bold $top.g.ital -side left
- pack $top.g -side top
- canvas $top.c -width 150 -height 50 -border 2 -relief sunk \
- -background white
- $top.c create text 100 25 -anchor center -text $which -font sample \
- -fill black -tags text
- bind $top.c <Configure> [list centertext $top.c]
- pack $top.c -side top -fill x
- ${NS}::frame $top.buts
- ${NS}::button $top.buts.ok -text [mc "OK"] -command fontok -default active
- ${NS}::button $top.buts.can -text [mc "Cancel"] -command fontcan -default normal
- bind $top <Key-Return> fontok
- bind $top <Key-Escape> fontcan
- grid $top.buts.ok $top.buts.can
- grid columnconfigure $top.buts 0 -weight 1 -uniform a
- grid columnconfigure $top.buts 1 -weight 1 -uniform a
- pack $top.buts -side bottom -fill x
- trace add variable fontparam write chg_fontparam
+ font create sample
+ eval font config sample [font actual $font]
+ ttk_toplevel $top
+ make_transient $top $prefstop
+ wm title $top [mc "Gitk font chooser"]
+ ${NS}::label $top.l -textvariable fontparam(which)
+ pack $top.l -side top
+ set fontlist [lsort [font families]]
+ ${NS}::frame $top.f
+ listbox $top.f.fam -listvariable fontlist \
+ -yscrollcommand [list $top.f.sb set]
+ bind $top.f.fam <<ListboxSelect>> selfontfam
+ ${NS}::scrollbar $top.f.sb -command [list $top.f.fam yview]
+ pack $top.f.sb -side right -fill y
+ pack $top.f.fam -side left -fill both -expand 1
+ pack $top.f -side top -fill both -expand 1
+ ${NS}::frame $top.g
+ spinbox $top.g.size -from 4 -to 40 -width 4 \
+ -textvariable fontparam(size) \
+ -validatecommand {string is integer -strict %s}
+ checkbutton $top.g.bold -padx 5 \
+ -font {{Times New Roman} 12 bold} -text [mc "B"] -indicatoron 0 \
+ -variable fontparam(weight) -onvalue bold -offvalue normal
+ checkbutton $top.g.ital -padx 5 \
+ -font {{Times New Roman} 12 italic} -text [mc "I"] -indicatoron 0 \
+ -variable fontparam(slant) -onvalue italic -offvalue roman
+ pack $top.g.size $top.g.bold $top.g.ital -side left
+ pack $top.g -side top
+ canvas $top.c -width 150 -height 50 -border 2 -relief sunk \
+ -background white
+ $top.c create text 100 25 -anchor center -text $which -font sample \
+ -fill black -tags text
+ bind $top.c <Configure> [list centertext $top.c]
+ pack $top.c -side top -fill x
+ ${NS}::frame $top.buts
+ ${NS}::button $top.buts.ok -text [mc "OK"] -command fontok -default active
+ ${NS}::button $top.buts.can -text [mc "Cancel"] -command fontcan -default normal
+ bind $top <Key-Return> fontok
+ bind $top <Key-Escape> fontcan
+ grid $top.buts.ok $top.buts.can
+ grid columnconfigure $top.buts 0 -weight 1 -uniform a
+ grid columnconfigure $top.buts 1 -weight 1 -uniform a
+ pack $top.buts -side bottom -fill x
+ trace add variable fontparam write chg_fontparam
} else {
- raise $top
- $top.c itemconf text -text $which
+ raise $top
+ $top.c itemconf text -text $which
}
set i [lsearch -exact $fontlist $fontparam(family)]
if {$i >= 0} {
- $top.f.fam selection set $i
- $top.f.fam see $i
+ $top.f.fam selection set $i
+ $top.f.fam see $i
}
}
@@ -11457,10 +11475,10 @@ proc fontok {} {
set f $fontparam(font)
set fontpref($f) [list $fontparam(family) $fontparam(size)]
if {$fontparam(weight) eq "bold"} {
- lappend fontpref($f) "bold"
+ lappend fontpref($f) "bold"
}
if {$fontparam(slant) eq "italic"} {
- lappend fontpref($f) "italic"
+ lappend fontpref($f) "italic"
}
set w $prefstop.notebook.fonts.$f
$w conf -text $fontparam(family) -font $fontpref($f)
@@ -11472,10 +11490,10 @@ proc fontcan {} {
global fonttop fontparam
if {[info exists fonttop]} {
- catch {destroy $fonttop}
- catch {font delete sample}
- unset fonttop
- unset fontparam
+ catch {destroy $fonttop}
+ catch {font delete sample}
+ unset fonttop
+ unset fontparam
}
}
@@ -11483,21 +11501,21 @@ if {[package vsatisfies [package provide Tk] 8.6]} {
# In Tk 8.6 we have a native font chooser dialog. Overwrite the above
# function to make use of it.
proc choosefont {font which} {
- tk fontchooser configure -title $which -font $font \
- -command [list on_choosefont $font $which]
- tk fontchooser show
+ tk fontchooser configure -title $which -font $font \
+ -command [list on_choosefont $font $which]
+ tk fontchooser show
}
proc on_choosefont {font which newfont} {
- global fontparam
- puts stderr "$font $newfont"
- array set f [font actual $newfont]
- set fontparam(which) $which
- set fontparam(font) $font
- set fontparam(family) $f(-family)
- set fontparam(size) $f(-size)
- set fontparam(weight) $f(-weight)
- set fontparam(slant) $f(-slant)
- fontok
+ global fontparam
+ puts stderr "$font $newfont"
+ array set f [font actual $newfont]
+ set fontparam(which) $which
+ set fontparam(font) $font
+ set fontparam(family) $f(-family)
+ set fontparam(size) $f(-size)
+ set fontparam(weight) $f(-weight)
+ set fontparam(slant) $f(-slant)
+ fontok
}
}
@@ -11506,7 +11524,7 @@ proc selfontfam {} {
set i [$fonttop.f.fam curselection]
if {$i ne {}} {
- set fontparam(family) [$fonttop.f.fam get $i]
+ set fontparam(family) [$fonttop.f.fam get $i]
}
}
@@ -11521,9 +11539,9 @@ proc create_prefs_page {w} {
global NS
set parent [join [lrange [split $w .] 0 end-1] .]
if {[winfo class $parent] eq "TNotebook"} {
- ${NS}::frame $w
+ ${NS}::frame $w
} else {
- ${NS}::labelframe $w
+ ${NS}::labelframe $w
}
}
@@ -11545,14 +11563,14 @@ proc prefspage_general {notebook} {
spinbox $page.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct
grid x $page.maxpctl $page.maxpct -sticky w
${NS}::checkbutton $page.showlocal -text [mc "Show local changes"] \
- -variable showlocalchanges
+ -variable showlocalchanges
grid x $page.showlocal -sticky w
${NS}::checkbutton $page.autoselect -text [mc "Auto-select SHA1 (length)"] \
- -variable autoselect
+ -variable autoselect
spinbox $page.autosellen -from 1 -to 40 -width 4 -textvariable autosellen
grid x $page.autoselect $page.autosellen -sticky w
${NS}::checkbutton $page.hideremotes -text [mc "Hide remote refs"] \
- -variable hideremotes
+ -variable hideremotes
grid x $page.hideremotes -sticky w
${NS}::label $page.ddisp -text [mc "Diff display options"]
@@ -11561,16 +11579,16 @@ proc prefspage_general {notebook} {
spinbox $page.tabstop -from 1 -to 20 -width 4 -textvariable tabstop
grid x $page.tabstopl $page.tabstop -sticky w
${NS}::checkbutton $page.ntag -text [mc "Display nearby tags/heads"] \
- -variable showneartags
+ -variable showneartags
grid x $page.ntag -sticky w
${NS}::label $page.maxrefsl -text [mc "Maximum # tags/heads to show"]
spinbox $page.maxrefs -from 1 -to 1000 -width 4 -textvariable maxrefs
grid x $page.maxrefsl $page.maxrefs -sticky w
${NS}::checkbutton $page.ldiff -text [mc "Limit diffs to listed paths"] \
- -variable limitdiffs
+ -variable limitdiffs
grid x $page.ldiff -sticky w
${NS}::checkbutton $page.lattr -text [mc "Support per-file encodings"] \
- -variable perfile_attrs
+ -variable perfile_attrs
grid x $page.lattr -sticky w
${NS}::entry $page.extdifft -textvariable extdifftool
@@ -11591,11 +11609,11 @@ proc prefspage_general {notebook} {
${NS}::label $page.lgen -text [mc "General options"]
grid $page.lgen - -sticky w -pady 10
${NS}::checkbutton $page.want_ttk -variable want_ttk \
- -text [mc "Use themed widgets"]
+ -text [mc "Use themed widgets"]
if {$have_ttk} {
- ${NS}::label $page.ttk_note -text [mc "(change requires restart)"]
+ ${NS}::label $page.ttk_note -text [mc "(change requires restart)"]
} else {
- ${NS}::label $page.ttk_note -text [mc "(currently unavailable)"]
+ ${NS}::label $page.ttk_note -text [mc "(currently unavailable)"]
}
grid x $page.want_ttk $page.ttk_note -sticky w
return $page
@@ -11603,6 +11621,7 @@ proc prefspage_general {notebook} {
proc prefspage_colors {notebook} {
global NS uicolor bgcolor fgcolor ctext diffcolors selectbgcolor markbgcolor
+ global diffbgcolors
set page [create_prefs_page $notebook.colors]
@@ -11614,37 +11633,49 @@ proc prefspage_colors {notebook} {
grid x $page.uibut $page.ui -sticky w
label $page.bg -padx 40 -relief sunk -background $bgcolor
${NS}::button $page.bgbut -text [mc "Background"] \
- -command [list choosecolor bgcolor {} $page.bg [mc "background"] setbg]
+ -command [list choosecolor bgcolor {} $page.bg [mc "background"] setbg]
grid x $page.bgbut $page.bg -sticky w
label $page.fg -padx 40 -relief sunk -background $fgcolor
${NS}::button $page.fgbut -text [mc "Foreground"] \
- -command [list choosecolor fgcolor {} $page.fg [mc "foreground"] setfg]
+ -command [list choosecolor fgcolor {} $page.fg [mc "foreground"] setfg]
grid x $page.fgbut $page.fg -sticky w
label $page.diffold -padx 40 -relief sunk -background [lindex $diffcolors 0]
${NS}::button $page.diffoldbut -text [mc "Diff: old lines"] \
- -command [list choosecolor diffcolors 0 $page.diffold [mc "diff old lines"] \
- [list $ctext tag conf d0 -foreground]]
+ -command [list choosecolor diffcolors 0 $page.diffold [mc "diff old lines"] \
+ [list $ctext tag conf d0 -foreground]]
grid x $page.diffoldbut $page.diffold -sticky w
+ label $page.diffoldbg -padx 40 -relief sunk -background [lindex $diffbgcolors 0]
+ ${NS}::button $page.diffoldbgbut -text [mc "Diff: old lines bg"] \
+ -command [list choosecolor diffbgcolors 0 $page.diffoldbg \
+ [mc "diff old lines bg"] \
+ [list $ctext tag conf d0 -background]]
+ grid x $page.diffoldbgbut $page.diffoldbg -sticky w
label $page.diffnew -padx 40 -relief sunk -background [lindex $diffcolors 1]
${NS}::button $page.diffnewbut -text [mc "Diff: new lines"] \
- -command [list choosecolor diffcolors 1 $page.diffnew [mc "diff new lines"] \
- [list $ctext tag conf dresult -foreground]]
+ -command [list choosecolor diffcolors 1 $page.diffnew [mc "diff new lines"] \
+ [list $ctext tag conf dresult -foreground]]
grid x $page.diffnewbut $page.diffnew -sticky w
+ label $page.diffnewbg -padx 40 -relief sunk -background [lindex $diffbgcolors 1]
+ ${NS}::button $page.diffnewbgbut -text [mc "Diff: new lines bg"] \
+ -command [list choosecolor diffbgcolors 1 $page.diffnewbg \
+ [mc "diff new lines bg"] \
+ [list $ctext tag conf dresult -background]]
+ grid x $page.diffnewbgbut $page.diffnewbg -sticky w
label $page.hunksep -padx 40 -relief sunk -background [lindex $diffcolors 2]
${NS}::button $page.hunksepbut -text [mc "Diff: hunk header"] \
- -command [list choosecolor diffcolors 2 $page.hunksep \
- [mc "diff hunk header"] \
- [list $ctext tag conf hunksep -foreground]]
+ -command [list choosecolor diffcolors 2 $page.hunksep \
+ [mc "diff hunk header"] \
+ [list $ctext tag conf hunksep -foreground]]
grid x $page.hunksepbut $page.hunksep -sticky w
label $page.markbgsep -padx 40 -relief sunk -background $markbgcolor
${NS}::button $page.markbgbut -text [mc "Marked line bg"] \
- -command [list choosecolor markbgcolor {} $page.markbgsep \
- [mc "marked line background"] \
- [list $ctext tag conf omark -background]]
+ -command [list choosecolor markbgcolor {} $page.markbgsep \
+ [mc "marked line background"] \
+ [list $ctext tag conf omark -background]]
grid x $page.markbgbut $page.markbgsep -sticky w
label $page.selbgsep -padx 40 -relief sunk -background $selectbgcolor
${NS}::button $page.selbgbut -text [mc "Select bg"] \
- -command [list choosecolor selectbgcolor {} $page.selbgsep [mc "background"] setselbg]
+ -command [list choosecolor selectbgcolor {} $page.selbgsep [mc "background"] setselbg]
grid x $page.selbgbut $page.selbgsep -sticky w
return $page
}
@@ -11670,21 +11701,21 @@ proc doprefs {} {
set top .gitkprefs
set prefstop $top
if {[winfo exists $top]} {
- raise $top
- return
+ raise $top
+ return
}
foreach v {maxwidth maxgraphpct showneartags showlocalchanges \
- limitdiffs tabstop perfile_attrs hideremotes want_ttk} {
- set oldprefs($v) [set $v]
+ limitdiffs tabstop perfile_attrs hideremotes want_ttk} {
+ set oldprefs($v) [set $v]
}
ttk_toplevel $top
wm title $top [mc "Gitk preferences"]
make_transient $top .
if {[set use_notebook [expr {$use_ttk && [info command ::ttk::notebook] ne ""}]]} {
- set notebook [ttk::notebook $top.notebook]
+ set notebook [ttk::notebook $top.notebook]
} else {
- set notebook [${NS}::frame $top.notebook -borderwidth 0 -relief flat]
+ set notebook [${NS}::frame $top.notebook -borderwidth 0 -relief flat]
}
lappend pages [prefspage_general $notebook] [mc "General"]
@@ -11692,21 +11723,21 @@ proc doprefs {} {
lappend pages [prefspage_fonts $notebook] [mc "Fonts"]
set col 0
foreach {page title} $pages {
- if {$use_notebook} {
- $notebook add $page -text $title
- } else {
- set btn [${NS}::button $notebook.b_[string map {. X} $page] \
- -text $title -command [list raise $page]]
- $page configure -text $title
- grid $btn -row 0 -column [incr col] -sticky w
- grid $page -row 1 -column 0 -sticky news -columnspan 100
- }
+ if {$use_notebook} {
+ $notebook add $page -text $title
+ } else {
+ set btn [${NS}::button $notebook.b_[string map {. X} $page] \
+ -text $title -command [list raise $page]]
+ $page configure -text $title
+ grid $btn -row 0 -column [incr col] -sticky w
+ grid $page -row 1 -column 0 -sticky news -columnspan 100
+ }
}
if {!$use_notebook} {
- grid columnconfigure $notebook 0 -weight 1
- grid rowconfigure $notebook 1 -weight 1
- raise [lindex $pages 0]
+ grid columnconfigure $notebook 0 -weight 1
+ grid rowconfigure $notebook 1 -weight 1
+ raise [lindex $pages 0]
}
grid $notebook -sticky news -padx 2 -pady 2
@@ -11731,7 +11762,7 @@ proc choose_extdiff {} {
set prog [tk_getOpenFile -title [mc "External diff tool"] -multiple false]
if {$prog ne {}} {
- set extdifftool $prog
+ set extdifftool $prog
}
}
@@ -11739,7 +11770,7 @@ proc choosecolor {v vi w x cmd} {
global $v
set c [tk_chooseColor -initialcolor [lindex [set $v] $vi] \
- -title [mc "Gitk: choose color for %s" $x]]
+ -title [mc "Gitk: choose color for %s" $x]]
if {$c eq {}} return
$w conf -background $c
lset $v $vi $c
@@ -11749,12 +11780,12 @@ proc choosecolor {v vi w x cmd} {
proc setselbg {c} {
global bglist cflist
foreach w $bglist {
- if {[winfo exists $w]} {
- $w configure -selectbackground $c
- }
+ if {[winfo exists $w]} {
+ $w configure -selectbackground $c
+ }
}
$cflist tag configure highlight \
- -background [$cflist cget -selectbackground]
+ -background [$cflist cget -selectbackground]
allcanvs itemconf secsel -fill $c
}
@@ -11768,7 +11799,7 @@ proc setui {c} {
set bg [winfo rgb . $c]
set selc black
if {[lindex $bg 0] + 1.5 * [lindex $bg 1] + 0.5 * [lindex $bg 2] > 100000} {
- set selc white
+ set selc white
}
tk_setPalette background $c selectColor $selc
}
@@ -11777,9 +11808,9 @@ proc setbg {c} {
global bglist
foreach w $bglist {
- if {[winfo exists $w]} {
- $w conf -background $c
- }
+ if {[winfo exists $w]} {
+ $w conf -background $c
+ }
}
}
@@ -11787,9 +11818,9 @@ proc setfg {c} {
global fglist canv
foreach w $fglist {
- if {[winfo exists $w]} {
- $w conf -foreground $c
- }
+ if {[winfo exists $w]} {
+ $w conf -foreground $c
+ }
}
allcanvs itemconf text -fill $c
$canv itemconf circle -outline $c
@@ -11800,9 +11831,9 @@ proc prefscan {} {
global oldprefs prefstop
foreach v {maxwidth maxgraphpct showneartags showlocalchanges \
- limitdiffs tabstop perfile_attrs hideremotes want_ttk} {
- global $v
- set $v $oldprefs($v)
+ limitdiffs tabstop perfile_attrs hideremotes want_ttk} {
+ global $v
+ set $v $oldprefs($v)
}
catch {destroy $prefstop}
unset prefstop
@@ -11821,76 +11852,76 @@ proc prefsok {} {
fontcan
set fontchanged 0
if {$mainfont ne $fontpref(mainfont)} {
- set mainfont $fontpref(mainfont)
- parsefont mainfont $mainfont
- eval font configure mainfont [fontflags mainfont]
- eval font configure mainfontbold [fontflags mainfont 1]
- setcoords
- set fontchanged 1
+ set mainfont $fontpref(mainfont)
+ parsefont mainfont $mainfont
+ eval font configure mainfont [fontflags mainfont]
+ eval font configure mainfontbold [fontflags mainfont 1]
+ setcoords
+ set fontchanged 1
}
if {$textfont ne $fontpref(textfont)} {
- set textfont $fontpref(textfont)
- parsefont textfont $textfont
- eval font configure textfont [fontflags textfont]
- eval font configure textfontbold [fontflags textfont 1]
+ set textfont $fontpref(textfont)
+ parsefont textfont $textfont
+ eval font configure textfont [fontflags textfont]
+ eval font configure textfontbold [fontflags textfont 1]
}
if {$uifont ne $fontpref(uifont)} {
- set uifont $fontpref(uifont)
- parsefont uifont $uifont
- eval font configure uifont [fontflags uifont]
+ set uifont $fontpref(uifont)
+ parsefont uifont $uifont
+ eval font configure uifont [fontflags uifont]
}
settabs
if {$showlocalchanges != $oldprefs(showlocalchanges)} {
- if {$showlocalchanges} {
- doshowlocalchanges
- } else {
- dohidelocalchanges
- }
+ if {$showlocalchanges} {
+ doshowlocalchanges
+ } else {
+ dohidelocalchanges
+ }
}
if {$limitdiffs != $oldprefs(limitdiffs) ||
- ($perfile_attrs && !$oldprefs(perfile_attrs))} {
- # treediffs elements are limited by path;
- # won't have encodings cached if perfile_attrs was just turned on
- unset -nocomplain treediffs
+ ($perfile_attrs && !$oldprefs(perfile_attrs))} {
+ # treediffs elements are limited by path;
+ # won't have encodings cached if perfile_attrs was just turned on
+ unset -nocomplain treediffs
}
if {$fontchanged || $maxwidth != $oldprefs(maxwidth)
- || $maxgraphpct != $oldprefs(maxgraphpct)} {
- redisplay
+ || $maxgraphpct != $oldprefs(maxgraphpct)} {
+ redisplay
} elseif {$showneartags != $oldprefs(showneartags) ||
- $limitdiffs != $oldprefs(limitdiffs)} {
- reselectline
+ $limitdiffs != $oldprefs(limitdiffs)} {
+ reselectline
}
if {$hideremotes != $oldprefs(hideremotes)} {
- rereadrefs
+ rereadrefs
}
}
proc formatdate {d} {
global datetimeformat
if {$d ne {}} {
- # If $datetimeformat includes a timezone, display in the
- # timezone of the argument. Otherwise, display in local time.
- if {[string match {*%[zZ]*} $datetimeformat]} {
- if {[catch {set d [clock format [lindex $d 0] -timezone [lindex $d 1] -format $datetimeformat]}]} {
- # Tcl < 8.5 does not support -timezone. Emulate it by
- # setting TZ (e.g. TZ=<-0430>+04:30).
- global env
- if {[info exists env(TZ)]} {
- set savedTZ $env(TZ)
- }
- set zone [lindex $d 1]
- set sign [string map {+ - - +} [string index $zone 0]]
- set env(TZ) <$zone>$sign[string range $zone 1 2]:[string range $zone 3 4]
- set d [clock format [lindex $d 0] -format $datetimeformat]
- if {[info exists savedTZ]} {
- set env(TZ) $savedTZ
- } else {
- unset env(TZ)
- }
- }
- } else {
- set d [clock format [lindex $d 0] -format $datetimeformat]
- }
+ # If $datetimeformat includes a timezone, display in the
+ # timezone of the argument. Otherwise, display in local time.
+ if {[string match {*%[zZ]*} $datetimeformat]} {
+ if {[catch {set d [clock format [lindex $d 0] -timezone [lindex $d 1] -format $datetimeformat]}]} {
+ # Tcl < 8.5 does not support -timezone. Emulate it by
+ # setting TZ (e.g. TZ=<-0430>+04:30).
+ global env
+ if {[info exists env(TZ)]} {
+ set savedTZ $env(TZ)
+ }
+ set zone [lindex $d 1]
+ set sign [string map {+ - - +} [string index $zone 0]]
+ set env(TZ) <$zone>$sign[string range $zone 1 2]:[string range $zone 3 4]
+ set d [clock format [lindex $d 0] -format $datetimeformat]
+ if {[info exists savedTZ]} {
+ set env(TZ) $savedTZ
+ } else {
+ unset env(TZ)
+ }
+ }
+ } else {
+ set d [clock format [lindex $d 0] -format $datetimeformat]
+ }
}
return $d
}
@@ -12136,38 +12167,38 @@ set encoding_aliases {
proc tcl_encoding {enc} {
global encoding_aliases tcl_encoding_cache
if {[info exists tcl_encoding_cache($enc)]} {
- return $tcl_encoding_cache($enc)
+ return $tcl_encoding_cache($enc)
}
set names [encoding names]
set lcnames [string tolower $names]
set enc [string tolower $enc]
set i [lsearch -exact $lcnames $enc]
if {$i < 0} {
- # look for "isonnn" instead of "iso-nnn" or "iso_nnn"
- if {[regsub {^(iso|cp|ibm|jis)[-_]} $enc {\1} encx]} {
- set i [lsearch -exact $lcnames $encx]
- }
+ # look for "isonnn" instead of "iso-nnn" or "iso_nnn"
+ if {[regsub {^(iso|cp|ibm|jis)[-_]} $enc {\1} encx]} {
+ set i [lsearch -exact $lcnames $encx]
+ }
}
if {$i < 0} {
- foreach l $encoding_aliases {
- set ll [string tolower $l]
- if {[lsearch -exact $ll $enc] < 0} continue
- # look through the aliases for one that tcl knows about
- foreach e $ll {
- set i [lsearch -exact $lcnames $e]
- if {$i < 0} {
- if {[regsub {^(iso|cp|ibm|jis)[-_]} $e {\1} ex]} {
- set i [lsearch -exact $lcnames $ex]
- }
- }
- if {$i >= 0} break
- }
- break
- }
+ foreach l $encoding_aliases {
+ set ll [string tolower $l]
+ if {[lsearch -exact $ll $enc] < 0} continue
+ # look through the aliases for one that tcl knows about
+ foreach e $ll {
+ set i [lsearch -exact $lcnames $e]
+ if {$i < 0} {
+ if {[regsub {^(iso|cp|ibm|jis)[-_]} $e {\1} ex]} {
+ set i [lsearch -exact $lcnames $ex]
+ }
+ }
+ if {$i >= 0} break
+ }
+ break
+ }
}
set tclenc {}
if {$i >= 0} {
- set tclenc [lindex $names $i]
+ set tclenc [lindex $names $i]
}
set tcl_encoding_cache($enc) $tclenc
return $tclenc
@@ -12176,16 +12207,16 @@ proc tcl_encoding {enc} {
proc gitattr {path attr default} {
global path_attr_cache
if {[info exists path_attr_cache($attr,$path)]} {
- set r $path_attr_cache($attr,$path)
+ set r $path_attr_cache($attr,$path)
} else {
- set r "unspecified"
- if {![catch {set line [exec git check-attr $attr -- $path]}]} {
- regexp "(.*): $attr: (.*)" $line m f r
- }
- set path_attr_cache($attr,$path) $r
+ set r "unspecified"
+ if {![catch {set line [exec git check-attr $attr -- $path]}]} {
+ regexp "(.*): $attr: (.*)" $line m f r
+ }
+ set path_attr_cache($attr,$path) $r
}
if {$r eq "unspecified"} {
- return $default
+ return $default
}
return $r
}
@@ -12194,28 +12225,28 @@ proc cache_gitattr {attr pathlist} {
global path_attr_cache
set newlist {}
foreach path $pathlist {
- if {![info exists path_attr_cache($attr,$path)]} {
- lappend newlist $path
- }
+ if {![info exists path_attr_cache($attr,$path)]} {
+ lappend newlist $path
+ }
}
set lim 1000
if {[tk windowingsystem] == "win32"} {
- # windows has a 32k limit on the arguments to a command...
- set lim 30
+ # windows has a 32k limit on the arguments to a command...
+ set lim 30
}
while {$newlist ne {}} {
- set head [lrange $newlist 0 [expr {$lim - 1}]]
- set newlist [lrange $newlist $lim end]
- if {![catch {set rlist [eval exec git check-attr $attr -- $head]}]} {
- foreach row [split $rlist "\n"] {
- if {[regexp "(.*): $attr: (.*)" $row m path value]} {
- if {[string index $path 0] eq "\""} {
- set path [encoding convertfrom [lindex $path 0]]
- }
- set path_attr_cache($attr,$path) $value
- }
- }
- }
+ set head [lrange $newlist 0 [expr {$lim - 1}]]
+ set newlist [lrange $newlist $lim end]
+ if {![catch {set rlist [eval exec git check-attr $attr -- $head]}]} {
+ foreach row [split $rlist "\n"] {
+ if {[regexp "(.*): $attr: (.*)" $row m path value]} {
+ if {[string index $path 0] eq "\""} {
+ set path [encoding convertfrom [lindex $path 0]]
+ }
+ set path_attr_cache($attr,$path) $value
+ }
+ }
+ }
}
}
@@ -12223,10 +12254,10 @@ proc get_path_encoding {path} {
global gui_encoding perfile_attrs
set tcl_enc $gui_encoding
if {$path ne {} && $perfile_attrs} {
- set enc2 [tcl_encoding [gitattr $path encoding $tcl_enc]]
- if {$enc2 ne {}} {
- set tcl_enc $enc2
- }
+ set enc2 [tcl_encoding [gitattr $path encoding $tcl_enc]]
+ if {$enc2 ne {}} {
+ set tcl_enc $enc2
+ }
}
return $tcl_enc
}
@@ -12253,7 +12284,7 @@ namespace import ::msgcat::mc
# First check that Tcl/Tk is recent enough
if {[catch {package require Tk 8.4} err]} {
show_error {} . [mc "Sorry, gitk cannot run with this version of Tcl/Tk.\n\
- Gitk requires at least Tcl/Tk 8.4."]
+ Gitk requires at least Tcl/Tk 8.4."]
exit 1
}
@@ -12293,12 +12324,12 @@ set gui_encoding [encoding system]
catch {
set enc [exec git config --get gui.encoding]
if {$enc ne {}} {
- set tclenc [tcl_encoding $enc]
- if {$tclenc ne {}} {
- set gui_encoding $tclenc
- } else {
- puts stderr "Warning: encoding $enc is not supported by Tcl/Tk"
- }
+ set tclenc [tcl_encoding $enc]
+ if {$tclenc ne {}} {
+ set gui_encoding $tclenc
+ } else {
+ puts stderr "Warning: encoding $enc is not supported by Tcl/Tk"
+ }
}
}
@@ -12368,12 +12399,13 @@ if {[tk windowingsystem] eq "win32"} {
set fgcolor black
set selectbgcolor gray85
if {[tk windowingsystem] eq "aqua"} {
- set web_browser "open"
+ set web_browser "open"
} else {
- set web_browser "xdg-open"
+ set web_browser "xdg-open"
}
}
-set diffcolors {red "#00a000" blue}
+set diffcolors {"#c30000" "#009800" blue}
+set diffbgcolors {"#fff3f3" "#f0fff0"}
set diffcontext 3
set mergecolors {red blue "#00ff00" purple brown "#009090" magenta "#808000" "#009000" "#ff0080" cyan "#b07070" "#70b0f0" "#70f0b0" "#f0b070" "#ff70b0"}
set ignorespace 0
@@ -12413,22 +12445,22 @@ catch {
# follow the XDG base directory specification by default. See
# http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
if {[info exists env(XDG_CONFIG_HOME)] && $env(XDG_CONFIG_HOME) ne ""} {
- # XDG_CONFIG_HOME environment variable is set
- set config_file [file join $env(XDG_CONFIG_HOME) git gitk]
- set config_file_tmp [file join $env(XDG_CONFIG_HOME) git gitk-tmp]
+ # XDG_CONFIG_HOME environment variable is set
+ set config_file [file join $env(XDG_CONFIG_HOME) git gitk]
+ set config_file_tmp [file join $env(XDG_CONFIG_HOME) git gitk-tmp]
} else {
- # default XDG_CONFIG_HOME
- set config_file "~/.config/git/gitk"
- set config_file_tmp "~/.config/git/gitk-tmp"
+ # default XDG_CONFIG_HOME
+ set config_file "~/.config/git/gitk"
+ set config_file_tmp "~/.config/git/gitk-tmp"
}
if {![file exists $config_file]} {
- # for backward compatibility use the old config file if it exists
- if {[file exists "~/.gitk"]} {
- set config_file "~/.gitk"
- set config_file_tmp "~/.gitk-tmp"
- } elseif {![file exists [file dirname $config_file]]} {
- file mkdir [file dirname $config_file]
- }
+ # for backward compatibility use the old config file if it exists
+ if {[file exists "~/.gitk"]} {
+ set config_file "~/.gitk"
+ set config_file_tmp "~/.gitk-tmp"
+ } elseif {![file exists [file dirname $config_file]]} {
+ file mkdir [file dirname $config_file]
+ }
}
source $config_file
}
@@ -12444,7 +12476,7 @@ set config_variables {
remotebgcolor tagbgcolor tagfgcolor tagoutlinecolor reflinecolor
filesepbgcolor filesepfgcolor linehoverbgcolor linehoverfgcolor
linehoveroutlinecolor mainheadcirclecolor workingfilescirclecolor
- indexcirclecolor circlecolors linkfgcolor circleoutlinecolor
+ indexcirclecolor circlecolors linkfgcolor circleoutlinecolor diffbgcolors
web_browser
}
foreach var $config_variables {
@@ -12482,20 +12514,20 @@ set i 0
set revtreeargscmd {}
foreach arg $argv {
switch -glob -- $arg {
- "" { }
- "--" {
- set cmdline_files [lrange $argv [expr {$i + 1}] end]
- break
- }
- "--select-commit=*" {
- set selecthead [string range $arg 16 end]
- }
- "--argscmd=*" {
- set revtreeargscmd [string range $arg 10 end]
- }
- default {
- lappend revtreeargs $arg
- }
+ "" { }
+ "--" {
+ set cmdline_files [lrange $argv [expr {$i + 1}] end]
+ break
+ }
+ "--select-commit=*" {
+ set selecthead [string range $arg 16 end]
+ }
+ "--argscmd=*" {
+ set revtreeargscmd [string range $arg 10 end]
+ }
+ default {
+ lappend revtreeargs $arg
+ }
}
incr i
}
@@ -12507,29 +12539,29 @@ if {$selecthead eq "HEAD"} {
if {$i >= [llength $argv] && $revtreeargs ne {}} {
# no -- on command line, but some arguments (other than --argscmd)
if {[catch {
- set f [eval exec git rev-parse --no-revs --no-flags $revtreeargs]
- set cmdline_files [split $f "\n"]
- set n [llength $cmdline_files]
- set revtreeargs [lrange $revtreeargs 0 end-$n]
- # Unfortunately git rev-parse doesn't produce an error when
- # something is both a revision and a filename. To be consistent
- # with git log and git rev-list, check revtreeargs for filenames.
- foreach arg $revtreeargs {
- if {[file exists $arg]} {
- show_error {} . [mc "Ambiguous argument '%s': both revision\
- and filename" $arg]
- exit 1
- }
- }
+ set f [eval exec git rev-parse --no-revs --no-flags $revtreeargs]
+ set cmdline_files [split $f "\n"]
+ set n [llength $cmdline_files]
+ set revtreeargs [lrange $revtreeargs 0 end-$n]
+ # Unfortunately git rev-parse doesn't produce an error when
+ # something is both a revision and a filename. To be consistent
+ # with git log and git rev-list, check revtreeargs for filenames.
+ foreach arg $revtreeargs {
+ if {[file exists $arg]} {
+ show_error {} . [mc "Ambiguous argument '%s': both revision\
+ and filename" $arg]
+ exit 1
+ }
+ }
} err]} {
- # unfortunately we get both stdout and stderr in $err,
- # so look for "fatal:".
- set i [string first "fatal:" $err]
- if {$i > 0} {
- set err [string range $err [expr {$i + 6}] end]
- }
- show_error {} . "[mc "Bad arguments to gitk:"]\n$err"
- exit 1
+ # unfortunately we get both stdout and stderr in $err,
+ # so look for "fatal:".
+ set i [string first "fatal:" $err]
+ if {$i > 0} {
+ set err [string range $err [expr {$i + 6}] end]
+ }
+ show_error {} . "[mc "Bad arguments to gitk:"]\n$err"
+ exit 1
}
}
@@ -12599,7 +12631,7 @@ set cdup {}
if {[expr {[exec git rev-parse --is-inside-work-tree] == "true"}]} {
set cdup [exec git rev-parse --show-cdup]
}
-set worktree [exec git rev-parse --show-toplevel]
+set worktree [gitworktree]
setcoords
makewindow
catch {
@@ -12650,15 +12682,15 @@ if {$cmdline_files ne {} || $revtreeargs ne {} || $revtreeargscmd ne {}} {
if {[info exists permviews]} {
foreach v $permviews {
- set n $nextviewnum
- incr nextviewnum
- set viewname($n) [lindex $v 0]
- set viewfiles($n) [lindex $v 1]
- set viewargs($n) [lindex $v 2]
- set viewargscmd($n) [lindex $v 3]
- set viewperm($n) 1
- set viewchanged($n) 0
- addviewmenu $n
+ set n $nextviewnum
+ incr nextviewnum
+ set viewname($n) [lindex $v 0]
+ set viewfiles($n) [lindex $v 1]
+ set viewargs($n) [lindex $v 2]
+ set viewargscmd($n) [lindex $v 3]
+ set viewperm($n) 1
+ set viewchanged($n) 0
+ addviewmenu $n
}
}
diff --git a/line-log.c b/line-log.c
index bf73ea9..68eeb42 100644
--- a/line-log.c
+++ b/line-log.c
@@ -1159,7 +1159,7 @@ static int bloom_filter_check(struct rev_info *rev,
return 1;
if (!rev->bloom_filter_settings ||
- !(filter = get_bloom_filter(rev->repo, commit, 0)))
+ !(filter = get_bloom_filter(rev->repo, commit)))
return 1;
if (!range)
diff --git a/log-tree.c b/log-tree.c
index cb8942f..1927f91 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -885,7 +885,7 @@ int log_tree_diff_flush(struct rev_info *opt)
static int do_diff_combined(struct rev_info *opt, struct commit *commit)
{
- diff_tree_combined_merge(commit, opt->dense_combined_merges, opt);
+ diff_tree_combined_merge(commit, opt);
return !opt->loginfo;
}
diff --git a/object.h b/object.h
index 96a2105..20b1880 100644
--- a/object.h
+++ b/object.h
@@ -73,6 +73,7 @@ struct object_array {
* sha1-name.c: 20
* list-objects-filter.c: 21
* builtin/fsck.c: 0--3
+ * builtin/gc.c: 0
* builtin/index-pack.c: 2021
* builtin/pack-objects.c: 20
* builtin/reflog.c: 10--12
diff --git a/oidset.c b/oidset.c
index 15d4e18..2d0ab76 100644
--- a/oidset.c
+++ b/oidset.c
@@ -43,6 +43,12 @@ int oidset_size(struct oidset *set)
void oidset_parse_file(struct oidset *set, const char *path)
{
+ oidset_parse_file_carefully(set, path, NULL, NULL);
+}
+
+void oidset_parse_file_carefully(struct oidset *set, const char *path,
+ oidset_parse_tweak_fn fn, void *cbdata)
+{
FILE *fp;
struct strbuf sb = STRBUF_INIT;
struct object_id oid;
@@ -66,7 +72,8 @@ void oidset_parse_file(struct oidset *set, const char *path)
if (!sb.len)
continue;
- if (parse_oid_hex(sb.buf, &oid, &p) || *p != '\0')
+ if (parse_oid_hex(sb.buf, &oid, &p) || *p != '\0' ||
+ (fn && fn(&oid, cbdata)))
die("invalid object name: %s", sb.buf);
oidset_insert(set, &oid);
}
diff --git a/oidset.h b/oidset.h
index 209ae7a..01f6560 100644
--- a/oidset.h
+++ b/oidset.h
@@ -73,6 +73,15 @@ void oidset_clear(struct oidset *set);
*/
void oidset_parse_file(struct oidset *set, const char *path);
+/*
+ * Similar to the above, but with a callback which can (1) return non-zero to
+ * signal displeasure with the object and (2) replace object ID with something
+ * else (meant to be used to "peel").
+ */
+typedef int (*oidset_parse_tweak_fn)(struct object_id *, void *);
+void oidset_parse_file_carefully(struct oidset *set, const char *path,
+ oidset_parse_tweak_fn fn, void *cbdata);
+
struct oidset_iter {
kh_oid_set_t *set;
khiter_t iter;
diff --git a/pack-write.c b/pack-write.c
index 685d327..a6cdb3c 100644
--- a/pack-write.c
+++ b/pack-write.c
@@ -117,10 +117,8 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec
list = sorted_by_sha;
for (i = 0; i < nr_objects; i++) {
struct pack_idx_entry *obj = *list++;
- if (index_version < 2) {
- uint32_t offset = htonl(obj->offset);
- hashwrite(f, &offset, 4);
- }
+ if (index_version < 2)
+ hashwrite_be32(f, obj->offset);
hashwrite(f, obj->oid.hash, the_hash_algo->rawsz);
if ((opts->flags & WRITE_IDX_STRICT) &&
(i && oideq(&list[-2]->oid, &obj->oid)))
@@ -135,8 +133,7 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec
list = sorted_by_sha;
for (i = 0; i < nr_objects; i++) {
struct pack_idx_entry *obj = *list++;
- uint32_t crc32_val = htonl(obj->crc32);
- hashwrite(f, &crc32_val, 4);
+ hashwrite_be32(f, obj->crc32);
}
/* write the 32-bit offset table */
@@ -148,8 +145,7 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec
offset = (need_large_offset(obj->offset, opts)
? (0x80000000 | nr_large_offset++)
: obj->offset);
- offset = htonl(offset);
- hashwrite(f, &offset, 4);
+ hashwrite_be32(f, offset);
}
/* write the large offset table */
diff --git a/packfile.c b/packfile.c
index e69012e..0929ebe 100644
--- a/packfile.c
+++ b/packfile.c
@@ -1475,7 +1475,7 @@ void clear_delta_base_cache(void)
static void add_delta_base_cache(struct packed_git *p, off_t base_offset,
void *base, unsigned long base_size, enum object_type type)
{
- struct delta_base_cache_entry *ent = xmalloc(sizeof(*ent));
+ struct delta_base_cache_entry *ent;
struct list_head *lru, *tmp;
/*
@@ -1483,8 +1483,10 @@ static void add_delta_base_cache(struct packed_git *p, off_t base_offset,
* is unpacking the same object, in unpack_entry() (since its phases I
* and III might run concurrently across multiple threads).
*/
- if (in_delta_base_cache(p, base_offset))
+ if (in_delta_base_cache(p, base_offset)) {
+ free(base);
return;
+ }
delta_base_cached += base_size;
@@ -1496,6 +1498,7 @@ static void add_delta_base_cache(struct packed_git *p, off_t base_offset,
release_delta_base_cache(f);
}
+ ent = xmalloc(sizeof(*ent));
ent->key.p = p;
ent->key.base_offset = base_offset;
ent->type = type;
@@ -1776,12 +1779,10 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,
void *external_base = NULL;
unsigned long delta_size, base_size = size;
int i;
+ off_t base_obj_offset = obj_offset;
data = NULL;
- if (base)
- add_delta_base_cache(p, obj_offset, base, base_size, type);
-
if (!base) {
/*
* We're probably in deep shit, but let's try to fetch
@@ -1819,24 +1820,33 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,
"at offset %"PRIuMAX" from %s",
(uintmax_t)curpos, p->pack_name);
data = NULL;
- free(external_base);
- continue;
- }
+ } else {
+ data = patch_delta(base, base_size, delta_data,
+ delta_size, &size);
- data = patch_delta(base, base_size,
- delta_data, delta_size,
- &size);
+ /*
+ * We could not apply the delta; warn the user, but
+ * keep going. Our failure will be noticed either in
+ * the next iteration of the loop, or if this is the
+ * final delta, in the caller when we return NULL.
+ * Those code paths will take care of making a more
+ * explicit warning and retrying with another copy of
+ * the object.
+ */
+ if (!data)
+ error("failed to apply delta");
+ }
/*
- * We could not apply the delta; warn the user, but keep going.
- * Our failure will be noticed either in the next iteration of
- * the loop, or if this is the final delta, in the caller when
- * we return NULL. Those code paths will take care of making
- * a more explicit warning and retrying with another copy of
- * the object.
+ * We delay adding `base` to the cache until the end of the loop
+ * because unpack_compressed_entry() momentarily releases the
+ * obj_read_mutex, giving another thread the chance to access
+ * the cache. Therefore, if `base` was already there, this other
+ * thread could free() it (e.g. to make space for another entry)
+ * before we are done using it.
*/
- if (!data)
- error("failed to apply delta");
+ if (!external_base)
+ add_delta_base_cache(p, base_obj_offset, base, base_size, type);
free(delta_data);
free(external_base);
diff --git a/protocol.c b/protocol.c
index 8d964fc..052d7ed 100644
--- a/protocol.c
+++ b/protocol.c
@@ -17,7 +17,6 @@ static enum protocol_version parse_protocol_version(const char *value)
enum protocol_version get_protocol_version_config(void)
{
const char *value;
- int val;
const char *git_test_k = "GIT_TEST_PROTOCOL_VERSION";
const char *git_test_v;
@@ -31,9 +30,6 @@ enum protocol_version get_protocol_version_config(void)
return version;
}
- if (!git_config_get_bool("feature.experimental", &val) && val)
- return protocol_v2;
-
git_test_v = getenv(git_test_k);
if (git_test_v && *git_test_v) {
enum protocol_version env = parse_protocol_version(git_test_v);
@@ -43,7 +39,7 @@ enum protocol_version get_protocol_version_config(void)
return env;
}
- return protocol_v0;
+ return protocol_v2;
}
enum protocol_version determine_protocol_version_server(void)
diff --git a/ref-filter.c b/ref-filter.c
index 5550a0d..c62f6b4 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1557,9 +1557,7 @@ char *get_head_description(void)
strbuf_addstr(&desc, _("no branch"));
strbuf_addch(&desc, ')');
- free(state.branch);
- free(state.onto);
- free(state.detached_from);
+ wt_status_state_free_buffers(&state);
return strbuf_detach(&desc, NULL);
}
@@ -2239,12 +2237,14 @@ static void reach_filter(struct ref_array *array,
{
struct rev_info revs;
int i, old_nr;
- struct commit **to_clear = xcalloc(sizeof(struct commit *), array->nr);
+ struct commit **to_clear;
struct commit_list *cr;
if (!check_reachable)
return;
+ to_clear = xcalloc(sizeof(struct commit *), array->nr);
+
repo_init_revisions(the_repository, &revs, NULL);
for (i = 0; i < array->nr; i++) {
diff --git a/remote.h b/remote.h
index 5e3ea5a..eb62a47 100644
--- a/remote.h
+++ b/remote.h
@@ -93,6 +93,14 @@ int for_each_remote(each_remote_fn fn, void *priv);
int remote_has_url(struct remote *remote, const char *url);
+struct ref_push_report {
+ const char *ref_name;
+ struct object_id *old_oid;
+ struct object_id *new_oid;
+ unsigned int forced_update:1;
+ struct ref_push_report *next;
+};
+
struct ref {
struct ref *next;
struct object_id old_oid;
@@ -140,6 +148,7 @@ struct ref {
REF_STATUS_ATOMIC_PUSH_FAILED
} status;
char *remote_status;
+ struct ref_push_report *report;
struct ref *peer_ref; /* when renaming */
char name[FLEX_ARRAY]; /* more */
};
diff --git a/repo-settings.c b/repo-settings.c
index aa61a35..88ccce2 100644
--- a/repo-settings.c
+++ b/repo-settings.c
@@ -17,9 +17,12 @@ void prepare_repo_settings(struct repository *r)
if (!repo_config_get_bool(r, "core.commitgraph", &value))
r->settings.core_commit_graph = value;
+ if (!repo_config_get_bool(r, "commitgraph.readchangedpaths", &value))
+ r->settings.commit_graph_read_changed_paths = value;
if (!repo_config_get_bool(r, "gc.writecommitgraph", &value))
r->settings.gc_write_commit_graph = value;
UPDATE_DEFAULT_BOOL(r->settings.core_commit_graph, 1);
+ UPDATE_DEFAULT_BOOL(r->settings.commit_graph_read_changed_paths, 1);
UPDATE_DEFAULT_BOOL(r->settings.gc_write_commit_graph, 1);
if (!repo_config_get_int(r, "index.version", &value))
diff --git a/repository.h b/repository.h
index 628c834..bacf843 100644
--- a/repository.h
+++ b/repository.h
@@ -30,6 +30,7 @@ struct repo_settings {
int initialized;
int core_commit_graph;
+ int commit_graph_read_changed_paths;
int gc_write_commit_graph;
int fetch_write_commit_graph;
diff --git a/revision.c b/revision.c
index 067030e..d9dc578 100644
--- a/revision.c
+++ b/revision.c
@@ -681,10 +681,7 @@ static void prepare_to_use_bloom_filter(struct rev_info *revs)
repo_parse_commit(revs->repo, revs->commits->item);
- if (!revs->repo->objects->commit_graph)
- return;
-
- revs->bloom_filter_settings = revs->repo->objects->commit_graph->bloom_filter_settings;
+ revs->bloom_filter_settings = get_bloom_filter_settings(revs->repo);
if (!revs->bloom_filter_settings)
return;
@@ -755,7 +752,7 @@ static int check_maybe_different_in_bloom_filter(struct rev_info *revs,
if (commit_graph_generation(commit) == GENERATION_NUMBER_INFINITY)
return -1;
- filter = get_bloom_filter(revs->repo, commit, 0);
+ filter = get_bloom_filter(revs->repo, commit);
if (!filter) {
count_bloom_filter_not_present++;
diff --git a/run-command.c b/run-command.c
index cc9c329..2ee59ac 100644
--- a/run-command.c
+++ b/run-command.c
@@ -1866,15 +1866,13 @@ int run_processes_parallel_tr2(int n, get_next_task_fn get_next_task,
return result;
}
-int run_auto_gc(int quiet)
+int run_auto_maintenance(int quiet)
{
- struct strvec argv_gc_auto = STRVEC_INIT;
- int status;
+ struct child_process maint = CHILD_PROCESS_INIT;
- strvec_pushl(&argv_gc_auto, "gc", "--auto", NULL);
- if (quiet)
- strvec_push(&argv_gc_auto, "--quiet");
- status = run_command_v_opt(argv_gc_auto.v, RUN_GIT_CMD);
- strvec_clear(&argv_gc_auto);
- return status;
+ maint.git_cmd = 1;
+ strvec_pushl(&maint.args, "maintenance", "run", "--auto", NULL);
+ strvec_push(&maint.args, quiet ? "--quiet" : "--no-quiet");
+
+ return run_command(&maint);
}
diff --git a/run-command.h b/run-command.h
index 8b9bfae..6472b38 100644
--- a/run-command.h
+++ b/run-command.h
@@ -221,7 +221,7 @@ int run_hook_ve(const char *const *env, const char *name, va_list args);
/*
* Trigger an auto-gc
*/
-int run_auto_gc(int quiet);
+int run_auto_maintenance(int quiet);
#define RUN_COMMAND_NO_STDIN 1
#define RUN_GIT_CMD 2 /*If this is to be git sub-command */
diff --git a/send-pack.c b/send-pack.c
index 632f158..c969807 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -154,25 +154,79 @@ static int receive_status(struct packet_reader *reader, struct ref *refs)
{
struct ref *hint;
int ret;
+ struct ref_push_report *report = NULL;
+ int new_report = 0;
+ int once = 0;
hint = NULL;
ret = receive_unpack_status(reader);
while (1) {
+ struct object_id old_oid, new_oid;
+ const char *head;
const char *refname;
- char *msg;
+ char *p;
if (packet_reader_read(reader) != PACKET_READ_NORMAL)
break;
- if (!starts_with(reader->line, "ok ") && !starts_with(reader->line, "ng ")) {
- error("invalid ref status from remote: %s", reader->line);
+ head = reader->line;
+ p = strchr(head, ' ');
+ if (!p) {
+ error("invalid status line from remote: %s", reader->line);
ret = -1;
break;
}
+ *p++ = '\0';
- refname = reader->line + 3;
- msg = strchr(refname, ' ');
- if (msg)
- *msg++ = '\0';
+ if (!strcmp(head, "option")) {
+ const char *key, *val;
+ if (!hint || !(report || new_report)) {
+ if (!once++)
+ error("'option' without a matching 'ok/ng' directive");
+ ret = -1;
+ continue;
+ }
+ if (new_report) {
+ if (!hint->report) {
+ hint->report = xcalloc(1, sizeof(struct ref_push_report));
+ report = hint->report;
+ } else {
+ report = hint->report;
+ while (report->next)
+ report = report->next;
+ report->next = xcalloc(1, sizeof(struct ref_push_report));
+ report = report->next;
+ }
+ new_report = 0;
+ }
+ key = p;
+ p = strchr(key, ' ');
+ if (p)
+ *p++ = '\0';
+ val = p;
+ if (!strcmp(key, "refname"))
+ report->ref_name = xstrdup_or_null(val);
+ else if (!strcmp(key, "old-oid") && val &&
+ !parse_oid_hex(val, &old_oid, &val))
+ report->old_oid = oiddup(&old_oid);
+ else if (!strcmp(key, "new-oid") && val &&
+ !parse_oid_hex(val, &new_oid, &val))
+ report->new_oid = oiddup(&new_oid);
+ else if (!strcmp(key, "forced-update"))
+ report->forced_update = 1;
+ continue;
+ }
+
+ report = NULL;
+ new_report = 0;
+ if (strcmp(head, "ok") && strcmp(head, "ng")) {
+ error("invalid ref status from remote: %s", head);
+ ret = -1;
+ break;
+ }
+ refname = p;
+ p = strchr(refname, ' ');
+ if (p)
+ *p++ = '\0';
/* first try searching at our hint, falling back to all refs */
if (hint)
hint = find_ref_by_name(hint, refname);
@@ -180,22 +234,27 @@ static int receive_status(struct packet_reader *reader, struct ref *refs)
hint = find_ref_by_name(refs, refname);
if (!hint) {
warning("remote reported status on unknown ref: %s",
- refname);
+ refname);
continue;
}
- if (hint->status != REF_STATUS_EXPECTING_REPORT) {
+ if (hint->status != REF_STATUS_EXPECTING_REPORT &&
+ hint->status != REF_STATUS_OK &&
+ hint->status != REF_STATUS_REMOTE_REJECT) {
warning("remote reported status on unexpected ref: %s",
- refname);
+ refname);
continue;
}
-
- if (reader->line[0] == 'o' && reader->line[1] == 'k')
- hint->status = REF_STATUS_OK;
- else
+ if (!strcmp(head, "ng")) {
hint->status = REF_STATUS_REMOTE_REJECT;
- hint->remote_status = xstrdup_or_null(msg);
- /* start our next search from the next ref */
- hint = hint->next;
+ if (p)
+ hint->remote_status = xstrdup(p);
+ else
+ hint->remote_status = "failed";
+ } else {
+ hint->status = REF_STATUS_OK;
+ hint->remote_status = xstrdup_or_null(p);
+ new_report = 1;
+ }
}
return ret;
}
@@ -244,7 +303,12 @@ static int check_to_send_update(const struct ref *ref, const struct send_pack_ar
return CHECK_REF_STATUS_REJECTED;
case REF_STATUS_UPTODATE:
return CHECK_REF_UPTODATE;
+
default:
+ case REF_STATUS_EXPECTING_REPORT:
+ /* already passed checks on the local side */
+ case REF_STATUS_OK:
+ /* of course this is OK */
return 0;
}
}
@@ -371,7 +435,9 @@ int send_pack(struct send_pack_args *args,
struct packet_reader reader;
/* Does the other end support the reporting? */
- if (server_supports("report-status"))
+ if (server_supports("report-status-v2"))
+ status_report = 2;
+ else if (server_supports("report-status"))
status_report = 1;
if (server_supports("delete-refs"))
allow_deleting_refs = 1;
@@ -423,8 +489,10 @@ int send_pack(struct send_pack_args *args,
use_push_options = push_options_supported && args->push_options;
- if (status_report)
+ if (status_report == 1)
strbuf_addstr(&cap_buf, " report-status");
+ else if (status_report == 2)
+ strbuf_addstr(&cap_buf, " report-status-v2");
if (use_sideband)
strbuf_addstr(&cap_buf, " side-band-64k");
if (quiet_supported && (args->quiet || !args->progress))
@@ -447,13 +515,6 @@ int send_pack(struct send_pack_args *args,
if (ref->deletion && !allow_deleting_refs)
ref->status = REF_STATUS_REJECT_NODELETE;
- if (!args->dry_run)
- advertise_shallow_grafts_buf(&req_buf);
-
- if (!args->dry_run && push_cert_nonce)
- cmds_sent = generate_push_cert(&req_buf, remote_refs, args,
- cap_buf.buf, push_cert_nonce);
-
/*
* Clear the status for each ref and see if we need to send
* the pack data.
@@ -489,31 +550,35 @@ int send_pack(struct send_pack_args *args,
ref->status = REF_STATUS_EXPECTING_REPORT;
}
+ if (!args->dry_run)
+ advertise_shallow_grafts_buf(&req_buf);
+
/*
* Finally, tell the other end!
*/
- for (ref = remote_refs; ref; ref = ref->next) {
- char *old_hex, *new_hex;
-
- if (args->dry_run || push_cert_nonce)
- continue;
-
- if (check_to_send_update(ref, args) < 0)
- continue;
-
- old_hex = oid_to_hex(&ref->old_oid);
- new_hex = oid_to_hex(&ref->new_oid);
- if (!cmds_sent) {
- packet_buf_write(&req_buf,
- "%s %s %s%c%s",
- old_hex, new_hex, ref->name, 0,
- cap_buf.buf);
- cmds_sent = 1;
- } else {
- packet_buf_write(&req_buf, "%s %s %s",
- old_hex, new_hex, ref->name);
+ if (!args->dry_run && push_cert_nonce)
+ cmds_sent = generate_push_cert(&req_buf, remote_refs, args,
+ cap_buf.buf, push_cert_nonce);
+ else if (!args->dry_run)
+ for (ref = remote_refs; ref; ref = ref->next) {
+ char *old_hex, *new_hex;
+
+ if (check_to_send_update(ref, args) < 0)
+ continue;
+
+ old_hex = oid_to_hex(&ref->old_oid);
+ new_hex = oid_to_hex(&ref->new_oid);
+ if (!cmds_sent) {
+ packet_buf_write(&req_buf,
+ "%s %s %s%c%s",
+ old_hex, new_hex, ref->name, 0,
+ cap_buf.buf);
+ cmds_sent = 1;
+ } else {
+ packet_buf_write(&req_buf, "%s %s %s",
+ old_hex, new_hex, ref->name);
+ }
}
- }
if (use_push_options) {
struct string_list_item *item;
diff --git a/sequencer.c b/sequencer.c
index e8676e9..3367eb5 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -120,7 +120,7 @@ static GIT_PATH_FUNC(rebase_path_author_script, "rebase-merge/author-script")
static GIT_PATH_FUNC(rebase_path_amend, "rebase-merge/amend")
/*
* When we stop at a given patch via the "edit" command, this file contains
- * the abbreviated commit name of the corresponding patch.
+ * the commit object name of the corresponding patch.
*/
static GIT_PATH_FUNC(rebase_path_stopped_sha, "rebase-merge/stopped-sha")
/*
@@ -3111,11 +3111,12 @@ static int make_patch(struct repository *r,
{
struct strbuf buf = STRBUF_INIT;
struct rev_info log_tree_opt;
- const char *subject, *p;
+ const char *subject;
+ char hex[GIT_MAX_HEXSZ + 1];
int res = 0;
- p = short_commit_name(commit);
- if (write_message(p, strlen(p), rebase_path_stopped_sha(), 1) < 0)
+ oid_to_hex_r(hex, &commit->object.oid);
+ if (write_message(hex, strlen(hex), rebase_path_stopped_sha(), 1) < 0)
return -1;
res |= write_rebase_head(&commit->object.oid);
@@ -4527,7 +4528,7 @@ int sequencer_continue(struct repository *r, struct replay_opts *opts)
if (read_oneliner(&buf, rebase_path_stopped_sha(),
READ_ONELINER_SKIP_IF_EMPTY) &&
- !get_oid_committish(buf.buf, &oid))
+ !get_oid_hex(buf.buf, &oid))
record_in_rewritten(&oid, peek_command(&todo_list, 0));
strbuf_release(&buf);
}
diff --git a/shortlog.h b/shortlog.h
index 2fa61c4..64be879 100644
--- a/shortlog.h
+++ b/shortlog.h
@@ -15,7 +15,13 @@ struct shortlog {
int in2;
int user_format;
int abbrev;
- int committer;
+
+ enum {
+ SHORTLOG_GROUP_AUTHOR = (1 << 0),
+ SHORTLOG_GROUP_COMMITTER = (1 << 1),
+ SHORTLOG_GROUP_TRAILER = (1 << 2),
+ } groups;
+ struct string_list trailers;
char *common_repo_prefix;
int email;
diff --git a/submodule.c b/submodule.c
index 543b112..b3bb59f 100644
--- a/submodule.c
+++ b/submodule.c
@@ -865,7 +865,8 @@ static void collect_changed_submodules(struct repository *r,
diff_rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
diff_rev.diffopt.format_callback = collect_changed_submodules_cb;
diff_rev.diffopt.format_callback_data = &data;
- diff_tree_combined_merge(commit, 1, &diff_rev);
+ diff_rev.dense_combined_merges = 1;
+ diff_tree_combined_merge(commit, &diff_rev);
}
reset_revision_walk();
diff --git a/t/helper/test-bloom.c b/t/helper/test-bloom.c
index 5e77d56..46e97b0 100644
--- a/t/helper/test-bloom.c
+++ b/t/helper/test-bloom.c
@@ -39,7 +39,9 @@ static void get_bloom_filter_for_commit(const struct object_id *commit_oid)
struct bloom_filter *filter;
setup_git_directory();
c = lookup_commit(the_repository, commit_oid);
- filter = get_bloom_filter(the_repository, c, 1);
+ filter = get_or_compute_bloom_filter(the_repository, c, 1,
+ &settings,
+ NULL);
print_bloom_filter(filter);
}
diff --git a/t/helper/test-proc-receive.c b/t/helper/test-proc-receive.c
new file mode 100644
index 0000000..42164d9
--- /dev/null
+++ b/t/helper/test-proc-receive.c
@@ -0,0 +1,176 @@
+#include "cache.h"
+#include "connect.h"
+#include "parse-options.h"
+#include "pkt-line.h"
+#include "sigchain.h"
+#include "test-tool.h"
+
+static const char *proc_receive_usage[] = {
+ "test-tool proc-receive [<options>...]",
+ NULL
+};
+
+static int die_version;
+static int die_readline;
+static int no_push_options;
+static int use_atomic;
+static int use_push_options;
+static int verbose;
+static int version = 1;
+static struct string_list returns = STRING_LIST_INIT_NODUP;
+
+struct command {
+ struct command *next;
+ const char *error_string;
+ unsigned int skip_update:1,
+ did_not_exist:1;
+ int index;
+ struct object_id old_oid;
+ struct object_id new_oid;
+ char ref_name[FLEX_ARRAY]; /* more */
+};
+
+static void proc_receive_verison(struct packet_reader *reader) {
+ int server_version = 0;
+
+ for (;;) {
+ int linelen;
+
+ if (packet_reader_read(reader) != PACKET_READ_NORMAL)
+ break;
+
+ if (reader->pktlen > 8 && starts_with(reader->line, "version=")) {
+ server_version = atoi(reader->line+8);
+ linelen = strlen(reader->line);
+ if (linelen < reader->pktlen) {
+ const char *feature_list = reader->line + linelen + 1;
+ if (parse_feature_request(feature_list, "atomic"))
+ use_atomic= 1;
+ if (parse_feature_request(feature_list, "push-options"))
+ use_push_options = 1;
+ }
+ }
+ }
+
+ if (server_version != 1 || die_version)
+ die("bad protocol version: %d", server_version);
+
+ packet_write_fmt(1, "version=%d%c%s\n",
+ version, '\0',
+ use_push_options && !no_push_options ? "push-options": "");
+ packet_flush(1);
+}
+
+static void proc_receive_read_commands(struct packet_reader *reader,
+ struct command **commands)
+{
+ struct command **tail = commands;
+
+ for (;;) {
+ struct object_id old_oid, new_oid;
+ struct command *cmd;
+ const char *refname;
+ const char *p;
+
+ if (packet_reader_read(reader) != PACKET_READ_NORMAL)
+ break;
+
+ if (parse_oid_hex(reader->line, &old_oid, &p) ||
+ *p++ != ' ' ||
+ parse_oid_hex(p, &new_oid, &p) ||
+ *p++ != ' ' ||
+ die_readline)
+ die("protocol error: expected 'old new ref', got '%s'",
+ reader->line);
+ refname = p;
+ FLEX_ALLOC_STR(cmd, ref_name, refname);
+ oidcpy(&cmd->old_oid, &old_oid);
+ oidcpy(&cmd->new_oid, &new_oid);
+
+ *tail = cmd;
+ tail = &cmd->next;
+ }
+}
+
+static void proc_receive_read_push_options(struct packet_reader *reader,
+ struct string_list *options)
+{
+
+ if (no_push_options || !use_push_options)
+ return;
+
+ while (1) {
+ if (packet_reader_read(reader) != PACKET_READ_NORMAL)
+ break;
+
+ string_list_append(options, reader->line);
+ }
+}
+
+int cmd__proc_receive(int argc, const char **argv)
+{
+ int nongit_ok = 0;
+ struct packet_reader reader;
+ struct command *commands = NULL;
+ struct string_list push_options = STRING_LIST_INIT_DUP;
+ struct string_list_item *item;
+ struct option options[] = {
+ OPT_BOOL(0, "no-push-options", &no_push_options,
+ "disable push options"),
+ OPT_BOOL(0, "die-version", &die_version,
+ "die during version negotiation"),
+ OPT_BOOL(0, "die-readline", &die_readline,
+ "die when readline"),
+ OPT_STRING_LIST('r', "return", &returns, "old/new/ref/status/msg",
+ "return of results"),
+ OPT__VERBOSE(&verbose, "be verbose"),
+ OPT_INTEGER('V', "version", &version,
+ "use this protocol version number"),
+ OPT_END()
+ };
+
+ setup_git_directory_gently(&nongit_ok);
+
+ argc = parse_options(argc, argv, "test-tools", options, proc_receive_usage, 0);
+ if (argc > 0)
+ usage_msg_opt("Too many arguments.", proc_receive_usage, options);
+ packet_reader_init(&reader, 0, NULL, 0,
+ PACKET_READ_CHOMP_NEWLINE |
+ PACKET_READ_DIE_ON_ERR_PACKET);
+
+ sigchain_push(SIGPIPE, SIG_IGN);
+ proc_receive_verison(&reader);
+ proc_receive_read_commands(&reader, &commands);
+ proc_receive_read_push_options(&reader, &push_options);
+
+ if (verbose) {
+ struct command *cmd;
+
+ if (use_push_options || use_atomic)
+ fprintf(stderr, "proc-receive:%s%s\n",
+ use_atomic? " atomic": "",
+ use_push_options ? " push_options": "");
+
+ for (cmd = commands; cmd; cmd = cmd->next)
+ fprintf(stderr, "proc-receive< %s %s %s\n",
+ oid_to_hex(&cmd->old_oid),
+ oid_to_hex(&cmd->new_oid),
+ cmd->ref_name);
+
+ if (push_options.nr > 0)
+ for_each_string_list_item(item, &push_options)
+ fprintf(stderr, "proc-receive< %s\n", item->string);
+
+ if (returns.nr)
+ for_each_string_list_item(item, &returns)
+ fprintf(stderr, "proc-receive> %s\n", item->string);
+ }
+
+ if (returns.nr)
+ for_each_string_list_item(item, &returns)
+ packet_write_fmt(1, "%s\n", item->string);
+ packet_flush(1);
+ sigchain_pop(SIGPIPE);
+
+ return 0;
+}
diff --git a/t/helper/test-reach.c b/t/helper/test-reach.c
index 14a3655..cda804e 100644
--- a/t/helper/test-reach.c
+++ b/t/helper/test-reach.c
@@ -107,6 +107,8 @@ int cmd__reach(int ac, const char **av)
printf("%s(A,B):%d\n", av[1], ref_newer(&oid_A, &oid_B));
else if (!strcmp(av[1], "in_merge_bases"))
printf("%s(A,B):%d\n", av[1], in_merge_bases(A, B));
+ else if (!strcmp(av[1], "in_merge_bases_many"))
+ printf("%s(A,X):%d\n", av[1], in_merge_bases_many(A, X_nr, X_array));
else if (!strcmp(av[1], "is_descendant_of"))
printf("%s(A,X):%d\n", av[1], repo_is_descendant_of(r, A, X));
else if (!strcmp(av[1], "get_merge_bases_many")) {
diff --git a/t/helper/test-read-graph.c b/t/helper/test-read-graph.c
index 6d0c962..5f585a1 100644
--- a/t/helper/test-read-graph.c
+++ b/t/helper/test-read-graph.c
@@ -12,11 +12,12 @@ int cmd__read_graph(int argc, const char **argv)
setup_git_directory();
odb = the_repository->objects->odb;
+ prepare_repo_settings(the_repository);
+
graph = read_commit_graph_one(the_repository, odb);
if (!graph)
return 1;
-
printf("header: %08x %d %d %d %d\n",
ntohl(*(uint32_t*)graph->data),
*(unsigned char*)(graph->data + 4),
diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
index 590b2ef..a0d3966 100644
--- a/t/helper/test-tool.c
+++ b/t/helper/test-tool.c
@@ -46,6 +46,7 @@ static struct test_cmd cmds[] = {
{ "path-utils", cmd__path_utils },
{ "pkt-line", cmd__pkt_line },
{ "prio-queue", cmd__prio_queue },
+ { "proc-receive", cmd__proc_receive},
{ "progress", cmd__progress },
{ "reach", cmd__reach },
{ "read-cache", cmd__read_cache },
diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h
index ddc8e99..07034d3 100644
--- a/t/helper/test-tool.h
+++ b/t/helper/test-tool.h
@@ -35,6 +35,7 @@ int cmd__parse_pathspec_file(int argc, const char** argv);
int cmd__path_utils(int argc, const char **argv);
int cmd__pkt_line(int argc, const char **argv);
int cmd__prio_queue(int argc, const char **argv);
+int cmd__proc_receive(int argc, const char **argv);
int cmd__progress(int argc, const char **argv);
int cmd__reach(int argc, const char **argv);
int cmd__read_cache(int argc, const char **argv);
diff --git a/t/t0095-bloom.sh b/t/t0095-bloom.sh
index 232ba2c..7e4ab17 100755
--- a/t/t0095-bloom.sh
+++ b/t/t0095-bloom.sh
@@ -71,8 +71,8 @@ test_expect_success 'get bloom filters for commit with no changes' '
git init &&
git commit --allow-empty -m "c0" &&
cat >expect <<-\EOF &&
- Filter_Length:0
- Filter_Data:
+ Filter_Length:1
+ Filter_Data:00|
EOF
test-tool bloom get_filter_for_commit "$(git rev-parse HEAD)" >actual &&
test_cmp expect actual
@@ -107,8 +107,8 @@ test_expect_success EXPENSIVE 'get bloom filter for commit with 513 changes' '
git add bigDir &&
git commit -m "commit with 513 changes" &&
cat >expect <<-\EOF &&
- Filter_Length:0
- Filter_Data:
+ Filter_Length:1
+ Filter_Data:ff|
EOF
test-tool bloom get_filter_for_commit "$(git rev-parse HEAD)" >actual &&
test_cmp expect actual
diff --git a/t/t1506-rev-parse-diagnosis.sh b/t/t1506-rev-parse-diagnosis.sh
index dbf690b..3e657e6 100755
--- a/t/t1506-rev-parse-diagnosis.sh
+++ b/t/t1506-rev-parse-diagnosis.sh
@@ -190,6 +190,24 @@ test_expect_success 'dotdot is not an empty set' '
test_cmp expect actual
'
+test_expect_success 'dotdot does not peel endpoints' '
+ git tag -a -m "annote" annotated HEAD &&
+ A=$(git rev-parse annotated) &&
+ H=$(git rev-parse annotated^0) &&
+ {
+ echo $A && echo ^$A
+ } >expect-with-two-dots &&
+ {
+ echo $A && echo $A && echo ^$H
+ } >expect-with-merge-base &&
+
+ git rev-parse annotated..annotated >actual-with-two-dots &&
+ test_cmp expect-with-two-dots actual-with-two-dots &&
+
+ git rev-parse annotated...annotated >actual-with-merge-base &&
+ test_cmp expect-with-merge-base actual-with-merge-base
+'
+
test_expect_success 'arg before dashdash must be a revision (missing)' '
test_must_fail git rev-parse foobar -- 2>stderr &&
test_i18ngrep "bad revision" stderr
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index c24c663..6efe7a4 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -234,10 +234,10 @@ test_expect_success 'git branch -M master master should work when master is chec
git branch -M master master
'
-test_expect_success 'git branch -M master2 master2 should work when master is checked out' '
+test_expect_success 'git branch -M topic topic should work when master is checked out' '
git checkout master &&
- git branch master2 &&
- git branch -M master2 master2
+ git branch topic &&
+ git branch -M topic topic
'
test_expect_success 'git branch -v -d t should work' '
@@ -324,8 +324,8 @@ test_expect_success 'git branch --list -v with --abbrev' '
test_expect_success 'git branch --column' '
COLUMNS=81 git branch --column=column >actual &&
cat >expect <<\EOF &&
- a/b/c bam foo l * master mb o/o q
- abc bar j/k m/m master2 n o/p r
+ a/b/c bam foo l * master n o/p r
+ abc bar j/k m/m mb o/o q topic
EOF
test_cmp expect actual
'
@@ -346,13 +346,13 @@ test_expect_success 'git branch --column with an extremely long branch name' '
l
m/m
* master
- master2
mb
n
o/o
o/p
q
r
+ topic
$long
EOF
test_cmp expect actual
@@ -365,8 +365,8 @@ test_expect_success 'git branch with column.*' '
git config --unset column.branch &&
git config --unset column.ui &&
cat >expect <<\EOF &&
- a/b/c bam foo l * master mb o/o q
- abc bar j/k m/m master2 n o/p r
+ a/b/c bam foo l * master n o/p r
+ abc bar j/k m/m mb o/o q topic
EOF
test_cmp expect actual
'
@@ -377,7 +377,7 @@ test_expect_success 'git branch --column -v should fail' '
test_expect_success 'git branch -v with column.ui ignored' '
git config column.ui column &&
- COLUMNS=80 git branch -v | cut -c -10 | sed "s/ *$//" >actual &&
+ COLUMNS=80 git branch -v | cut -c -9 | sed "s/ *$//" >actual &&
git config --unset column.ui &&
cat >expect <<\EOF &&
a/b/c
@@ -389,13 +389,13 @@ test_expect_success 'git branch -v with column.ui ignored' '
l
m/m
* master
- master2
mb
n
o/o
o/p
q
r
+ topic
EOF
test_cmp expect actual
'
@@ -597,10 +597,10 @@ test_expect_success 'git branch -C master master should work when master is chec
git branch -C master master
'
-test_expect_success 'git branch -C master5 master5 should work when master is checked out' '
+test_expect_success 'git branch -C main5 main5 should work when master is checked out' '
git checkout master &&
- git branch master5 &&
- git branch -C master5 master5
+ git branch main5 &&
+ git branch -C main5 main5
'
test_expect_success 'git branch -C ab cd should overwrite existing config for cd' '
@@ -711,11 +711,11 @@ test_expect_success 'deleting a self-referential symref' '
'
test_expect_success 'renaming a symref is not allowed' '
- git symbolic-ref refs/heads/master2 refs/heads/master &&
- test_must_fail git branch -m master2 master3 &&
- git symbolic-ref refs/heads/master2 &&
+ git symbolic-ref refs/heads/topic refs/heads/master &&
+ test_must_fail git branch -m topic new-topic &&
+ git symbolic-ref refs/heads/topic &&
test_path_is_file .git/refs/heads/master &&
- test_path_is_missing .git/refs/heads/master3
+ test_path_is_missing .git/refs/heads/new-topic
'
test_expect_success SYMLINKS 'git branch -m u v should fail when the reflog for u is a symlink' '
diff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh
index e024cff..6eb344b 100755
--- a/t/t3206-range-diff.sh
+++ b/t/t3206-range-diff.sh
@@ -252,17 +252,13 @@ test_expect_success 'changed commit with --stat diff option' '
git range-diff --no-color --stat topic...changed >actual &&
cat >expect <<-EOF &&
1: $(test_oid t1) = 1: $(test_oid c1) s/5/A/
- a => b | 0
- 1 file changed, 0 insertions(+), 0 deletions(-)
2: $(test_oid t2) = 2: $(test_oid c2) s/4/A/
- a => b | 0
- 1 file changed, 0 insertions(+), 0 deletions(-)
3: $(test_oid t3) ! 3: $(test_oid c3) s/11/B/
- a => b | 0
- 1 file changed, 0 insertions(+), 0 deletions(-)
+ a => b | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
4: $(test_oid t4) ! 4: $(test_oid c4) s/12/B/
- a => b | 0
- 1 file changed, 0 insertions(+), 0 deletions(-)
+ a => b | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
EOF
test_cmp expect actual
'
diff --git a/t/t3427-rebase-subtree.sh b/t/t3427-rebase-subtree.sh
index 79e43a3..2a7d958 100755
--- a/t/t3427-rebase-subtree.sh
+++ b/t/t3427-rebase-subtree.sh
@@ -15,12 +15,12 @@ commit_message() {
# this test script tries to document them. First, the following commit history
# is generated (the onelines are shown, time flows from left to right):
#
-# master1 - master2 - master3
+# topic_1 - topic_2 - topic_3
# \
-# README ---------------------- Add subproject master - master4 - files_subtree/master5
+# README ---------------------- Add subproject master - topic_4 - files_subtree/topic_5
#
# Where the merge moves the files master[123].t into the subdirectory
-# files_subtree/ and master4 as well as files_subtree/master5 add files to that
+# files_subtree/ and topic_4 as well as files_subtree/topic_5 add files to that
# directory directly.
#
# Then, in subsequent test cases, `git filter-branch` is used to distill just
@@ -28,11 +28,11 @@ commit_message() {
# an empty commit is added on top. The pre-rebase commit history looks like
# this:
#
-# Add subproject master - master4 - files_subtree/master5 - Empty commit
+# Add subproject master - topic_4 - files_subtree/topic_5 - Empty commit
#
-# where the root commit adds three files: master1.t, master2.t and master3.t.
+# where the root commit adds three files: topic_1.t, topic_2.t and topic_3.t.
#
-# This commit history is then rebased onto `master3` with the
+# This commit history is then rebased onto `topic_3` with the
# `-Xsubtree=files_subtree` option in three different ways:
#
# 1. using `--preserve-merges`
@@ -43,9 +43,9 @@ test_expect_success 'setup' '
test_commit README &&
git init files &&
- test_commit -C files master1 &&
- test_commit -C files master2 &&
- test_commit -C files master3 &&
+ test_commit -C files topic_1 &&
+ test_commit -C files topic_2 &&
+ test_commit -C files topic_3 &&
: perform subtree merge into files_subtree/ &&
git fetch files refs/heads/master:refs/heads/files-master &&
@@ -55,8 +55,8 @@ test_expect_success 'setup' '
git commit -m "Add subproject master" &&
: add two extra commits to rebase &&
- test_commit -C files_subtree master4 &&
- test_commit files_subtree/master5 &&
+ test_commit -C files_subtree topic_4 &&
+ test_commit files_subtree/topic_5 &&
git checkout -b to-rebase &&
git fast-export --no-data HEAD -- files_subtree/ |
@@ -66,22 +66,22 @@ test_expect_success 'setup' '
git commit -m "Empty commit" --allow-empty
'
-# FAILURE: Does not preserve master4.
+# FAILURE: Does not preserve topic_4.
test_expect_failure REBASE_P 'Rebase -Xsubtree --preserve-merges --onto commit' '
reset_rebase &&
git checkout -b rebase-preserve-merges to-rebase &&
git rebase -Xsubtree=files_subtree --preserve-merges --onto files-master master &&
- verbose test "$(commit_message HEAD~)" = "master4" &&
- verbose test "$(commit_message HEAD)" = "files_subtree/master5"
+ verbose test "$(commit_message HEAD~)" = "topic_4" &&
+ verbose test "$(commit_message HEAD)" = "files_subtree/topic_5"
'
-# FAILURE: Does not preserve master4.
+# FAILURE: Does not preserve topic_4.
test_expect_failure REBASE_P 'Rebase -Xsubtree --keep-empty --preserve-merges --onto commit' '
reset_rebase &&
git checkout -b rebase-keep-empty to-rebase &&
git rebase -Xsubtree=files_subtree --keep-empty --preserve-merges --onto files-master master &&
- verbose test "$(commit_message HEAD~2)" = "master4" &&
- verbose test "$(commit_message HEAD~)" = "files_subtree/master5" &&
+ verbose test "$(commit_message HEAD~2)" = "topic_4" &&
+ verbose test "$(commit_message HEAD~)" = "files_subtree/topic_5" &&
verbose test "$(commit_message HEAD)" = "Empty commit"
'
@@ -91,8 +91,8 @@ test_expect_success 'Rebase -Xsubtree --empty=ask --onto commit' '
test_must_fail git rebase -Xsubtree=files_subtree --empty=ask --onto files-master master &&
: first pick results in no changes &&
git rebase --skip &&
- verbose test "$(commit_message HEAD~2)" = "master4" &&
- verbose test "$(commit_message HEAD~)" = "files_subtree/master5" &&
+ verbose test "$(commit_message HEAD~2)" = "topic_4" &&
+ verbose test "$(commit_message HEAD~)" = "files_subtree/topic_5" &&
verbose test "$(commit_message HEAD)" = "Empty commit"
'
@@ -102,8 +102,8 @@ test_expect_success 'Rebase -Xsubtree --empty=ask --rebase-merges --onto commit'
test_must_fail git rebase -Xsubtree=files_subtree --empty=ask --rebase-merges --onto files-master --root &&
: first pick results in no changes &&
git rebase --skip &&
- verbose test "$(commit_message HEAD~2)" = "master4" &&
- verbose test "$(commit_message HEAD~)" = "files_subtree/master5" &&
+ verbose test "$(commit_message HEAD~2)" = "topic_4" &&
+ verbose test "$(commit_message HEAD~)" = "files_subtree/topic_5" &&
verbose test "$(commit_message HEAD)" = "Empty commit"
'
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index 1da8ab1..3ecbef6 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -465,7 +465,7 @@ test_expect_success 'am changes committer and keeps author' '
test_expect_success 'am --signoff adds Signed-off-by: line' '
rm -fr .git/rebase-apply &&
git reset --hard &&
- git checkout -b master2 first &&
+ git checkout -b topic_2 first &&
git am --signoff <patch2 &&
{
printf "third\n\nSigned-off-by: %s <%s>\n\n" \
@@ -479,7 +479,7 @@ test_expect_success 'am --signoff adds Signed-off-by: line' '
'
test_expect_success 'am stays in branch' '
- echo refs/heads/master2 >expected &&
+ echo refs/heads/topic_2 >expected &&
git symbolic-ref HEAD >actual &&
test_cmp expected actual
'
@@ -540,7 +540,7 @@ test_expect_success 'am without --keep removes Re: and [PATCH] stuff' '
git reset --hard HEAD^ &&
git am <patch4 &&
git rev-parse HEAD >expected &&
- git rev-parse master2 >actual &&
+ git rev-parse topic_2 >actual &&
test_cmp expected actual
'
@@ -567,7 +567,7 @@ test_expect_success 'am --keep-non-patch really keeps the non-patch part' '
test_expect_success 'setup am -3' '
rm -fr .git/rebase-apply &&
git reset --hard &&
- git checkout -b base3way master2 &&
+ git checkout -b base3way topic_2 &&
sed -n -e "3,\$p" msg >file &&
head -n 9 msg >>file &&
git add file &&
diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh
index d3a7ce6..3d5c4a2 100755
--- a/t/t4201-shortlog.sh
+++ b/t/t4201-shortlog.sh
@@ -215,4 +215,145 @@ test_expect_success 'shortlog --committer (external)' '
test_cmp expect actual
'
+test_expect_success '--group=committer is the same as --committer' '
+ git shortlog -ns --group=committer HEAD >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'shortlog --group=trailer:signed-off-by' '
+ git commit --allow-empty -m foo -s &&
+ GIT_COMMITTER_NAME="SOB One" \
+ GIT_COMMITTER_EMAIL=sob@example.com \
+ git commit --allow-empty -m foo -s &&
+ git commit --allow-empty --amend --no-edit -s &&
+ cat >expect <<-\EOF &&
+ 2 C O Mitter <committer@example.com>
+ 1 SOB One <sob@example.com>
+ EOF
+ git shortlog -nse --group=trailer:signed-off-by HEAD >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'trailer idents are split' '
+ cat >expect <<-\EOF &&
+ 2 C O Mitter
+ 1 SOB One
+ EOF
+ git shortlog -ns --group=trailer:signed-off-by HEAD >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'trailer idents are mailmapped' '
+ cat >expect <<-\EOF &&
+ 2 C O Mitter
+ 1 Another Name
+ EOF
+ echo "Another Name <sob@example.com>" >mail.map &&
+ git -c mailmap.file=mail.map shortlog -ns \
+ --group=trailer:signed-off-by HEAD >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'shortlog de-duplicates trailers in a single commit' '
+ git commit --allow-empty -F - <<-\EOF &&
+ subject one
+
+ this message has two distinct values, plus a repeat
+
+ Repeated-trailer: Foo
+ Repeated-trailer: Bar
+ Repeated-trailer: Foo
+ EOF
+
+ git commit --allow-empty -F - <<-\EOF &&
+ subject two
+
+ similar to the previous, but without the second distinct value
+
+ Repeated-trailer: Foo
+ Repeated-trailer: Foo
+ EOF
+
+ cat >expect <<-\EOF &&
+ 2 Foo
+ 1 Bar
+ EOF
+ git shortlog -ns --group=trailer:repeated-trailer -2 HEAD >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'shortlog can match multiple groups' '
+ git commit --allow-empty -F - <<-\EOF &&
+ subject one
+
+ this has two trailers that are distinct from the author; it will count
+ 3 times in the output
+
+ Some-trailer: User A <a@example.com>
+ Another-trailer: User B <b@example.com>
+ EOF
+
+ git commit --allow-empty -F - <<-\EOF &&
+ subject two
+
+ this one has two trailers, one of which is a duplicate with the author;
+ it will only be counted once for them
+
+ Another-trailer: A U Thor <author@example.com>
+ Some-trailer: User B <b@example.com>
+ EOF
+
+ cat >expect <<-\EOF &&
+ 2 A U Thor
+ 2 User B
+ 1 User A
+ EOF
+ git shortlog -ns \
+ --group=author \
+ --group=trailer:some-trailer \
+ --group=trailer:another-trailer \
+ -2 HEAD >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'set up option selection tests' '
+ git commit --allow-empty -F - <<-\EOF
+ subject
+
+ body
+
+ Trailer-one: value-one
+ Trailer-two: value-two
+ EOF
+'
+
+test_expect_success '--no-group resets group list to author' '
+ cat >expect <<-\EOF &&
+ 1 A U Thor
+ EOF
+ git shortlog -ns \
+ --group=committer \
+ --group=trailer:trailer-one \
+ --no-group \
+ -1 HEAD >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--no-group resets trailer list' '
+ cat >expect <<-\EOF &&
+ 1 value-two
+ EOF
+ git shortlog -ns \
+ --group=trailer:trailer-one \
+ --no-group \
+ --group=trailer:trailer-two \
+ -1 HEAD >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin with multiple groups reports error' '
+ git log >log &&
+ test_must_fail git shortlog --group=author --group=committer <log
+'
+
test_done
diff --git a/t/t4216-log-bloom.sh b/t/t4216-log-bloom.sh
index 4bb9e9d..d11040c 100755
--- a/t/t4216-log-bloom.sh
+++ b/t/t4216-log-bloom.sh
@@ -30,6 +30,7 @@ test_expect_success 'setup test - repo, commits, commit graph, log outputs' '
rm file_to_be_deleted &&
git add . &&
git commit -m "file removed" &&
+ git commit --allow-empty -m "empty" &&
git commit-graph write --reachable --changed-paths &&
test_oid_cache <<-EOF
@@ -37,6 +38,7 @@ test_expect_success 'setup test - repo, commits, commit graph, log outputs' '
oid_version sha256:2
EOF
'
+
graph_read_expect () {
NUM_CHUNKS=5
cat >expect <<- EOF
@@ -49,7 +51,7 @@ graph_read_expect () {
}
test_expect_success 'commit-graph write wrote out the bloom chunks' '
- graph_read_expect 15
+ graph_read_expect 16
'
# Turn off any inherited trace2 settings for this test.
@@ -58,14 +60,14 @@ sane_unset GIT_TRACE2_PERF_BRIEF
sane_unset GIT_TRACE2_CONFIG_PARAMS
setup () {
- rm "$TRASH_DIRECTORY/trace.perf"
+ rm -f "$TRASH_DIRECTORY/trace.perf" &&
git -c core.commitGraph=false log --pretty="format:%s" $1 >log_wo_bloom &&
GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.perf" git -c core.commitGraph=true log --pretty="format:%s" $1 >log_w_bloom
}
test_bloom_filters_used () {
log_args=$1
- bloom_trace_prefix="statistics:{\"filter_not_present\":0,\"maybe\""
+ bloom_trace_prefix="statistics:{\"filter_not_present\":${2:-0},\"maybe\""
setup "$log_args" &&
grep -q "$bloom_trace_prefix" "$TRASH_DIRECTORY/trace.perf" &&
test_cmp log_wo_bloom log_w_bloom &&
@@ -95,7 +97,9 @@ do
"--ancestry-path side..master"
do
test_expect_success "git log option: $option for path: $path" '
- test_bloom_filters_used "$option -- $path"
+ test_bloom_filters_used "$option -- $path" &&
+ test_config commitgraph.readChangedPaths false &&
+ test_bloom_filters_not_used "$option -- $path"
'
done
done
@@ -139,8 +143,11 @@ test_expect_success 'setup - add commit-graph to the chain without Bloom filters
test_line_count = 2 .git/objects/info/commit-graphs/commit-graph-chain
'
-test_expect_success 'Do not use Bloom filters if the latest graph does not have Bloom filters.' '
- test_bloom_filters_not_used "-- A/B"
+test_expect_success 'use Bloom filters even if the latest graph does not have Bloom filters' '
+ # Ensure that the number of empty filters is equal to the number of
+ # filters in the latest graph layer to prove that they are loaded (and
+ # ignored).
+ test_bloom_filters_used "-- A/B" 3
'
test_expect_success 'setup - add commit-graph to the chain with Bloom filters' '
@@ -151,7 +158,7 @@ test_expect_success 'setup - add commit-graph to the chain with Bloom filters' '
test_bloom_filters_used_when_some_filters_are_missing () {
log_args=$1
- bloom_trace_prefix="statistics:{\"filter_not_present\":3,\"maybe\":6,\"definitely_not\":8"
+ bloom_trace_prefix="statistics:{\"filter_not_present\":3,\"maybe\":6,\"definitely_not\":9"
setup "$log_args" &&
grep -q "$bloom_trace_prefix" "$TRASH_DIRECTORY/trace.perf" &&
test_cmp log_wo_bloom log_w_bloom
@@ -169,31 +176,230 @@ test_expect_success 'persist filter settings' '
GIT_TEST_BLOOM_SETTINGS_NUM_HASHES=9 \
GIT_TEST_BLOOM_SETTINGS_BITS_PER_ENTRY=15 \
git commit-graph write --reachable --changed-paths &&
- grep "{\"hash_version\":1,\"num_hashes\":9,\"bits_per_entry\":15}" trace2.txt &&
+ grep "{\"hash_version\":1,\"num_hashes\":9,\"bits_per_entry\":15,\"max_changed_paths\":512" trace2.txt &&
GIT_TRACE2_EVENT="$(pwd)/trace2-auto.txt" \
GIT_TRACE2_EVENT_NESTING=5 \
git commit-graph write --reachable --changed-paths &&
- grep "{\"hash_version\":1,\"num_hashes\":9,\"bits_per_entry\":15}" trace2-auto.txt
+ grep "{\"hash_version\":1,\"num_hashes\":9,\"bits_per_entry\":15,\"max_changed_paths\":512" trace2-auto.txt
'
+test_max_changed_paths () {
+ grep "\"max_changed_paths\":$1" $2
+}
+
+test_filter_not_computed () {
+ grep "\"key\":\"filter-not-computed\",\"value\":\"$1\"" $2
+}
+
+test_filter_computed () {
+ grep "\"key\":\"filter-computed\",\"value\":\"$1\"" $2
+}
+
+test_filter_trunc_empty () {
+ grep "\"key\":\"filter-trunc-empty\",\"value\":\"$1\"" $2
+}
+
+test_filter_trunc_large () {
+ grep "\"key\":\"filter-trunc-large\",\"value\":\"$1\"" $2
+}
+
test_expect_success 'correctly report changes over limit' '
- git init 513changes &&
+ git init limits &&
(
- cd 513changes &&
- for i in $(test_seq 1 513)
+ cd limits &&
+ mkdir d &&
+ mkdir d/e &&
+
+ for i in $(test_seq 1 2)
do
- echo $i >file$i.txt || return 1
+ printf $i >d/file$i.txt &&
+ printf $i >d/e/file$i.txt || return 1
done &&
- git add . &&
+
+ mkdir mode &&
+ printf bash >mode/script.sh &&
+
+ mkdir foo &&
+ touch foo/bar &&
+ touch foo.txt &&
+
+ git add d foo foo.txt mode &&
git commit -m "files" &&
- git commit-graph write --reachable --changed-paths &&
- for i in $(test_seq 1 513)
+
+ # Commit has 7 file and 4 directory adds
+ GIT_TEST_BLOOM_SETTINGS_MAX_CHANGED_PATHS=10 \
+ GIT_TRACE2_EVENT="$(pwd)/trace" \
+ git commit-graph write --reachable --changed-paths &&
+ test_max_changed_paths 10 trace &&
+ test_filter_computed 1 trace &&
+ test_filter_trunc_large 1 trace &&
+
+ for path in $(git ls-tree -r --name-only HEAD)
+ do
+ git -c commitGraph.readChangedPaths=false log \
+ -- $path >expect &&
+ git log -- $path >actual &&
+ test_cmp expect actual || return 1
+ done &&
+
+ # Make a variety of path changes
+ printf new1 >d/e/file1.txt &&
+ printf new2 >d/file2.txt &&
+ rm d/e/file2.txt &&
+ rm -r foo &&
+ printf text >foo &&
+ mkdir f &&
+ printf new1 >f/file1.txt &&
+
+ # including a mode-only change (counts as modified)
+ git update-index --chmod=+x mode/script.sh &&
+
+ git add foo d f &&
+ git commit -m "complicated" &&
+
+ # start from scratch and rebuild
+ rm -f .git/objects/info/commit-graph &&
+ GIT_TEST_BLOOM_SETTINGS_MAX_CHANGED_PATHS=10 \
+ GIT_TRACE2_EVENT="$(pwd)/trace-edit" \
+ git commit-graph write --reachable --changed-paths &&
+ test_max_changed_paths 10 trace-edit &&
+ test_filter_computed 2 trace-edit &&
+ test_filter_trunc_large 2 trace-edit &&
+
+ for path in $(git ls-tree -r --name-only HEAD)
+ do
+ git -c commitGraph.readChangedPaths=false log \
+ -- $path >expect &&
+ git log -- $path >actual &&
+ test_cmp expect actual || return 1
+ done &&
+
+ # start from scratch and rebuild
+ rm -f .git/objects/info/commit-graph &&
+ GIT_TEST_BLOOM_SETTINGS_MAX_CHANGED_PATHS=11 \
+ GIT_TRACE2_EVENT="$(pwd)/trace-update" \
+ git commit-graph write --reachable --changed-paths &&
+ test_max_changed_paths 11 trace-update &&
+ test_filter_computed 2 trace-update &&
+ test_filter_trunc_large 0 trace-update &&
+
+ for path in $(git ls-tree -r --name-only HEAD)
do
- git -c core.commitGraph=false log -- file$i.txt >expect &&
- git log -- file$i.txt >actual &&
+ git -c commitGraph.readChangedPaths=false log \
+ -- $path >expect &&
+ git log -- $path >actual &&
test_cmp expect actual || return 1
done
)
'
+test_expect_success 'correctly report commits with no changed paths' '
+ git init empty &&
+ test_when_finished "rm -fr empty" &&
+ (
+ cd empty &&
+
+ git commit --allow-empty -m "initial commit" &&
+
+ GIT_TRACE2_EVENT="$(pwd)/trace.event" \
+ git commit-graph write --reachable --changed-paths &&
+ test_filter_computed 1 trace.event &&
+ test_filter_not_computed 0 trace.event &&
+ test_filter_trunc_empty 1 trace.event &&
+ test_filter_trunc_large 0 trace.event
+ )
+'
+
+test_expect_success 'Bloom generation is limited by --max-new-filters' '
+ (
+ cd limits &&
+ test_commit c2 filter &&
+ test_commit c3 filter &&
+ test_commit c4 no-filter &&
+
+ rm -f trace.event &&
+ GIT_TRACE2_EVENT="$(pwd)/trace.event" \
+ git commit-graph write --reachable --split=replace \
+ --changed-paths --max-new-filters=2 &&
+
+ test_filter_computed 2 trace.event &&
+ test_filter_not_computed 3 trace.event &&
+ test_filter_trunc_empty 0 trace.event &&
+ test_filter_trunc_large 0 trace.event
+ )
+'
+
+test_expect_success 'Bloom generation backfills previously-skipped filters' '
+ # Check specifying commitGraph.maxNewFilters over "git config" works.
+ test_config -C limits commitGraph.maxNewFilters 1 &&
+ (
+ cd limits &&
+
+ rm -f trace.event &&
+ GIT_TRACE2_EVENT="$(pwd)/trace.event" \
+ git commit-graph write --reachable --changed-paths \
+ --split=replace &&
+ test_filter_computed 1 trace.event &&
+ test_filter_not_computed 4 trace.event &&
+ test_filter_trunc_empty 0 trace.event &&
+ test_filter_trunc_large 0 trace.event
+ )
+'
+
+test_expect_success '--max-new-filters overrides configuration' '
+ git init override &&
+ test_when_finished "rm -fr override" &&
+ test_config -C override commitGraph.maxNewFilters 2 &&
+ (
+ cd override &&
+ test_commit one &&
+ test_commit two &&
+
+ rm -f trace.event &&
+ GIT_TRACE2_EVENT="$(pwd)/trace.event" \
+ git commit-graph write --reachable --changed-paths \
+ --max-new-filters=1 &&
+ test_filter_computed 1 trace.event &&
+ test_filter_not_computed 1 trace.event &&
+ test_filter_trunc_empty 0 trace.event &&
+ test_filter_trunc_large 0 trace.event
+ )
+'
+
+test_expect_success 'Bloom generation backfills empty commits' '
+ git init empty &&
+ test_when_finished "rm -fr empty" &&
+ (
+ cd empty &&
+ for i in $(test_seq 1 6)
+ do
+ git commit --allow-empty -m "$i"
+ done &&
+
+ # Generate Bloom filters for empty commits 1-6, two at a time.
+ for i in $(test_seq 1 3)
+ do
+ rm -f trace.event &&
+ GIT_TRACE2_EVENT="$(pwd)/trace.event" \
+ git commit-graph write --reachable \
+ --changed-paths --max-new-filters=2 &&
+ test_filter_computed 2 trace.event &&
+ test_filter_not_computed 4 trace.event &&
+ test_filter_trunc_empty 2 trace.event &&
+ test_filter_trunc_large 0 trace.event
+ done &&
+
+ # Finally, make sure that once all commits have filters, that
+ # none are subsequently recomputed.
+ rm -f trace.event &&
+ GIT_TRACE2_EVENT="$(pwd)/trace.event" \
+ git commit-graph write --reachable \
+ --changed-paths --max-new-filters=2 &&
+ test_filter_computed 0 trace.event &&
+ test_filter_not_computed 6 trace.event &&
+ test_filter_trunc_empty 0 trace.event &&
+ test_filter_trunc_large 0 trace.event
+ )
+'
+
test_done
diff --git a/t/t5324-split-commit-graph.sh b/t/t5324-split-commit-graph.sh
index 1821646..c334ee9 100755
--- a/t/t5324-split-commit-graph.sh
+++ b/t/t5324-split-commit-graph.sh
@@ -427,4 +427,17 @@ done <<\EOF
0600 -r--------
EOF
+test_expect_success '--split=replace with partial Bloom data' '
+ rm -rf $graphdir $infodir/commit-graph &&
+ git reset --hard commits/3 &&
+ git rev-list -1 HEAD~2 >a &&
+ git rev-list -1 HEAD~1 >b &&
+ git commit-graph write --split=no-merge --stdin-commits --changed-paths <a &&
+ git commit-graph write --split=no-merge --stdin-commits <b &&
+ git commit-graph write --split=replace --stdin-commits --changed-paths <c &&
+ ls $graphdir/graph-*.graph >graph-files &&
+ test_line_count = 1 graph-files &&
+ verify_chain_files_exist $graphdir
+'
+
test_done
diff --git a/t/t5411-proc-receive-hook.sh b/t/t5411-proc-receive-hook.sh
new file mode 100755
index 0000000..7464872
--- /dev/null
+++ b/t/t5411-proc-receive-hook.sh
@@ -0,0 +1,117 @@
+#!/bin/sh
+#
+# Copyright (c) 2020 Jiang Xin
+#
+
+test_description='Test proc-receive hook'
+
+. ./test-lib.sh
+
+. "$TEST_DIRECTORY"/t5411/common-functions.sh
+
+setup_upstream_and_workbench () {
+ # Refs of upstream : master(A)
+ # Refs of workbench: master(A) tags/v123
+ test_expect_success "setup upstream and workbench" '
+ rm -rf upstream.git &&
+ rm -rf workbench &&
+ git init --bare upstream.git &&
+ git init workbench &&
+ create_commits_in workbench A B &&
+ (
+ cd workbench &&
+ # Try to make a stable fixed width for abbreviated commit ID,
+ # this fixed-width oid will be replaced with "<OID>".
+ git config core.abbrev 7 &&
+ git tag -m "v123" v123 $A &&
+ git remote add origin ../upstream.git &&
+ git push origin master &&
+ git update-ref refs/heads/master $A $B &&
+ git -C ../upstream.git update-ref \
+ refs/heads/master $A $B
+ ) &&
+ TAG=$(git -C workbench rev-parse v123) &&
+
+ # setup pre-receive hook
+ write_script upstream.git/hooks/pre-receive <<-\EOF &&
+ exec >&2
+ echo "# pre-receive hook"
+ while read old new ref
+ do
+ echo "pre-receive< $old $new $ref"
+ done
+ EOF
+
+ # setup post-receive hook
+ write_script upstream.git/hooks/post-receive <<-\EOF &&
+ exec >&2
+ echo "# post-receive hook"
+ while read old new ref
+ do
+ echo "post-receive< $old $new $ref"
+ done
+ EOF
+
+ upstream=upstream.git
+ '
+}
+
+run_proc_receive_hook_test() {
+ case $1 in
+ http)
+ PROTOCOL="HTTP protocol"
+ URL_PREFIX="http://.*"
+ ;;
+ local)
+ PROTOCOL="builtin protocol"
+ URL_PREFIX="\.\."
+ ;;
+ esac
+
+ # Include test cases for both file and HTTP protocol
+ for t in "$TEST_DIRECTORY"/t5411/test-*.sh
+ do
+ . "$t"
+ done
+}
+
+# Initialize the upstream repository and local workbench.
+setup_upstream_and_workbench
+
+# Load test cases that only need to be executed once.
+for t in "$TEST_DIRECTORY"/t5411/once-*.sh
+do
+ . "$t"
+done
+
+# Initialize the upstream repository and local workbench.
+setup_upstream_and_workbench
+
+# Run test cases for 'proc-receive' hook on local file protocol.
+run_proc_receive_hook_test local
+
+ROOT_PATH="$PWD"
+. "$TEST_DIRECTORY"/lib-gpg.sh
+. "$TEST_DIRECTORY"/lib-httpd.sh
+. "$TEST_DIRECTORY"/lib-terminal.sh
+start_httpd
+
+# Re-initialize the upstream repository and local workbench.
+setup_upstream_and_workbench
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+test_expect_success "setup for HTTP protocol" '
+ git -C upstream.git config http.receivepack true &&
+ upstream="$HTTPD_DOCUMENT_ROOT_PATH/upstream.git" &&
+ mv upstream.git "$upstream" &&
+ git -C workbench remote set-url origin "$HTTPD_URL/auth-push/smart/upstream.git" &&
+ set_askpass user@host pass@host
+'
+
+setup_askpass_helper
+
+# Run test cases for 'proc-receive' hook on HTTP protocol.
+run_proc_receive_hook_test http
+
+test_done
diff --git a/t/t5411/common-functions.sh b/t/t5411/common-functions.sh
new file mode 100644
index 0000000..6580beb
--- /dev/null
+++ b/t/t5411/common-functions.sh
@@ -0,0 +1,56 @@
+# Create commits in <repo> and assign each commit's oid to shell variables
+# given in the arguments (A, B, and C). E.g.:
+#
+# create_commits_in <repo> A B C
+#
+# NOTE: Never calling this function from a subshell since variable
+# assignments will disappear when subshell exits.
+create_commits_in () {
+ repo="$1" &&
+ if ! parent=$(git -C "$repo" rev-parse HEAD^{} --)
+ then
+ parent=
+ fi &&
+ T=$(git -C "$repo" write-tree) &&
+ shift &&
+ while test $# -gt 0
+ do
+ name=$1 &&
+ test_tick &&
+ if test -z "$parent"
+ then
+ oid=$(echo $name | git -C "$repo" commit-tree $T)
+ else
+ oid=$(echo $name | git -C "$repo" commit-tree -p $parent $T)
+ fi &&
+ eval $name=$oid &&
+ parent=$oid &&
+ shift ||
+ return 1
+ done &&
+ git -C "$repo" update-ref refs/heads/master $oid
+}
+
+# Format the output of git-push, git-show-ref and other commands to make a
+# user-friendly and stable text. We can easily prepare the expect text
+# without having to worry about future changes of the commit ID and spaces
+# of the output. Single quotes are replaced with double quotes, because
+# it is boring to prepare unquoted single quotes in expect text. We also
+# remove some locale error messages, which break test if we turn on
+# `GIT_TEST_GETTEXT_POISON=true` in order to test unintentional translations
+# on plumbing commands.
+make_user_friendly_and_stable_output () {
+ sed \
+ -e "s/ *\$//" \
+ -e "s/ */ /g" \
+ -e "s/'/\"/g" \
+ -e "s/ / /g" \
+ -e "s/$A/<COMMIT-A>/g" \
+ -e "s/$B/<COMMIT-B>/g" \
+ -e "s/$TAG/<TAG-v123>/g" \
+ -e "s/$ZERO_OID/<ZERO-OID>/g" \
+ -e "s/$(echo $A | cut -c1-7)[0-9a-f]*/<OID-A>/g" \
+ -e "s/$(echo $B | cut -c1-7)[0-9a-f]*/<OID-B>/g" \
+ -e "s#To $URL_PREFIX/upstream.git#To <URL/of/upstream.git>#" \
+ -e "/^error: / d"
+}
diff --git a/t/t5411/once-0010-report-status-v1.sh b/t/t5411/once-0010-report-status-v1.sh
new file mode 100644
index 0000000..dc2cf4a
--- /dev/null
+++ b/t/t5411/once-0010-report-status-v1.sh
@@ -0,0 +1,94 @@
+test_expect_success "setup receive.procReceiveRefs" '
+ git -C "$upstream" config --add receive.procReceiveRefs refs/for
+'
+
+test_expect_success "setup proc-receive hook" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/master/topic1" \
+ -r "option fall-through" \
+ -r "ok refs/for/master/topic2" \
+ -r "option refname refs/for/changes/23/123/1" \
+ -r "option new-oid $A" \
+ -r "ok refs/for/master/topic2" \
+ -r "option refname refs/for/changes/24/124/2" \
+ -r "option old-oid $B" \
+ -r "option new-oid $A" \
+ -r "option forced-update" \
+ -r "ng refs/for/next/topic target branch not exist"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : (B) refs/for/master/topic1(A) foo(A) refs/for/next/topic(A) refs/for/master/topic2(A)
+test_expect_success "proc-receive: report status v1" '
+ {
+ if test -z "$GIT_DEFAULT_HASH" || test "$GIT_DEFAULT_HASH" = "sha1"
+ then
+ printf "%s %s refs/heads/master\0report-status\n" \
+ $A $B | packetize
+ else
+ printf "%s %s refs/heads/master\0report-status object-format=$GIT_DEFAULT_HASH\n" \
+ $A $B | packetize
+ fi &&
+ printf "%s %s refs/for/master/topic1\n" \
+ $ZERO_OID $A | packetize &&
+ printf "%s %s refs/heads/foo\n" \
+ $ZERO_OID $A | packetize &&
+ printf "%s %s refs/for/next/topic\n" \
+ $ZERO_OID $A | packetize &&
+ printf "%s %s refs/for/master/topic2\n" \
+ $ZERO_OID $A | packetize &&
+ printf 0000 &&
+ printf "" | git -C "$upstream" pack-objects --stdout
+ } | git receive-pack "$upstream" --stateless-rpc \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ # pre-receive hook
+ pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/master
+ pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic1
+ pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/foo
+ pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
+ pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic2
+ # proc-receive hook
+ proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic1
+ proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
+ proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic2
+ proc-receive> ok refs/for/master/topic1
+ proc-receive> option fall-through
+ proc-receive> ok refs/for/master/topic2
+ proc-receive> option refname refs/for/changes/23/123/1
+ proc-receive> option new-oid <COMMIT-A>
+ proc-receive> ok refs/for/master/topic2
+ proc-receive> option refname refs/for/changes/24/124/2
+ proc-receive> option old-oid <COMMIT-B>
+ proc-receive> option new-oid <COMMIT-A>
+ proc-receive> option forced-update
+ proc-receive> ng refs/for/next/topic target branch not exist
+ 000eunpack ok
+ 0019ok refs/heads/master
+ 001eok refs/for/master/topic1
+ 0016ok refs/heads/foo
+ 0033ng refs/for/next/topic target branch not exist
+ 001eok refs/for/master/topic2
+ 0000# post-receive hook
+ post-receive< <COMMIT-A> <COMMIT-B> refs/heads/master
+ post-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic1
+ post-receive< <ZERO-OID> <COMMIT-A> refs/heads/foo
+ post-receive< <ZERO-OID> <COMMIT-A> refs/for/changes/23/123/1
+ post-receive< <COMMIT-B> <COMMIT-A> refs/for/changes/24/124/2
+ EOF
+ test_cmp expect actual &&
+
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/for/master/topic1
+ <COMMIT-A> refs/heads/foo
+ <COMMIT-B> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
diff --git a/t/t5411/test-0000-standard-git-push.sh b/t/t5411/test-0000-standard-git-push.sh
new file mode 100644
index 0000000..e206587
--- /dev/null
+++ b/t/t5411/test-0000-standard-git-push.sh
@@ -0,0 +1,143 @@
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git-push : master(B) next(A)
+test_expect_success "git-push ($PROTOCOL)" '
+ git -C workbench push origin \
+ $B:refs/heads/master \
+ HEAD:refs/heads/next \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/master
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
+ remote: # post-receive hook
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/master
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
+ To <URL/of/upstream.git>
+ <OID-A>..<OID-B> <COMMIT-B> -> master
+ * [new branch] HEAD -> next
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-B> refs/heads/master
+ <COMMIT-A> refs/heads/next
+ EOF
+ test_cmp expect actual
+'
+
+# Refs of upstream : master(B) next(A)
+# Refs of workbench: master(A) tags/v123
+# git-push --atomic: master(A) next(B)
+test_expect_success "git-push --atomic ($PROTOCOL)" '
+ test_must_fail git -C workbench push --atomic origin \
+ master \
+ $B:refs/heads/next \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out |
+ sed -n \
+ -e "/^To / { s/ */ /g; p; }" \
+ -e "/^ ! / { s/ */ /g; p; }" \
+ >actual &&
+ cat >expect <<-EOF &&
+ To <URL/of/upstream.git>
+ ! [rejected] master -> master (non-fast-forward)
+ ! [rejected] <COMMIT-B> -> next (atomic push failed)
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-B> refs/heads/master
+ <COMMIT-A> refs/heads/next
+ EOF
+ test_cmp expect actual
+'
+
+# Refs of upstream : master(B) next(A)
+# Refs of workbench: master(A) tags/v123
+# git-push : master(A) next(B)
+test_expect_success "non-fast-forward git-push ($PROTOCOL)" '
+ test_must_fail git \
+ -C workbench \
+ -c advice.pushUpdateRejected=false \
+ push origin \
+ master \
+ $B:refs/heads/next \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/next
+ remote: # post-receive hook
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/next
+ To <URL/of/upstream.git>
+ <OID-A>..<OID-B> <COMMIT-B> -> next
+ ! [rejected] master -> master (non-fast-forward)
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-B> refs/heads/master
+ <COMMIT-B> refs/heads/next
+ EOF
+ test_cmp expect actual
+'
+
+# Refs of upstream : master(B) next(B)
+# Refs of workbench: master(A) tags/v123
+# git-push -f : master(A) NULL tags/v123 refs/review/master/topic(A) a/b/c(A)
+test_expect_success "git-push -f ($PROTOCOL)" '
+ git -C workbench push -f origin \
+ refs/tags/v123 \
+ :refs/heads/next \
+ master \
+ master:refs/review/master/topic \
+ HEAD:refs/heads/a/b/c \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <COMMIT-B> <COMMIT-A> refs/heads/master
+ remote: pre-receive< <COMMIT-B> <ZERO-OID> refs/heads/next
+ remote: pre-receive< <ZERO-OID> <TAG-v123> refs/tags/v123
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/review/master/topic
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/a/b/c
+ remote: # post-receive hook
+ remote: post-receive< <COMMIT-B> <COMMIT-A> refs/heads/master
+ remote: post-receive< <COMMIT-B> <ZERO-OID> refs/heads/next
+ remote: post-receive< <ZERO-OID> <TAG-v123> refs/tags/v123
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/review/master/topic
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/a/b/c
+ To <URL/of/upstream.git>
+ + <OID-B>...<OID-A> master -> master (forced update)
+ - [deleted] next
+ * [new tag] v123 -> v123
+ * [new reference] master -> refs/review/master/topic
+ * [new branch] HEAD -> a/b/c
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/a/b/c
+ <COMMIT-A> refs/heads/master
+ <COMMIT-A> refs/review/master/topic
+ <TAG-v123> refs/tags/v123
+ EOF
+ test_cmp expect actual
+'
+
+# Refs of upstream : master(A) tags/v123 refs/review/master/topic(A) a/b/c(A)
+# Refs of workbench: master(A) tags/v123
+test_expect_success "cleanup ($PROTOCOL)" '
+ (
+ cd "$upstream" &&
+ git update-ref -d refs/review/master/topic &&
+ git update-ref -d refs/tags/v123 &&
+ git update-ref -d refs/heads/a/b/c
+ )
+'
diff --git a/t/t5411/test-0001-standard-git-push--porcelain.sh b/t/t5411/test-0001-standard-git-push--porcelain.sh
new file mode 100644
index 0000000..48f6fcc
--- /dev/null
+++ b/t/t5411/test-0001-standard-git-push--porcelain.sh
@@ -0,0 +1,147 @@
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git-push : master(B) next(A)
+test_expect_success "git-push ($PROTOCOL/porcelain)" '
+ git -C workbench push --porcelain origin \
+ $B:refs/heads/master \
+ HEAD:refs/heads/next \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/master
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
+ remote: # post-receive hook
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/master
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
+ To <URL/of/upstream.git>
+ <COMMIT-B>:refs/heads/master <OID-A>..<OID-B>
+ * HEAD:refs/heads/next [new branch]
+ Done
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-B> refs/heads/master
+ <COMMIT-A> refs/heads/next
+ EOF
+ test_cmp expect actual
+'
+
+# Refs of upstream : master(B) next(A)
+# Refs of workbench: master(A) tags/v123
+# git-push --atomic: master(A) next(B)
+test_expect_success "git-push --atomic ($PROTOCOL/porcelain)" '
+ test_must_fail git -C workbench push --atomic --porcelain origin \
+ master \
+ $B:refs/heads/next \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out |
+ sed -n \
+ -e "s/^# GETTEXT POISON #//" \
+ -e "/^To / { s/ */ /g; p; }" \
+ -e "/^! / { s/ */ /g; p; }" \
+ >actual &&
+ cat >expect <<-EOF &&
+ To <URL/of/upstream.git>
+ ! refs/heads/master:refs/heads/master [rejected] (non-fast-forward)
+ ! <COMMIT-B>:refs/heads/next [rejected] (atomic push failed)
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-B> refs/heads/master
+ <COMMIT-A> refs/heads/next
+ EOF
+ test_cmp expect actual
+'
+
+# Refs of upstream : master(B) next(A)
+# Refs of workbench: master(A) tags/v123
+# git-push : master(A) next(B)
+test_expect_success "non-fast-forward git-push ($PROTOCOL/porcelain)" '
+ test_must_fail git \
+ -C workbench \
+ -c advice.pushUpdateRejected=false \
+ push --porcelain origin \
+ master \
+ $B:refs/heads/next \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/next
+ remote: # post-receive hook
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/next
+ To <URL/of/upstream.git>
+ <COMMIT-B>:refs/heads/next <OID-A>..<OID-B>
+ ! refs/heads/master:refs/heads/master [rejected] (non-fast-forward)
+ Done
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-B> refs/heads/master
+ <COMMIT-B> refs/heads/next
+ EOF
+ test_cmp expect actual
+'
+
+# Refs of upstream : master(B) next(B)
+# Refs of workbench: master(A) tags/v123
+# git-push -f : master(A) NULL tags/v123 refs/review/master/topic(A) a/b/c(A)
+test_expect_success "git-push -f ($PROTOCOL/porcelain)" '
+ git -C workbench push --porcelain -f origin \
+ refs/tags/v123 \
+ :refs/heads/next \
+ master \
+ master:refs/review/master/topic \
+ HEAD:refs/heads/a/b/c \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <COMMIT-B> <COMMIT-A> refs/heads/master
+ remote: pre-receive< <COMMIT-B> <ZERO-OID> refs/heads/next
+ remote: pre-receive< <ZERO-OID> <TAG-v123> refs/tags/v123
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/review/master/topic
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/a/b/c
+ remote: # post-receive hook
+ remote: post-receive< <COMMIT-B> <COMMIT-A> refs/heads/master
+ remote: post-receive< <COMMIT-B> <ZERO-OID> refs/heads/next
+ remote: post-receive< <ZERO-OID> <TAG-v123> refs/tags/v123
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/review/master/topic
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/a/b/c
+ To <URL/of/upstream.git>
+ + refs/heads/master:refs/heads/master <OID-B>...<OID-A> (forced update)
+ - :refs/heads/next [deleted]
+ * refs/tags/v123:refs/tags/v123 [new tag]
+ * refs/heads/master:refs/review/master/topic [new reference]
+ * HEAD:refs/heads/a/b/c [new branch]
+ Done
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/a/b/c
+ <COMMIT-A> refs/heads/master
+ <COMMIT-A> refs/review/master/topic
+ <TAG-v123> refs/tags/v123
+ EOF
+ test_cmp expect actual
+'
+
+# Refs of upstream : master(A) tags/v123 refs/review/master/topic(A) a/b/c(A)
+# Refs of workbench: master(A) tags/v123
+test_expect_success "cleanup ($PROTOCOL/porcelain)" '
+ (
+ cd "$upstream" &&
+ git update-ref -d refs/review/master/topic &&
+ git update-ref -d refs/tags/v123 &&
+ git update-ref -d refs/heads/a/b/c
+ )
+'
diff --git a/t/t5411/test-0002-pre-receive-declined.sh b/t/t5411/test-0002-pre-receive-declined.sh
new file mode 100644
index 0000000..c246f7e
--- /dev/null
+++ b/t/t5411/test-0002-pre-receive-declined.sh
@@ -0,0 +1,33 @@
+test_expect_success "setup pre-receive hook ($PROTOCOL)" '
+ mv "$upstream/hooks/pre-receive" "$upstream/hooks/pre-receive.ok" &&
+ write_script "$upstream/hooks/pre-receive" <<-EOF
+ exit 1
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git-push : master(B) next(A)
+test_expect_success "git-push is declined ($PROTOCOL)" '
+ test_must_fail git -C workbench push origin \
+ $B:refs/heads/master \
+ HEAD:refs/heads/next \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ To <URL/of/upstream.git>
+ ! [remote rejected] <COMMIT-B> -> master (pre-receive hook declined)
+ ! [remote rejected] HEAD -> next (pre-receive hook declined)
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "cleanup ($PROTOCOL)" '
+ mv "$upstream/hooks/pre-receive.ok" "$upstream/hooks/pre-receive"
+'
diff --git a/t/t5411/test-0003-pre-receive-declined--porcelain.sh b/t/t5411/test-0003-pre-receive-declined--porcelain.sh
new file mode 100644
index 0000000..b14894d
--- /dev/null
+++ b/t/t5411/test-0003-pre-receive-declined--porcelain.sh
@@ -0,0 +1,34 @@
+test_expect_success "setup pre-receive hook ($PROTOCOL/porcelain)" '
+ mv "$upstream/hooks/pre-receive" "$upstream/hooks/pre-receive.ok" &&
+ write_script "$upstream/hooks/pre-receive" <<-EOF
+ exit 1
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git-push : master(B) next(A)
+test_expect_success "git-push is declined ($PROTOCOL/porcelain)" '
+ test_must_fail git -C workbench push --porcelain origin \
+ $B:refs/heads/master \
+ HEAD:refs/heads/next \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ To <URL/of/upstream.git>
+ ! <COMMIT-B>:refs/heads/master [remote rejected] (pre-receive hook declined)
+ ! HEAD:refs/heads/next [remote rejected] (pre-receive hook declined)
+ Done
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "cleanup ($PROTOCOL/porcelain)" '
+ mv "$upstream/hooks/pre-receive.ok" "$upstream/hooks/pre-receive"
+'
diff --git a/t/t5411/test-0010-proc-receive-settings.sh b/t/t5411/test-0010-proc-receive-settings.sh
new file mode 100644
index 0000000..a368099
--- /dev/null
+++ b/t/t5411/test-0010-proc-receive-settings.sh
@@ -0,0 +1,7 @@
+test_expect_success "add two receive.procReceiveRefs settings" '
+ (
+ cd "$upstream" &&
+ git config --add receive.procReceiveRefs refs/for &&
+ git config --add receive.procReceiveRefs refs/review/
+ )
+'
diff --git a/t/t5411/test-0011-no-hook-error.sh b/t/t5411/test-0011-no-hook-error.sh
new file mode 100644
index 0000000..bb6ec92
--- /dev/null
+++ b/t/t5411/test-0011-no-hook-error.sh
@@ -0,0 +1,64 @@
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : next(A) refs/for/master/topic(A)
+test_expect_success "proc-receive: no hook, fail to push special ref ($PROTOCOL)" '
+ test_must_fail git -C workbench push origin \
+ HEAD:next \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: error: cannot find hook "proc-receive"
+ remote: # post-receive hook
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
+ To <URL/of/upstream.git>
+ * [new branch] HEAD -> next
+ ! [remote rejected] HEAD -> refs/for/master/topic (fail to run proc-receive hook)
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ <COMMIT-A> refs/heads/next
+ EOF
+ test_cmp expect actual
+'
+
+# Refs of upstream : master(A) next(A)
+# Refs of workbench: master(A) tags/v123
+test_expect_success "cleanup ($PROTOCOL)" '
+ git -C "$upstream" update-ref -d refs/heads/next
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push --atomic: (B) next(A) refs/for/master/topic(A)
+test_expect_success "proc-receive: no hook, all failed for atomic push ($PROTOCOL)" '
+ test_must_fail git -C workbench push --atomic origin \
+ $B:master \
+ HEAD:next \
+ HEAD:refs/for/master/topic >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/master
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: error: cannot find hook "proc-receive"
+ To <URL/of/upstream.git>
+ ! [remote rejected] <COMMIT-B> -> master (fail to run proc-receive hook)
+ ! [remote rejected] HEAD -> next (fail to run proc-receive hook)
+ ! [remote rejected] HEAD -> refs/for/master/topic (fail to run proc-receive hook)
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
diff --git a/t/t5411/test-0012-no-hook-error--porcelain.sh b/t/t5411/test-0012-no-hook-error--porcelain.sh
new file mode 100644
index 0000000..4814f74
--- /dev/null
+++ b/t/t5411/test-0012-no-hook-error--porcelain.sh
@@ -0,0 +1,66 @@
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : next(A) refs/for/master/topic(A)
+test_expect_success "proc-receive: no hook, fail to push special ref ($PROTOCOL/porcelain)" '
+ test_must_fail git -C workbench push --porcelain origin \
+ HEAD:next \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: error: cannot find hook "proc-receive"
+ remote: # post-receive hook
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
+ To <URL/of/upstream.git>
+ * HEAD:refs/heads/next [new branch]
+ ! HEAD:refs/for/master/topic [remote rejected] (fail to run proc-receive hook)
+ Done
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ <COMMIT-A> refs/heads/next
+ EOF
+ test_cmp expect actual
+'
+
+# Refs of upstream : master(A) next(A)
+# Refs of workbench: master(A) tags/v123
+test_expect_success "cleanup ($PROTOCOL/porcelain)" '
+ git -C "$upstream" update-ref -d refs/heads/next
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push --atomic: (B) next(A) refs/for/master/topic(A)
+test_expect_success "proc-receive: no hook, all failed for atomic push ($PROTOCOL/porcelain)" '
+ test_must_fail git -C workbench push --porcelain --atomic origin \
+ $B:master \
+ HEAD:next \
+ HEAD:refs/for/master/topic >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/master
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: error: cannot find hook "proc-receive"
+ To <URL/of/upstream.git>
+ ! <COMMIT-B>:refs/heads/master [remote rejected] (fail to run proc-receive hook)
+ ! HEAD:refs/heads/next [remote rejected] (fail to run proc-receive hook)
+ ! HEAD:refs/for/master/topic [remote rejected] (fail to run proc-receive hook)
+ Done
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
diff --git a/t/t5411/test-0013-bad-protocol.sh b/t/t5411/test-0013-bad-protocol.sh
new file mode 100644
index 0000000..c5fe4cb
--- /dev/null
+++ b/t/t5411/test-0013-bad-protocol.sh
@@ -0,0 +1,217 @@
+test_expect_success "setup proc-receive hook (unknown version, $PROTOCOL)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v --version 2
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/master/topic(A)
+test_expect_success "proc-receive: bad protocol (unknown version, $PROTOCOL)" '
+ test_must_fail git -C workbench push origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+
+ # Check status report for git-push
+ sed -n \
+ -e "/^To / { p; n; p; }" \
+ <actual >actual-report &&
+ cat >expect <<-EOF &&
+ To <URL/of/upstream.git>
+ ! [remote rejected] HEAD -> refs/for/master/topic (fail to run proc-receive hook)
+ EOF
+ test_cmp expect actual-report &&
+
+ # Check error message from "receive-pack", but ignore unstable fatal error
+ # message ("remote: fatal: the remote end hung up unexpectedly") which
+ # is different from the remote HTTP server with different locale settings.
+ grep "^remote: error:" <actual >actual-error &&
+ cat >expect <<-EOF &&
+ remote: error: proc-receive version "2" is not supported
+ EOF
+ test_cmp expect actual-error &&
+
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "setup proc-receive hook (hook --die-version, $PROTOCOL)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v --die-version
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/master/topic(A)
+test_expect_success "proc-receive: bad protocol (hook --die-version, $PROTOCOL)" '
+ test_must_fail git -C workbench push origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: fatal: bad protocol version: 1
+ remote: error: proc-receive version "0" is not supported
+ To <URL/of/upstream.git>
+ ! [remote rejected] HEAD -> refs/for/master/topic (fail to run proc-receive hook)
+ EOF
+ test_cmp expect actual &&
+
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "setup proc-receive hook (hook --die-readline, $PROTOCOL)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v --die-readline
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/master/topic(A)
+test_expect_success "proc-receive: bad protocol (hook --die-readline, $PROTOCOL)" '
+ test_must_fail git -C workbench push origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+
+ grep "remote: fatal: protocol error: expected \"old new ref\", got \"<ZERO-OID> <COMMIT-A> refs/for/master/topic\"" actual &&
+
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "setup proc-receive hook (no report, $PROTOCOL)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : next(A) refs/for/master/topic(A)
+test_expect_success "proc-receive: bad protocol (no report, $PROTOCOL)" '
+ test_must_fail git -C workbench push origin \
+ HEAD:refs/heads/next \
+ HEAD:refs/for/master/topic >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # post-receive hook
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
+ To <URL/of/upstream.git>
+ * [new branch] HEAD -> next
+ ! [remote rejected] HEAD -> refs/for/master/topic (proc-receive failed to report status)
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ <COMMIT-A> refs/heads/next
+ EOF
+ test_cmp expect actual
+'
+
+# Refs of upstream : master(A) next(A)
+# Refs of workbench: master(A) tags/v123
+test_expect_success "cleanup ($PROTOCOL)" '
+ git -C "$upstream" update-ref -d refs/heads/next
+
+'
+
+test_expect_success "setup proc-receive hook (no ref, $PROTOCOL)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/master/topic
+test_expect_success "proc-receive: bad protocol (no ref, $PROTOCOL)" '
+ test_must_fail git -C workbench push origin \
+ HEAD:refs/for/master/topic\
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ok
+ remote: error: proc-receive reported incomplete status line: "ok"
+ To <URL/of/upstream.git>
+ ! [remote rejected] HEAD -> refs/for/master/topic (proc-receive failed to report status)
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "setup proc-receive hook (unknown status, $PROTOCOL)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "xx refs/for/master/topic"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/master/topic
+test_expect_success "proc-receive: bad protocol (unknown status, $PROTOCOL)" '
+ test_must_fail git -C workbench push origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> xx refs/for/master/topic
+ remote: error: proc-receive reported bad status "xx" on ref "refs/for/master/topic"
+ To <URL/of/upstream.git>
+ ! [remote rejected] HEAD -> refs/for/master/topic (proc-receive failed to report status)
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
diff --git a/t/t5411/test-0014-bad-protocol--porcelain.sh b/t/t5411/test-0014-bad-protocol--porcelain.sh
new file mode 100644
index 0000000..53b47b0
--- /dev/null
+++ b/t/t5411/test-0014-bad-protocol--porcelain.sh
@@ -0,0 +1,160 @@
+test_expect_success "setup proc-receive hook (unknown version, $PROTOCOL/porcelain)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v --version 2
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/master/topic(A)
+test_expect_success "proc-receive: bad protocol (unknown version, $PROTOCOL/porcelain)" '
+ test_must_fail git -C workbench push --porcelain origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+
+ # Check status report for git-push
+ sed -n \
+ -e "/^To / { p; n; p; n; p; }" \
+ <actual >actual-report &&
+ cat >expect <<-EOF &&
+ To <URL/of/upstream.git>
+ ! HEAD:refs/for/master/topic [remote rejected] (fail to run proc-receive hook)
+ Done
+ EOF
+ test_cmp expect actual-report &&
+
+ # Check error message from "receive-pack", but ignore unstable fatal error
+ # message ("remote: fatal: the remote end hung up unexpectedly") which
+ # is different from the remote HTTP server with different locale settings.
+ grep "^remote: error:" <actual >actual-error &&
+ cat >expect <<-EOF &&
+ remote: error: proc-receive version "2" is not supported
+ EOF
+ test_cmp expect actual-error &&
+
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "setup proc-receive hook (no report, $PROTOCOL/porcelain)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : next(A) refs/for/master/topic(A)
+test_expect_success "proc-receive: bad protocol (no report, $PROTOCOL/porcelain)" '
+ test_must_fail git -C workbench push --porcelain origin \
+ HEAD:refs/heads/next \
+ HEAD:refs/for/master/topic >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # post-receive hook
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
+ To <URL/of/upstream.git>
+ * HEAD:refs/heads/next [new branch]
+ ! HEAD:refs/for/master/topic [remote rejected] (proc-receive failed to report status)
+ Done
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ <COMMIT-A> refs/heads/next
+ EOF
+ test_cmp expect actual
+'
+
+# Refs of upstream : master(A) next(A)
+# Refs of workbench: master(A) tags/v123
+test_expect_success "cleanup ($PROTOCOL/porcelain)" '
+ git -C "$upstream" update-ref -d refs/heads/next
+
+'
+
+test_expect_success "setup proc-receive hook (no ref, $PROTOCOL/porcelain)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/master/topic
+test_expect_success "proc-receive: bad protocol (no ref, $PROTOCOL/porcelain)" '
+ test_must_fail git -C workbench push --porcelain origin \
+ HEAD:refs/for/master/topic\
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ok
+ remote: error: proc-receive reported incomplete status line: "ok"
+ To <URL/of/upstream.git>
+ ! HEAD:refs/for/master/topic [remote rejected] (proc-receive failed to report status)
+ Done
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "setup proc-receive hook (unknown status, $PROTOCOL/porcelain)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "xx refs/for/master/topic"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/master/topic
+test_expect_success "proc-receive: bad protocol (unknown status, $PROTOCOL/porcelain)" '
+ test_must_fail git -C workbench push --porcelain origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> xx refs/for/master/topic
+ remote: error: proc-receive reported bad status "xx" on ref "refs/for/master/topic"
+ To <URL/of/upstream.git>
+ ! HEAD:refs/for/master/topic [remote rejected] (proc-receive failed to report status)
+ Done
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
diff --git a/t/t5411/test-0020-report-ng.sh b/t/t5411/test-0020-report-ng.sh
new file mode 100644
index 0000000..f726b7c
--- /dev/null
+++ b/t/t5411/test-0020-report-ng.sh
@@ -0,0 +1,67 @@
+test_expect_success "setup proc-receive hook (ng, no message, $PROTOCOL)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ng refs/for/master/topic"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/master/topic
+test_expect_success "proc-receive: fail to update (ng, no message, $PROTOCOL)" '
+ test_must_fail git -C workbench push origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ng refs/for/master/topic
+ To <URL/of/upstream.git>
+ ! [remote rejected] HEAD -> refs/for/master/topic (failed)
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "setup proc-receive hook (ng message, $PROTOCOL)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ng refs/for/master/topic error msg"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/master/topic
+test_expect_success "proc-receive: fail to update (ng, with message, $PROTOCOL)" '
+ test_must_fail git -C workbench push origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ng refs/for/master/topic error msg
+ To <URL/of/upstream.git>
+ ! [remote rejected] HEAD -> refs/for/master/topic (error msg)
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
diff --git a/t/t5411/test-0021-report-ng--porcelain.sh b/t/t5411/test-0021-report-ng--porcelain.sh
new file mode 100644
index 0000000..fbf5569
--- /dev/null
+++ b/t/t5411/test-0021-report-ng--porcelain.sh
@@ -0,0 +1,69 @@
+test_expect_success "setup proc-receive hook (ng, no message, $PROTOCOL/porcelain)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ng refs/for/master/topic"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/master/topic
+test_expect_success "proc-receive: fail to update (ng, no message, $PROTOCOL/porcelain)" '
+ test_must_fail git -C workbench push --porcelain origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ng refs/for/master/topic
+ To <URL/of/upstream.git>
+ ! HEAD:refs/for/master/topic [remote rejected] (failed)
+ Done
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "setup proc-receive hook (ng message, $PROTOCOL/porcelain)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ng refs/for/master/topic error msg"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/master/topic
+test_expect_success "proc-receive: fail to update (ng, with message, $PROTOCOL/porcelain)" '
+ test_must_fail git -C workbench push --porcelain origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ng refs/for/master/topic error msg
+ To <URL/of/upstream.git>
+ ! HEAD:refs/for/master/topic [remote rejected] (error msg)
+ Done
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
diff --git a/t/t5411/test-0022-report-unexpect-ref.sh b/t/t5411/test-0022-report-unexpect-ref.sh
new file mode 100644
index 0000000..92a415b
--- /dev/null
+++ b/t/t5411/test-0022-report-unexpect-ref.sh
@@ -0,0 +1,45 @@
+test_expect_success "setup proc-receive hook (unexpected ref, $PROTOCOL)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/heads/master"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : (B) refs/for/master/topic
+test_expect_success "proc-receive: report unexpected ref ($PROTOCOL)" '
+ test_must_fail git -C workbench push origin \
+ $B:refs/heads/master \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/master
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ok refs/heads/master
+ remote: error: proc-receive reported status on unexpected ref: refs/heads/master
+ remote: # post-receive hook
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/master
+ To <URL/of/upstream.git>
+ <OID-A>..<OID-B> <COMMIT-B> -> master
+ ! [remote rejected] HEAD -> refs/for/master/topic (proc-receive failed to report status)
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-B> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
+
+# Refs of upstream : master(B)
+# Refs of workbench: master(A) tags/v123
+test_expect_success "cleanup ($PROTOCOL)" '
+ git -C "$upstream" update-ref refs/heads/master $A
+'
diff --git a/t/t5411/test-0023-report-unexpect-ref--porcelain.sh b/t/t5411/test-0023-report-unexpect-ref--porcelain.sh
new file mode 100644
index 0000000..acbf93e
--- /dev/null
+++ b/t/t5411/test-0023-report-unexpect-ref--porcelain.sh
@@ -0,0 +1,46 @@
+test_expect_success "setup proc-receive hook (unexpected ref, $PROTOCOL/porcelain)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/heads/master"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : (B) refs/for/master/topic
+test_expect_success "proc-receive: report unexpected ref ($PROTOCOL/porcelain)" '
+ test_must_fail git -C workbench push --porcelain origin \
+ $B:refs/heads/master \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/master
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ok refs/heads/master
+ remote: error: proc-receive reported status on unexpected ref: refs/heads/master
+ remote: # post-receive hook
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/master
+ To <URL/of/upstream.git>
+ <COMMIT-B>:refs/heads/master <OID-A>..<OID-B>
+ ! HEAD:refs/for/master/topic [remote rejected] (proc-receive failed to report status)
+ Done
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-B> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
+
+# Refs of upstream : master(B)
+# Refs of workbench: master(A) tags/v123
+test_expect_success "cleanup ($PROTOCOL/porcelain)" '
+ git -C "$upstream" update-ref refs/heads/master $A
+'
diff --git a/t/t5411/test-0024-report-unknown-ref.sh b/t/t5411/test-0024-report-unknown-ref.sh
new file mode 100644
index 0000000..c3946f3
--- /dev/null
+++ b/t/t5411/test-0024-report-unknown-ref.sh
@@ -0,0 +1,34 @@
+test_expect_success "setup proc-receive hook (unexpected ref, $PROTOCOL)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/master/topic"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/a/b/c/my/topic
+test_expect_success "proc-receive: report unknown reference ($PROTOCOL)" '
+ test_must_fail git -C workbench push origin \
+ HEAD:refs/for/a/b/c/my/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/my/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/my/topic
+ remote: proc-receive> ok refs/for/master/topic
+ remote: error: proc-receive reported status on unknown ref: refs/for/master/topic
+ To <URL/of/upstream.git>
+ ! [remote rejected] HEAD -> refs/for/a/b/c/my/topic (proc-receive failed to report status)
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
diff --git a/t/t5411/test-0025-report-unknown-ref--porcelain.sh b/t/t5411/test-0025-report-unknown-ref--porcelain.sh
new file mode 100644
index 0000000..d093b1a
--- /dev/null
+++ b/t/t5411/test-0025-report-unknown-ref--porcelain.sh
@@ -0,0 +1,35 @@
+test_expect_success "setup proc-receive hook (unexpected ref, $PROTOCOL/porcelain)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/master/topic"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/a/b/c/my/topic
+test_expect_success "proc-receive: report unknown reference ($PROTOCOL/porcelain)" '
+ test_must_fail git -C workbench push --porcelain origin \
+ HEAD:refs/for/a/b/c/my/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/my/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/my/topic
+ remote: proc-receive> ok refs/for/master/topic
+ remote: error: proc-receive reported status on unknown ref: refs/for/master/topic
+ To <URL/of/upstream.git>
+ ! HEAD:refs/for/a/b/c/my/topic [remote rejected] (proc-receive failed to report status)
+ Done
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
diff --git a/t/t5411/test-0026-push-options.sh b/t/t5411/test-0026-push-options.sh
new file mode 100644
index 0000000..d0c4da8
--- /dev/null
+++ b/t/t5411/test-0026-push-options.sh
@@ -0,0 +1,79 @@
+test_expect_success "setup proc-receive hook and disable push-options ($PROTOCOL)" '
+ git -C "$upstream" config receive.advertisePushOptions false &&
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/master/topic"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push -o ... : refs/for/master/topic
+test_expect_success "proc-receive: not support push options ($PROTOCOL)" '
+ test_must_fail git -C workbench push \
+ -o issue=123 \
+ -o reviewer=user1 \
+ origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ test_i18ngrep "fatal: the receiving end does not support push options" \
+ actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "enable push options ($PROTOCOL)" '
+ git -C "$upstream" config receive.advertisePushOptions true
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push -o ... : next(A) refs/for/master/topic
+test_expect_success "proc-receive: push with options ($PROTOCOL)" '
+ git -C workbench push \
+ --atomic \
+ -o issue=123 \
+ -o reviewer=user1 \
+ origin \
+ HEAD:refs/heads/next \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive: atomic push_options
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive< issue=123
+ remote: proc-receive< reviewer=user1
+ remote: proc-receive> ok refs/for/master/topic
+ remote: # post-receive hook
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ To <URL/of/upstream.git>
+ * [new branch] HEAD -> next
+ * [new reference] HEAD -> refs/for/master/topic
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ <COMMIT-A> refs/heads/next
+ EOF
+ test_cmp expect actual
+'
+
+# Refs of upstream : master(A) next(A)
+# Refs of workbench: master(A) tags/v123
+test_expect_success "cleanup ($PROTOCOL)" '
+ git -C "$upstream" update-ref -d refs/heads/next
+'
diff --git a/t/t5411/test-0027-push-options--porcelain.sh b/t/t5411/test-0027-push-options--porcelain.sh
new file mode 100644
index 0000000..c89a1e7
--- /dev/null
+++ b/t/t5411/test-0027-push-options--porcelain.sh
@@ -0,0 +1,82 @@
+test_expect_success "setup proc-receive hook and disable push-options ($PROTOCOL/porcelain)" '
+ git -C "$upstream" config receive.advertisePushOptions false &&
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/master/topic"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push -o ... : refs/for/master/topic
+test_expect_success "proc-receive: not support push options ($PROTOCOL/porcelain)" '
+ test_must_fail git -C workbench push \
+ --porcelain \
+ -o issue=123 \
+ -o reviewer=user1 \
+ origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ test_i18ngrep "fatal: the receiving end does not support push options" \
+ actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "enable push options ($PROTOCOL/porcelain)" '
+ git -C "$upstream" config receive.advertisePushOptions true
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push -o ... : next(A) refs/for/master/topic
+test_expect_success "proc-receive: push with options ($PROTOCOL/porcelain)" '
+ git -C workbench push \
+ --porcelain \
+ --atomic \
+ -o issue=123 \
+ -o reviewer=user1 \
+ origin \
+ HEAD:refs/heads/next \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive: atomic push_options
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive< issue=123
+ remote: proc-receive< reviewer=user1
+ remote: proc-receive> ok refs/for/master/topic
+ remote: # post-receive hook
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ To <URL/of/upstream.git>
+ * HEAD:refs/heads/next [new branch]
+ * HEAD:refs/for/master/topic [new reference]
+ Done
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ <COMMIT-A> refs/heads/next
+ EOF
+ test_cmp expect actual
+'
+
+# Refs of upstream : master(A) next(A)
+# Refs of workbench: master(A) tags/v123
+test_expect_success "cleanup ($PROTOCOL/porcelain)" '
+ git -C "$upstream" update-ref -d refs/heads/next
+'
diff --git a/t/t5411/test-0030-report-ok.sh b/t/t5411/test-0030-report-ok.sh
new file mode 100644
index 0000000..44c99d3
--- /dev/null
+++ b/t/t5411/test-0030-report-ok.sh
@@ -0,0 +1,35 @@
+test_expect_success "setup proc-receive hook (ok, $PROTOCOL)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/master/topic"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/master/topic
+test_expect_success "proc-receive: ok ($PROTOCOL)" '
+ git -C workbench push origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ok refs/for/master/topic
+ remote: # post-receive hook
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ To <URL/of/upstream.git>
+ * [new reference] HEAD -> refs/for/master/topic
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
diff --git a/t/t5411/test-0031-report-ok--porcelain.sh b/t/t5411/test-0031-report-ok--porcelain.sh
new file mode 100644
index 0000000..3223b26
--- /dev/null
+++ b/t/t5411/test-0031-report-ok--porcelain.sh
@@ -0,0 +1,36 @@
+test_expect_success "setup proc-receive hook (ok, $PROTOCOL/porcelain)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/master/topic"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/master/topic
+test_expect_success "proc-receive: ok ($PROTOCOL/porcelain)" '
+ git -C workbench push --porcelain origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ok refs/for/master/topic
+ remote: # post-receive hook
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ To <URL/of/upstream.git>
+ * HEAD:refs/for/master/topic [new reference]
+ Done
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
diff --git a/t/t5411/test-0032-report-with-options.sh b/t/t5411/test-0032-report-with-options.sh
new file mode 100644
index 0000000..b77b78c
--- /dev/null
+++ b/t/t5411/test-0032-report-with-options.sh
@@ -0,0 +1,256 @@
+test_expect_success "setup proc-receive hook (option without matching ok, $PROTOCOL)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "option refname refs/pull/123/head" \
+ -r "option old-oid $B"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A)
+test_expect_success "proc-receive: report option without matching ok ($PROTOCOL)" '
+ test_must_fail git -C workbench push origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> option refname refs/pull/123/head
+ remote: proc-receive> option old-oid <COMMIT-B>
+ remote: error: proc-receive reported "option" without a matching "ok/ng" directive
+ To <URL/of/upstream.git>
+ ! [remote rejected] HEAD -> refs/for/master/topic (proc-receive failed to report status)
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "setup proc-receive hook (option refname, $PROTOCOL)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/master/topic" \
+ -r "option refname refs/pull/123/head"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A)
+test_expect_success "proc-receive: report option refname ($PROTOCOL)" '
+ git -C workbench push origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option refname refs/pull/123/head
+ remote: # post-receive hook
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/pull/123/head
+ To <URL/of/upstream.git>
+ * [new reference] HEAD -> refs/pull/123/head
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "setup proc-receive hook (option refname and forced-update, $PROTOCOL)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/master/topic" \
+ -r "option refname refs/pull/123/head" \
+ -r "option forced-update"
+ EOF
+'
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A)
+test_expect_success "proc-receive: report option refname and forced-update ($PROTOCOL)" '
+ git -C workbench push origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option refname refs/pull/123/head
+ remote: proc-receive> option forced-update
+ remote: # post-receive hook
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/pull/123/head
+ To <URL/of/upstream.git>
+ * [new reference] HEAD -> refs/pull/123/head
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "setup proc-receive hook (option refname and old-oid, $PROTOCOL)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/master/topic" \
+ -r "option refname refs/pull/123/head" \
+ -r "option old-oid $B"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A)
+test_expect_success "proc-receive: report option refname and old-oid ($PROTOCOL)" '
+ git -C workbench push origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option refname refs/pull/123/head
+ remote: proc-receive> option old-oid <COMMIT-B>
+ remote: # post-receive hook
+ remote: post-receive< <COMMIT-B> <COMMIT-A> refs/pull/123/head
+ To <URL/of/upstream.git>
+ <OID-B>..<OID-A> HEAD -> refs/pull/123/head
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "setup proc-receive hook (option old-oid, $PROTOCOL)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/master/topic" \
+ -r "option old-oid $B"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A)
+test_expect_success "proc-receive: report option old-oid ($PROTOCOL)" '
+ git -C workbench push origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option old-oid <COMMIT-B>
+ remote: # post-receive hook
+ remote: post-receive< <COMMIT-B> <COMMIT-A> refs/for/master/topic
+ To <URL/of/upstream.git>
+ <OID-B>..<OID-A> HEAD -> refs/for/master/topic
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "setup proc-receive hook (option old-oid and new-oid, $PROTOCOL)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/master/topic" \
+ -r "option old-oid $A" \
+ -r "option new-oid $B"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A)
+test_expect_success "proc-receive: report option old-oid and new-oid ($PROTOCOL)" '
+ git -C workbench push origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option old-oid <COMMIT-A>
+ remote: proc-receive> option new-oid <COMMIT-B>
+ remote: # post-receive hook
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/master/topic
+ To <URL/of/upstream.git>
+ <OID-A>..<OID-B> HEAD -> refs/for/master/topic
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "setup proc-receive hook (report with multiple rewrites, $PROTOCOL)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/a/b/c/topic" \
+ -r "ok refs/for/next/topic" \
+ -r "option refname refs/pull/123/head" \
+ -r "ok refs/for/master/topic" \
+ -r "option refname refs/pull/124/head" \
+ -r "option old-oid $B" \
+ -r "option forced-update" \
+ -r "option new-oid $A"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A)
+test_expect_success "proc-receive: report with multiple rewrites ($PROTOCOL)" '
+ git -C workbench push origin \
+ HEAD:refs/for/next/topic \
+ HEAD:refs/for/a/b/c/topic \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/topic
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/topic
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ok refs/for/a/b/c/topic
+ remote: proc-receive> ok refs/for/next/topic
+ remote: proc-receive> option refname refs/pull/123/head
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option refname refs/pull/124/head
+ remote: proc-receive> option old-oid <COMMIT-B>
+ remote: proc-receive> option forced-update
+ remote: proc-receive> option new-oid <COMMIT-A>
+ remote: # post-receive hook
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/pull/123/head
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/topic
+ remote: post-receive< <COMMIT-B> <COMMIT-A> refs/pull/124/head
+ To <URL/of/upstream.git>
+ * [new reference] HEAD -> refs/pull/123/head
+ * [new reference] HEAD -> refs/for/a/b/c/topic
+ + <OID-B>...<OID-A> HEAD -> refs/pull/124/head (forced update)
+ EOF
+ test_cmp expect actual &&
+
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
diff --git a/t/t5411/test-0033-report-with-options--porcelain.sh b/t/t5411/test-0033-report-with-options--porcelain.sh
new file mode 100644
index 0000000..1fe352b
--- /dev/null
+++ b/t/t5411/test-0033-report-with-options--porcelain.sh
@@ -0,0 +1,265 @@
+test_expect_success "setup proc-receive hook (option without matching ok, $PROTOCOL/porcelain)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "option refname refs/pull/123/head" \
+ -r "option old-oid $B"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A)
+test_expect_success "proc-receive: report option without matching ok ($PROTOCOL/porcelain)" '
+ test_must_fail git -C workbench push --porcelain origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> option refname refs/pull/123/head
+ remote: proc-receive> option old-oid <COMMIT-B>
+ remote: error: proc-receive reported "option" without a matching "ok/ng" directive
+ To <URL/of/upstream.git>
+ ! HEAD:refs/for/master/topic [remote rejected] (proc-receive failed to report status)
+ Done
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "setup proc-receive hook (option refname, $PROTOCOL/porcelain)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/master/topic" \
+ -r "option refname refs/pull/123/head"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A)
+test_expect_success "proc-receive: report option refname ($PROTOCOL/porcelain)" '
+ git -C workbench push --porcelain origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option refname refs/pull/123/head
+ remote: # post-receive hook
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/pull/123/head
+ To <URL/of/upstream.git>
+ * HEAD:refs/pull/123/head [new reference]
+ Done
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "setup proc-receive hook (option refname and forced-update, $PROTOCOL/porcelain)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/master/topic" \
+ -r "option refname refs/pull/123/head" \
+ -r "option forced-update"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A)
+test_expect_success "proc-receive: report option refname and forced-update ($PROTOCOL/porcelain)" '
+ git -C workbench push --porcelain origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option refname refs/pull/123/head
+ remote: proc-receive> option forced-update
+ remote: # post-receive hook
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/pull/123/head
+ To <URL/of/upstream.git>
+ * HEAD:refs/pull/123/head [new reference]
+ Done
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "setup proc-receive hook (option refname and old-oid, $PROTOCOL/porcelain)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/master/topic" \
+ -r "option refname refs/pull/123/head" \
+ -r "option old-oid $B"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A)
+test_expect_success "proc-receive: report option refname and old-oid ($PROTOCOL/porcelain)" '
+ git -C workbench push --porcelain origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option refname refs/pull/123/head
+ remote: proc-receive> option old-oid <COMMIT-B>
+ remote: # post-receive hook
+ remote: post-receive< <COMMIT-B> <COMMIT-A> refs/pull/123/head
+ To <URL/of/upstream.git>
+ HEAD:refs/pull/123/head <OID-B>..<OID-A>
+ Done
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "setup proc-receive hook (option old-oid, $PROTOCOL/porcelain)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/master/topic" \
+ -r "option old-oid $B"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A)
+test_expect_success "proc-receive: report option old-oid ($PROTOCOL/porcelain)" '
+ git -C workbench push --porcelain origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option old-oid <COMMIT-B>
+ remote: # post-receive hook
+ remote: post-receive< <COMMIT-B> <COMMIT-A> refs/for/master/topic
+ To <URL/of/upstream.git>
+ HEAD:refs/for/master/topic <OID-B>..<OID-A>
+ Done
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "setup proc-receive hook (option old-oid and new-oid, $PROTOCOL/porcelain)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/master/topic" \
+ -r "option old-oid $A" \
+ -r "option new-oid $B"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A)
+test_expect_success "proc-receive: report option old-oid and new-oid ($PROTOCOL/porcelain)" '
+ git -C workbench push --porcelain origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option old-oid <COMMIT-A>
+ remote: proc-receive> option new-oid <COMMIT-B>
+ remote: # post-receive hook
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/master/topic
+ To <URL/of/upstream.git>
+ HEAD:refs/for/master/topic <OID-A>..<OID-B>
+ Done
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "setup proc-receive hook (report with multiple rewrites, $PROTOCOL/porcelain)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/a/b/c/topic" \
+ -r "ok refs/for/next/topic" \
+ -r "option refname refs/pull/123/head" \
+ -r "ok refs/for/master/topic" \
+ -r "option refname refs/pull/124/head" \
+ -r "option old-oid $B" \
+ -r "option forced-update" \
+ -r "option new-oid $A"
+
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A)
+test_expect_success "proc-receive: report with multiple rewrites ($PROTOCOL/porcelain)" '
+ git -C workbench push --porcelain origin \
+ HEAD:refs/for/next/topic \
+ HEAD:refs/for/a/b/c/topic \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/topic
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/topic
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ok refs/for/a/b/c/topic
+ remote: proc-receive> ok refs/for/next/topic
+ remote: proc-receive> option refname refs/pull/123/head
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option refname refs/pull/124/head
+ remote: proc-receive> option old-oid <COMMIT-B>
+ remote: proc-receive> option forced-update
+ remote: proc-receive> option new-oid <COMMIT-A>
+ remote: # post-receive hook
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/pull/123/head
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/topic
+ remote: post-receive< <COMMIT-B> <COMMIT-A> refs/pull/124/head
+ To <URL/of/upstream.git>
+ * HEAD:refs/pull/123/head [new reference]
+ * HEAD:refs/for/a/b/c/topic [new reference]
+ + HEAD:refs/pull/124/head <OID-B>...<OID-A> (forced update)
+ Done
+ EOF
+ test_cmp expect actual &&
+
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
diff --git a/t/t5411/test-0034-report-ft.sh b/t/t5411/test-0034-report-ft.sh
new file mode 100644
index 0000000..aca2b06
--- /dev/null
+++ b/t/t5411/test-0034-report-ft.sh
@@ -0,0 +1,44 @@
+test_expect_success "setup proc-receive hook (ft, $PROTOCOL)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/master/topic" \
+ -r "option fall-through"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/master/topic(B)
+test_expect_success "proc-receive: fall throught, let receive-pack to execute ($PROTOCOL)" '
+ git -C workbench push origin \
+ $B:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-B> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-B> refs/for/master/topic
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option fall-through
+ remote: # post-receive hook
+ remote: post-receive< <ZERO-OID> <COMMIT-B> refs/for/master/topic
+ To <URL/of/upstream.git>
+ * [new reference] <COMMIT-B> -> refs/for/master/topic
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-B> refs/for/master/topic
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
+
+# Refs of upstream : master(A) refs/for/master/topic(A)
+# Refs of workbench: master(A) tags/v123
+test_expect_success "cleanup ($PROTOCOL)" '
+ git -C "$upstream" update-ref -d refs/for/master/topic
+'
diff --git a/t/t5411/test-0035-report-ft--porcelain.sh b/t/t5411/test-0035-report-ft--porcelain.sh
new file mode 100644
index 0000000..30ffffb
--- /dev/null
+++ b/t/t5411/test-0035-report-ft--porcelain.sh
@@ -0,0 +1,45 @@
+test_expect_success "setup proc-receive hook (fall-through, $PROTOCOL/porcelain)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/master/topic" \
+ -r "option fall-through"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/master/topic(B)
+test_expect_success "proc-receive: fall throught, let receive-pack to execute ($PROTOCOL/porcelain)" '
+ git -C workbench push --porcelain origin \
+ $B:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-B> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-B> refs/for/master/topic
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option fall-through
+ remote: # post-receive hook
+ remote: post-receive< <ZERO-OID> <COMMIT-B> refs/for/master/topic
+ To <URL/of/upstream.git>
+ * <COMMIT-B>:refs/for/master/topic [new reference]
+ Done
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-B> refs/for/master/topic
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
+
+# Refs of upstream : master(A) refs/for/master/topic(A)
+# Refs of workbench: master(A) tags/v123
+test_expect_success "cleanup ($PROTOCOL/porcelain)" '
+ git -C "$upstream" update-ref -d refs/for/master/topic
+'
diff --git a/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh b/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh
new file mode 100644
index 0000000..73283d8
--- /dev/null
+++ b/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh
@@ -0,0 +1,227 @@
+test_expect_success "setup git config for remote-tracking of special refs" '
+ (
+ cd workbench &&
+ if ! git config --get-all remote.origin.fetch | grep refs/for/
+ then
+ git config --add remote.origin.fetch \
+ "+refs/for/*:refs/t/for/*" &&
+ git config --add remote.origin.fetch \
+ "+refs/pull/*:refs/t/pull/*" &&
+ git config --add remote.origin.fetch \
+ "+refs/changes/*:refs/t/changes/*"
+ fi
+ )
+'
+
+test_expect_success "setup proc-receive hook (multiple rewrites for one ref, no refname for the 1st rewrite, $PROTOCOL)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/master/topic" \
+ -r "option old-oid $A" \
+ -r "option new-oid $B" \
+ -r "ok refs/for/master/topic" \
+ -r "option refname refs/changes/24/124/1" \
+ -r "option old-oid $ZERO_OID" \
+ -r "option new-oid $A" \
+ -r "ok refs/for/master/topic" \
+ -r "option refname refs/changes/25/125/1" \
+ -r "option old-oid $A" \
+ -r "option new-oid $B"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/master/topic(A)
+test_expect_success "proc-receive: multiple rewrite for one ref, no refname for the 1st rewrite ($PROTOCOL)" '
+ git -C workbench push origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option old-oid <COMMIT-A>
+ remote: proc-receive> option new-oid <COMMIT-B>
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option refname refs/changes/24/124/1
+ remote: proc-receive> option old-oid <ZERO-OID>
+ remote: proc-receive> option new-oid <COMMIT-A>
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option refname refs/changes/25/125/1
+ remote: proc-receive> option old-oid <COMMIT-A>
+ remote: proc-receive> option new-oid <COMMIT-B>
+ remote: # post-receive hook
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/master/topic
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/changes/24/124/1
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/changes/25/125/1
+ To <URL/of/upstream.git>
+ <OID-A>..<OID-B> HEAD -> refs/for/master/topic
+ * [new reference] HEAD -> refs/changes/24/124/1
+ <OID-A>..<OID-B> HEAD -> refs/changes/25/125/1
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "proc-receive: check remote-tracking #1 ($PROTOCOL)" '
+ git -C workbench show-ref |
+ grep -v -e refs/remotes -e refs/heads -e refs/tags >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/t/changes/24/124/1
+ <COMMIT-B> refs/t/changes/25/125/1
+ <COMMIT-B> refs/t/for/master/topic
+ EOF
+ test_cmp expect actual &&
+ git -C workbench update-ref -d refs/t/for/master/topic &&
+ git -C workbench update-ref -d refs/t/changes/24/124/1 &&
+ git -C workbench update-ref -d refs/t/changes/25/125/1
+'
+
+test_expect_success "setup proc-receive hook (multiple rewrites for one ref, no refname for the 2nd rewrite, $PROTOCOL)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/master/topic" \
+ -r "option refname refs/changes/24/124/1" \
+ -r "option old-oid $ZERO_OID" \
+ -r "option new-oid $A" \
+ -r "ok refs/for/master/topic" \
+ -r "option old-oid $A" \
+ -r "option new-oid $B" \
+ -r "ok refs/for/master/topic" \
+ -r "option refname refs/changes/25/125/1" \
+ -r "option old-oid $B" \
+ -r "option new-oid $A" \
+ -r "option forced-update"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/master/topic(A)
+test_expect_success "proc-receive: multiple rewrites for one ref, no refname for the 2nd rewrite ($PROTOCOL)" '
+ git -C workbench push origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option refname refs/changes/24/124/1
+ remote: proc-receive> option old-oid <ZERO-OID>
+ remote: proc-receive> option new-oid <COMMIT-A>
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option old-oid <COMMIT-A>
+ remote: proc-receive> option new-oid <COMMIT-B>
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option refname refs/changes/25/125/1
+ remote: proc-receive> option old-oid <COMMIT-B>
+ remote: proc-receive> option new-oid <COMMIT-A>
+ remote: proc-receive> option forced-update
+ remote: # post-receive hook
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/changes/24/124/1
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/master/topic
+ remote: post-receive< <COMMIT-B> <COMMIT-A> refs/changes/25/125/1
+ To <URL/of/upstream.git>
+ * [new reference] HEAD -> refs/changes/24/124/1
+ <OID-A>..<OID-B> HEAD -> refs/for/master/topic
+ + <OID-B>...<OID-A> HEAD -> refs/changes/25/125/1 (forced update)
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "proc-receive: check remote-tracking #2 ($PROTOCOL)" '
+ git -C workbench show-ref |
+ grep -v -e refs/remotes -e refs/heads -e refs/tags >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/t/changes/24/124/1
+ <COMMIT-A> refs/t/changes/25/125/1
+ <COMMIT-B> refs/t/for/master/topic
+ EOF
+ test_cmp expect actual &&
+ git -C workbench update-ref -d refs/t/for/master/topic &&
+ git -C workbench update-ref -d refs/t/changes/24/124/1 &&
+ git -C workbench update-ref -d refs/t/changes/25/125/1
+'
+
+test_expect_success "setup proc-receive hook (multiple rewrites for one ref, $PROTOCOL)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/master/topic" \
+ -r "option refname refs/changes/23/123/1" \
+ -r "ok refs/for/master/topic" \
+ -r "option refname refs/changes/24/124/2" \
+ -r "option old-oid $A" \
+ -r "option new-oid $B"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/master/topic(A)
+test_expect_success "proc-receive: multiple rewrites for one ref ($PROTOCOL)" '
+ git -C workbench push origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option refname refs/changes/23/123/1
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option refname refs/changes/24/124/2
+ remote: proc-receive> option old-oid <COMMIT-A>
+ remote: proc-receive> option new-oid <COMMIT-B>
+ remote: # post-receive hook
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/changes/23/123/1
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/changes/24/124/2
+ To <URL/of/upstream.git>
+ * [new reference] HEAD -> refs/changes/23/123/1
+ <OID-A>..<OID-B> HEAD -> refs/changes/24/124/2
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "proc-receive: check remote-tracking #3 ($PROTOCOL)" '
+ git -C workbench show-ref |
+ grep -v -e refs/remotes -e refs/heads -e refs/tags >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/t/changes/23/123/1
+ <COMMIT-B> refs/t/changes/24/124/2
+ EOF
+ test_cmp expect actual &&
+ git -C workbench update-ref -d refs/t/changes/24/124/1 &&
+ git -C workbench update-ref -d refs/t/changes/25/125/2
+'
diff --git a/t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh b/t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh
new file mode 100644
index 0000000..77b5b22
--- /dev/null
+++ b/t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh
@@ -0,0 +1,172 @@
+test_expect_success "setup proc-receive hook (multiple rewrites for one ref, no refname for the 1st rewrite, $PROTOCOL/porcelain)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/master/topic" \
+ -r "option old-oid $A" \
+ -r "option new-oid $B" \
+ -r "ok refs/for/master/topic" \
+ -r "option refname refs/changes/24/124/1" \
+ -r "option old-oid $ZERO_OID" \
+ -r "option new-oid $A" \
+ -r "ok refs/for/master/topic" \
+ -r "option refname refs/changes/25/125/1" \
+ -r "option old-oid $A" \
+ -r "option new-oid $B"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/master/topic(A)
+test_expect_success "proc-receive: multiple rewrite for one ref, no refname for the 1st rewrite ($PROTOCOL/porcelain)" '
+ git -C workbench push --porcelain origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option old-oid <COMMIT-A>
+ remote: proc-receive> option new-oid <COMMIT-B>
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option refname refs/changes/24/124/1
+ remote: proc-receive> option old-oid <ZERO-OID>
+ remote: proc-receive> option new-oid <COMMIT-A>
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option refname refs/changes/25/125/1
+ remote: proc-receive> option old-oid <COMMIT-A>
+ remote: proc-receive> option new-oid <COMMIT-B>
+ remote: # post-receive hook
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/master/topic
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/changes/24/124/1
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/changes/25/125/1
+ To <URL/of/upstream.git>
+ HEAD:refs/for/master/topic <OID-A>..<OID-B>
+ * HEAD:refs/changes/24/124/1 [new reference]
+ HEAD:refs/changes/25/125/1 <OID-A>..<OID-B>
+ Done
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "setup proc-receive hook (multiple rewrites for one ref, no refname for the 2nd rewrite, $PROTOCOL/porcelain)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/master/topic" \
+ -r "option refname refs/changes/24/124/1" \
+ -r "option old-oid $ZERO_OID" \
+ -r "option new-oid $A" \
+ -r "ok refs/for/master/topic" \
+ -r "option old-oid $A" \
+ -r "option new-oid $B" \
+ -r "ok refs/for/master/topic" \
+ -r "option refname refs/changes/25/125/1" \
+ -r "option old-oid $B" \
+ -r "option new-oid $A" \
+ -r "option forced-update"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/master/topic(A)
+test_expect_success "proc-receive: multiple rewrites for one ref, no refname for the 2nd rewrite ($PROTOCOL/porcelain)" '
+ git -C workbench push --porcelain origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option refname refs/changes/24/124/1
+ remote: proc-receive> option old-oid <ZERO-OID>
+ remote: proc-receive> option new-oid <COMMIT-A>
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option old-oid <COMMIT-A>
+ remote: proc-receive> option new-oid <COMMIT-B>
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option refname refs/changes/25/125/1
+ remote: proc-receive> option old-oid <COMMIT-B>
+ remote: proc-receive> option new-oid <COMMIT-A>
+ remote: proc-receive> option forced-update
+ remote: # post-receive hook
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/changes/24/124/1
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/master/topic
+ remote: post-receive< <COMMIT-B> <COMMIT-A> refs/changes/25/125/1
+ To <URL/of/upstream.git>
+ * HEAD:refs/changes/24/124/1 [new reference]
+ HEAD:refs/for/master/topic <OID-A>..<OID-B>
+ + HEAD:refs/changes/25/125/1 <OID-B>...<OID-A> (forced update)
+ Done
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "setup proc-receive hook (multiple rewrites for one ref, $PROTOCOL/porcelain)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/master/topic" \
+ -r "option refname refs/changes/23/123/1" \
+ -r "ok refs/for/master/topic" \
+ -r "option refname refs/changes/24/124/2" \
+ -r "option old-oid $A" \
+ -r "option new-oid $B"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : refs/for/master/topic(A)
+test_expect_success "proc-receive: multiple rewrites for one ref ($PROTOCOL/porcelain)" '
+ git -C workbench push --porcelain origin \
+ HEAD:refs/for/master/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option refname refs/changes/23/123/1
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option refname refs/changes/24/124/2
+ remote: proc-receive> option old-oid <COMMIT-A>
+ remote: proc-receive> option new-oid <COMMIT-B>
+ remote: # post-receive hook
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/changes/23/123/1
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/changes/24/124/2
+ To <URL/of/upstream.git>
+ * HEAD:refs/changes/23/123/1 [new reference]
+ HEAD:refs/changes/24/124/2 <OID-A>..<OID-B>
+ Done
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
diff --git a/t/t5411/test-0038-report-mixed-refs.sh b/t/t5411/test-0038-report-mixed-refs.sh
new file mode 100644
index 0000000..a74a2cb
--- /dev/null
+++ b/t/t5411/test-0038-report-mixed-refs.sh
@@ -0,0 +1,89 @@
+test_expect_success "setup proc-receive hook ($PROTOCOL)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/next/topic2" \
+ -r "ng refs/for/next/topic1 fail to call Web API" \
+ -r "ok refs/for/master/topic" \
+ -r "option refname refs/for/master/topic" \
+ -r "option old-oid $A" \
+ -r "option new-oid $B"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : (B) bar(A) baz(A) refs/for/next/topic(A) foo(A) refs/for/master/topic(A)
+test_expect_success "proc-receive: report update of mixed refs ($PROTOCOL)" '
+ test_must_fail git -C workbench push origin \
+ $B:refs/heads/master \
+ HEAD:refs/heads/bar \
+ HEAD:refs/heads/baz \
+ HEAD:refs/for/next/topic2 \
+ HEAD:refs/for/next/topic1 \
+ HEAD:refs/heads/foo \
+ HEAD:refs/for/master/topic \
+ HEAD:refs/for/next/topic3 \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/master
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/bar
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/baz
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic2
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic1
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/foo
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic3
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic2
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic1
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic3
+ remote: proc-receive> ok refs/for/next/topic2
+ remote: proc-receive> ng refs/for/next/topic1 fail to call Web API
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option refname refs/for/master/topic
+ remote: proc-receive> option old-oid <COMMIT-A>
+ remote: proc-receive> option new-oid <COMMIT-B>
+ remote: # post-receive hook
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/master
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/bar
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/baz
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic2
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/foo
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/master/topic
+ To <URL/of/upstream.git>
+ <OID-A>..<OID-B> <COMMIT-B> -> master
+ * [new branch] HEAD -> bar
+ * [new branch] HEAD -> baz
+ * [new reference] HEAD -> refs/for/next/topic2
+ * [new branch] HEAD -> foo
+ <OID-A>..<OID-B> HEAD -> refs/for/master/topic
+ ! [remote rejected] HEAD -> refs/for/next/topic1 (fail to call Web API)
+ ! [remote rejected] HEAD -> refs/for/next/topic3 (proc-receive failed to report status)
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/bar
+ <COMMIT-A> refs/heads/baz
+ <COMMIT-A> refs/heads/foo
+ <COMMIT-B> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
+
+# Refs of upstream : master(B) foo(A) bar(A)) baz(A)
+# Refs of workbench: master(A) tags/v123
+test_expect_success "cleanup ($PROTOCOL)" '
+ (
+ cd "$upstream" &&
+ git update-ref refs/heads/master $A &&
+ git update-ref -d refs/heads/foo &&
+ git update-ref -d refs/heads/bar &&
+ git update-ref -d refs/heads/baz
+ )
+'
diff --git a/t/t5411/test-0039-report-mixed-refs--porcelain.sh b/t/t5411/test-0039-report-mixed-refs--porcelain.sh
new file mode 100644
index 0000000..e4baa13
--- /dev/null
+++ b/t/t5411/test-0039-report-mixed-refs--porcelain.sh
@@ -0,0 +1,91 @@
+test_expect_success "setup proc-receive hook ($PROTOCOL/porcelain)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/for/next/topic2" \
+ -r "ng refs/for/next/topic1 fail to call Web API" \
+ -r "ok refs/for/master/topic" \
+ -r "option refname refs/for/master/topic" \
+ -r "option old-oid $A" \
+ -r "option new-oid $B"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : (B) bar(A) baz(A) refs/for/next/topic(A) foo(A) refs/for/master/topic(A)
+test_expect_success "proc-receive: report update of mixed refs ($PROTOCOL/porcelain)" '
+ test_must_fail git -C workbench push --porcelain origin \
+ $B:refs/heads/master \
+ HEAD:refs/heads/bar \
+ HEAD:refs/heads/baz \
+ HEAD:refs/for/next/topic2 \
+ HEAD:refs/for/next/topic1 \
+ HEAD:refs/heads/foo \
+ HEAD:refs/for/master/topic \
+ HEAD:refs/for/next/topic3 \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/master
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/bar
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/baz
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic2
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic1
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/foo
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic3
+ remote: # proc-receive hook
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic2
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic1
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic3
+ remote: proc-receive> ok refs/for/next/topic2
+ remote: proc-receive> ng refs/for/next/topic1 fail to call Web API
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option refname refs/for/master/topic
+ remote: proc-receive> option old-oid <COMMIT-A>
+ remote: proc-receive> option new-oid <COMMIT-B>
+ remote: # post-receive hook
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/master
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/bar
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/baz
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic2
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/foo
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/master/topic
+ To <URL/of/upstream.git>
+ <COMMIT-B>:refs/heads/master <OID-A>..<OID-B>
+ * HEAD:refs/heads/bar [new branch]
+ * HEAD:refs/heads/baz [new branch]
+ * HEAD:refs/for/next/topic2 [new reference]
+ * HEAD:refs/heads/foo [new branch]
+ HEAD:refs/for/master/topic <OID-A>..<OID-B>
+ ! HEAD:refs/for/next/topic1 [remote rejected] (fail to call Web API)
+ ! HEAD:refs/for/next/topic3 [remote rejected] (proc-receive failed to report status)
+ Done
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/bar
+ <COMMIT-A> refs/heads/baz
+ <COMMIT-A> refs/heads/foo
+ <COMMIT-B> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
+
+# Refs of upstream : master(B) foo(A) bar(A)) baz(A)
+# Refs of workbench: master(A) tags/v123
+test_expect_success "cleanup ($PROTOCOL/porcelain)" '
+ (
+ cd "$upstream" &&
+ git update-ref refs/heads/master $A &&
+ git update-ref -d refs/heads/foo &&
+ git update-ref -d refs/heads/bar &&
+ git update-ref -d refs/heads/baz
+ )
+
+'
diff --git a/t/t5411/test-0040-process-all-refs.sh b/t/t5411/test-0040-process-all-refs.sh
new file mode 100644
index 0000000..b07c999
--- /dev/null
+++ b/t/t5411/test-0040-process-all-refs.sh
@@ -0,0 +1,113 @@
+test_expect_success "config receive.procReceiveRefs = refs ($PROTOCOL)" '
+ git -C "$upstream" config --unset-all receive.procReceiveRefs &&
+ git -C "$upstream" config --add receive.procReceiveRefs refs
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+test_expect_success "setup upstream branches ($PROTOCOL)" '
+ (
+ cd "$upstream" &&
+ git update-ref refs/heads/master $B &&
+ git update-ref refs/heads/foo $A &&
+ git update-ref refs/heads/bar $A &&
+ git update-ref refs/heads/baz $A
+ )
+
+'
+
+test_expect_success "setup proc-receive hook ($PROTOCOL)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/heads/master" \
+ -r "option fall-through" \
+ -r "ok refs/heads/foo" \
+ -r "option fall-through" \
+ -r "ok refs/heads/bar" \
+ -r "option fall-through" \
+ -r "ok refs/for/master/topic" \
+ -r "option refname refs/pull/123/head" \
+ -r "option old-oid $A" \
+ -r "option new-oid $B" \
+ -r "ok refs/for/next/topic" \
+ -r "option refname refs/pull/124/head" \
+ -r "option old-oid $B" \
+ -r "option new-oid $A" \
+ -r "option forced-update"
+ EOF
+'
+
+# Refs of upstream : master(B) foo(A) bar(A)) baz(A)
+# Refs of workbench: master(A) tags/v123
+# git push -f : master(A) (NULL) (B) refs/for/master/topic(A) refs/for/next/topic(A)
+test_expect_success "proc-receive: process all refs ($PROTOCOL)" '
+ git -C workbench push -f origin \
+ HEAD:refs/heads/master \
+ :refs/heads/foo \
+ $B:refs/heads/bar \
+ HEAD:refs/for/master/topic \
+ HEAD:refs/for/next/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar
+ remote: pre-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo
+ remote: pre-receive< <COMMIT-B> <COMMIT-A> refs/heads/master
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar
+ remote: proc-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo
+ remote: proc-receive< <COMMIT-B> <COMMIT-A> refs/heads/master
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
+ remote: proc-receive> ok refs/heads/master
+ remote: proc-receive> option fall-through
+ remote: proc-receive> ok refs/heads/foo
+ remote: proc-receive> option fall-through
+ remote: proc-receive> ok refs/heads/bar
+ remote: proc-receive> option fall-through
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option refname refs/pull/123/head
+ remote: proc-receive> option old-oid <COMMIT-A>
+ remote: proc-receive> option new-oid <COMMIT-B>
+ remote: proc-receive> ok refs/for/next/topic
+ remote: proc-receive> option refname refs/pull/124/head
+ remote: proc-receive> option old-oid <COMMIT-B>
+ remote: proc-receive> option new-oid <COMMIT-A>
+ remote: proc-receive> option forced-update
+ remote: # post-receive hook
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar
+ remote: post-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo
+ remote: post-receive< <COMMIT-B> <COMMIT-A> refs/heads/master
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/pull/123/head
+ remote: post-receive< <COMMIT-B> <COMMIT-A> refs/pull/124/head
+ To <URL/of/upstream.git>
+ <OID-A>..<OID-B> <COMMIT-B> -> bar
+ - [deleted] foo
+ + <OID-B>...<OID-A> HEAD -> master (forced update)
+ <OID-A>..<OID-B> HEAD -> refs/pull/123/head
+ + <OID-B>...<OID-A> HEAD -> refs/pull/124/head (forced update)
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-B> refs/heads/bar
+ <COMMIT-A> refs/heads/baz
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
+
+# Refs of upstream : master(A) bar(A) baz(B)
+# Refs of workbench: master(A) tags/v123
+test_expect_success "cleanup ($PROTOCOL)" '
+ (
+ cd "$upstream" &&
+ git update-ref -d refs/heads/bar &&
+ git update-ref -d refs/heads/baz
+ )
+'
diff --git a/t/t5411/test-0041-process-all-refs--porcelain.sh b/t/t5411/test-0041-process-all-refs--porcelain.sh
new file mode 100644
index 0000000..0dd9824
--- /dev/null
+++ b/t/t5411/test-0041-process-all-refs--porcelain.sh
@@ -0,0 +1,114 @@
+test_expect_success "config receive.procReceiveRefs = refs ($PROTOCOL/porcelain)" '
+ git -C "$upstream" config --unset-all receive.procReceiveRefs &&
+ git -C "$upstream" config --add receive.procReceiveRefs refs
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+test_expect_success "setup upstream branches ($PROTOCOL/porcelain)" '
+ (
+ cd "$upstream" &&
+ git update-ref refs/heads/master $B &&
+ git update-ref refs/heads/foo $A &&
+ git update-ref refs/heads/bar $A &&
+ git update-ref refs/heads/baz $A
+ )
+
+'
+
+test_expect_success "setup proc-receive hook ($PROTOCOL/porcelain)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/heads/master" \
+ -r "option fall-through" \
+ -r "ok refs/heads/foo" \
+ -r "option fall-through" \
+ -r "ok refs/heads/bar" \
+ -r "option fall-through" \
+ -r "ok refs/for/master/topic" \
+ -r "option refname refs/pull/123/head" \
+ -r "option old-oid $A" \
+ -r "option new-oid $B" \
+ -r "ok refs/for/next/topic" \
+ -r "option refname refs/pull/124/head" \
+ -r "option old-oid $B" \
+ -r "option new-oid $A" \
+ -r "option forced-update"
+ EOF
+'
+
+# Refs of upstream : master(B) foo(A) bar(A)) baz(A)
+# Refs of workbench: master(A) tags/v123
+# git push -f : master(A) (NULL) (B) refs/for/master/topic(A) refs/for/next/topic(A)
+test_expect_success "proc-receive: process all refs ($PROTOCOL/porcelain)" '
+ git -C workbench push --porcelain -f origin \
+ HEAD:refs/heads/master \
+ :refs/heads/foo \
+ $B:refs/heads/bar \
+ HEAD:refs/for/master/topic \
+ HEAD:refs/for/next/topic \
+ >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar
+ remote: pre-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo
+ remote: pre-receive< <COMMIT-B> <COMMIT-A> refs/heads/master
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
+ remote: # proc-receive hook
+ remote: proc-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar
+ remote: proc-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo
+ remote: proc-receive< <COMMIT-B> <COMMIT-A> refs/heads/master
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
+ remote: proc-receive> ok refs/heads/master
+ remote: proc-receive> option fall-through
+ remote: proc-receive> ok refs/heads/foo
+ remote: proc-receive> option fall-through
+ remote: proc-receive> ok refs/heads/bar
+ remote: proc-receive> option fall-through
+ remote: proc-receive> ok refs/for/master/topic
+ remote: proc-receive> option refname refs/pull/123/head
+ remote: proc-receive> option old-oid <COMMIT-A>
+ remote: proc-receive> option new-oid <COMMIT-B>
+ remote: proc-receive> ok refs/for/next/topic
+ remote: proc-receive> option refname refs/pull/124/head
+ remote: proc-receive> option old-oid <COMMIT-B>
+ remote: proc-receive> option new-oid <COMMIT-A>
+ remote: proc-receive> option forced-update
+ remote: # post-receive hook
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar
+ remote: post-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo
+ remote: post-receive< <COMMIT-B> <COMMIT-A> refs/heads/master
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/pull/123/head
+ remote: post-receive< <COMMIT-B> <COMMIT-A> refs/pull/124/head
+ To <URL/of/upstream.git>
+ <COMMIT-B>:refs/heads/bar <OID-A>..<OID-B>
+ - :refs/heads/foo [deleted]
+ + HEAD:refs/heads/master <OID-B>...<OID-A> (forced update)
+ HEAD:refs/pull/123/head <OID-A>..<OID-B>
+ + HEAD:refs/pull/124/head <OID-B>...<OID-A> (forced update)
+ Done
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-B> refs/heads/bar
+ <COMMIT-A> refs/heads/baz
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
+
+# Refs of upstream : master(A) bar(A) baz(B)
+# Refs of workbench: master(A) tags/v123
+test_expect_success "cleanup ($PROTOCOL/porcelain)" '
+ (
+ cd "$upstream" &&
+ git update-ref -d refs/heads/bar &&
+ git update-ref -d refs/heads/baz
+ )
+'
diff --git a/t/t5411/test-0050-proc-receive-refs-with-modifiers.sh b/t/t5411/test-0050-proc-receive-refs-with-modifiers.sh
new file mode 100644
index 0000000..c22849c
--- /dev/null
+++ b/t/t5411/test-0050-proc-receive-refs-with-modifiers.sh
@@ -0,0 +1,135 @@
+test_expect_success "config receive.procReceiveRefs with modifiers ($PROTOCOL)" '
+ (
+ cd "$upstream" &&
+ git config --unset-all receive.procReceiveRefs &&
+ git config --add receive.procReceiveRefs m:refs/heads/master &&
+ git config --add receive.procReceiveRefs ad:refs/heads &&
+ git config --add receive.procReceiveRefs "a!:refs/heads"
+ )
+'
+
+test_expect_success "setup proc-receive hook ($PROTOCOL)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/heads/master" \
+ -r "option refname refs/pull/123/head" \
+ -r "option old-oid $A" \
+ -r "option new-oid $B" \
+ -r "ok refs/tags/v123 " \
+ -r "option refname refs/pull/124/head"
+ EOF
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+# git push : master(B) tags/v123
+test_expect_success "proc-receive: update branch and new tag ($PROTOCOL)" '
+ git -C workbench push origin \
+ $B:refs/heads/master \
+ v123 >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/master
+ remote: pre-receive< <ZERO-OID> <TAG-v123> refs/tags/v123
+ remote: # proc-receive hook
+ remote: proc-receive< <COMMIT-A> <COMMIT-B> refs/heads/master
+ remote: proc-receive< <ZERO-OID> <TAG-v123> refs/tags/v123
+ remote: proc-receive> ok refs/heads/master
+ remote: proc-receive> option refname refs/pull/123/head
+ remote: proc-receive> option old-oid <COMMIT-A>
+ remote: proc-receive> option new-oid <COMMIT-B>
+ remote: proc-receive> ok refs/tags/v123
+ remote: proc-receive> option refname refs/pull/124/head
+ remote: # post-receive hook
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/pull/123/head
+ remote: post-receive< <ZERO-OID> <TAG-v123> refs/pull/124/head
+ To <URL/of/upstream.git>
+ <OID-A>..<OID-B> <COMMIT-B> -> refs/pull/123/head
+ * [new reference] v123 -> refs/pull/124/head
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ EOF
+ test_cmp expect actual
+'
+
+# Refs of upstream : master(A)
+# Refs of workbench: master(A) tags/v123
+test_expect_success "setup upstream: create tags/v123 ($PROTOCOL)" '
+ git -C "$upstream" update-ref refs/heads/topic $A &&
+ git -C "$upstream" update-ref refs/tags/v123 $TAG &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ <COMMIT-A> refs/heads/topic
+ <TAG-v123> refs/tags/v123
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success "setup proc-receive hook ($PROTOCOL)" '
+ write_script "$upstream/hooks/proc-receive" <<-EOF
+ printf >&2 "# proc-receive hook\n"
+ test-tool proc-receive -v \
+ -r "ok refs/heads/master" \
+ -r "option refname refs/pull/123/head" \
+ -r "option old-oid $A" \
+ -r "option new-oid $ZERO_OID" \
+ -r "ok refs/heads/next" \
+ -r "option refname refs/pull/124/head" \
+ -r "option new-oid $A"
+ EOF
+'
+
+# Refs of upstream : master(A) topic(A) tags/v123
+# Refs of workbench: master(A) tags/v123
+# git push : NULL topic(B) NULL next(A)
+test_expect_success "proc-receive: create/delete branch, and delete tag ($PROTOCOL)" '
+ git -C workbench push origin \
+ :refs/heads/master \
+ $B:refs/heads/topic \
+ $A:refs/heads/next \
+ :refs/tags/v123 >out 2>&1 &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ remote: # pre-receive hook
+ remote: pre-receive< <COMMIT-A> <ZERO-OID> refs/heads/master
+ remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/topic
+ remote: pre-receive< <TAG-v123> <ZERO-OID> refs/tags/v123
+ remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
+ remote: # proc-receive hook
+ remote: proc-receive< <COMMIT-A> <ZERO-OID> refs/heads/master
+ remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/heads/next
+ remote: proc-receive> ok refs/heads/master
+ remote: proc-receive> option refname refs/pull/123/head
+ remote: proc-receive> option old-oid <COMMIT-A>
+ remote: proc-receive> option new-oid <ZERO-OID>
+ remote: proc-receive> ok refs/heads/next
+ remote: proc-receive> option refname refs/pull/124/head
+ remote: proc-receive> option new-oid <COMMIT-A>
+ remote: # post-receive hook
+ remote: post-receive< <COMMIT-A> <ZERO-OID> refs/pull/123/head
+ remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/topic
+ remote: post-receive< <TAG-v123> <ZERO-OID> refs/tags/v123
+ remote: post-receive< <ZERO-OID> <COMMIT-A> refs/pull/124/head
+ To <URL/of/upstream.git>
+ - [deleted] refs/pull/123/head
+ <OID-A>..<OID-B> <COMMIT-B> -> topic
+ - [deleted] v123
+ * [new reference] <COMMIT-A> -> refs/pull/124/head
+ EOF
+ test_cmp expect actual &&
+ git -C "$upstream" show-ref >out &&
+ make_user_friendly_and_stable_output <out >actual &&
+ cat >expect <<-EOF &&
+ <COMMIT-A> refs/heads/master
+ <COMMIT-B> refs/heads/topic
+ EOF
+ test_cmp expect actual
+'
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 759aec9..dbc724e 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -936,7 +936,7 @@ test_expect_success 'fetching with auto-gc does not lock up' '
git config fetch.unpackLimit 1 &&
git config gc.autoPackLimit 1 &&
git config gc.autoDetach false &&
- GIT_ASK_YESNO="$D/askyesno" git fetch >fetch.out 2>&1 &&
+ GIT_ASK_YESNO="$D/askyesno" git fetch --verbose >fetch.out 2>&1 &&
test_i18ngrep "Auto packing the repository" fetch.out &&
! grep "Should I try again" fetch.out
)
diff --git a/t/t5514-fetch-multiple.sh b/t/t5514-fetch-multiple.sh
index de8e2f1..bd202ec 100755
--- a/t/t5514-fetch-multiple.sh
+++ b/t/t5514-fetch-multiple.sh
@@ -108,7 +108,7 @@ test_expect_success 'git fetch --multiple (two remotes)' '
GIT_TRACE=1 git fetch --multiple one two 2>trace &&
git branch -r > output &&
test_cmp ../expect output &&
- grep "built-in: git gc" trace >gc &&
+ grep "built-in: git maintenance" trace >gc &&
test_line_count = 1 gc
)
'
diff --git a/t/t5515-fetch-merge-logic.sh b/t/t5515-fetch-merge-logic.sh
index 9d6a46f..70a9d2d 100755
--- a/t/t5515-fetch-merge-logic.sh
+++ b/t/t5515-fetch-merge-logic.sh
@@ -15,7 +15,7 @@ export GIT_TEST_PROTOCOL_VERSION
build_script () {
script="$1" &&
- for i in one three_file master master2 one_tree three two two2 three2
+ for i in one three_file master topic_2 one_tree three two two2 three2
do
echo "s/$(test_oid --hash=sha1 "$i")/$(test_oid "$i")/g" >>"$script"
done
@@ -52,8 +52,8 @@ test_expect_success setup '
two sha1:525b7fb068d59950d185a8779dc957c77eed73ba
two sha256:3b21de3440cd38c2a9e9b464adb923f7054949ed4c918e1a0ac4c95cd52774db
- master2 sha1:754b754407bf032e9a2f9d5a9ad05ca79a6b228f
- master2 sha256:6c7abaea8a6d8ef4d89877e68462758dc6774690fbbbb0e6d7dd57415c9abde0
+ topic_2 sha1:754b754407bf032e9a2f9d5a9ad05ca79a6b228f
+ topic_2 sha256:6c7abaea8a6d8ef4d89877e68462758dc6774690fbbbb0e6d7dd57415c9abde0
two2 sha1:6134ee8f857693b96ff1cc98d3e2fd62b199e5a8
two2 sha256:87a2d3ee29c83a3dc7afd41c0606b11f67603120b910a7be7840accdc18344d4
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 36ad20a..d11382f 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -1039,7 +1039,7 @@ test_force_fetch_tag "annotated tag" "-f -a -m'tag message'"
test_expect_success 'push --porcelain' '
mk_empty testrepo &&
echo >.git/foo "To testrepo" &&
- echo >>.git/foo "* refs/heads/master:refs/remotes/origin/master [new branch]" &&
+ echo >>.git/foo "* refs/heads/master:refs/remotes/origin/master [new reference]" &&
echo >>.git/foo "Done" &&
git push >.git/bar --porcelain testrepo refs/heads/master:refs/remotes/origin/master &&
(
diff --git a/t/t5523-push-upstream.sh b/t/t5523-push-upstream.sh
index c0df81a..e47b5db 100755
--- a/t/t5523-push-upstream.sh
+++ b/t/t5523-push-upstream.sh
@@ -41,20 +41,20 @@ test_expect_success 'push -u --dry-run master:otherX' '
check_config master upstream refs/heads/other
'
-test_expect_success 'push -u master2:master2' '
- git branch master2 &&
- git push -u upstream master2:master2 &&
- check_config master2 upstream refs/heads/master2
+test_expect_success 'push -u topic_2:topic_2' '
+ git branch topic_2 &&
+ git push -u upstream topic_2:topic_2 &&
+ check_config topic_2 upstream refs/heads/topic_2
'
-test_expect_success 'push -u master2:other2' '
- git push -u upstream master2:other2 &&
- check_config master2 upstream refs/heads/other2
+test_expect_success 'push -u topic_2:other2' '
+ git push -u upstream topic_2:other2 &&
+ check_config topic_2 upstream refs/heads/other2
'
-test_expect_success 'push -u :master2' '
- git push -u upstream :master2 &&
- check_config master2 upstream refs/heads/other2
+test_expect_success 'push -u :topic_2' '
+ git push -u upstream :topic_2 &&
+ check_config topic_2 upstream refs/heads/other2
'
test_expect_success 'push -u --all' '
diff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh
index 030331f..7e928af 100755
--- a/t/t5534-push-signed.sh
+++ b/t/t5534-push-signed.sh
@@ -273,4 +273,27 @@ test_expect_success GPGSM 'fail without key and heed user.signingkey x509' '
test_cmp expect dst/push-cert-status
'
+test_expect_success GPG 'failed atomic push does not execute GPG' '
+ prepare_dst &&
+ git -C dst config receive.certnonceseed sekrit &&
+ write_script gpg <<-EOF &&
+ # should check atomic push locally before running GPG.
+ exit 1
+ EOF
+ test_must_fail env PATH="$TRASH_DIRECTORY:$PATH" git push \
+ --signed --atomic --porcelain \
+ dst noop ff noff >out 2>&1 &&
+
+ test_i18ngrep ! "gpg failed to sign" out &&
+ sed -n -e "/^To dst/,$ p" out >actual &&
+ cat >expect <<-EOF &&
+ To dst
+ = refs/heads/noop:refs/heads/noop [up to date]
+ ! refs/heads/ff:refs/heads/ff [rejected] (atomic push failed)
+ ! refs/heads/noff:refs/heads/noff [rejected] (non-fast-forward)
+ Done
+ EOF
+ test_i18ncmp expect actual
+'
+
test_done
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 15fb64c..b6c8312 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -631,6 +631,20 @@ test_expect_success CASE_INSENSITIVE_FS 'colliding file detection' '
test_i18ngrep "the following paths have collided" icasefs/warning
'
+test_expect_success 'clone with GIT_DEFAULT_HASH' '
+ (
+ sane_unset GIT_DEFAULT_HASH &&
+ git init --object-format=sha1 test-sha1 &&
+ git init --object-format=sha256 test-sha256
+ ) &&
+ test_commit -C test-sha1 foo &&
+ test_commit -C test-sha256 foo &&
+ GIT_DEFAULT_HASH=sha1 git clone test-sha256 test-clone-sha256 &&
+ GIT_DEFAULT_HASH=sha256 git clone test-sha1 test-clone-sha1 &&
+ git -C test-clone-sha1 status &&
+ git -C test-clone-sha256 status
+'
+
partial_clone_server () {
SERVER="$1" &&
diff --git a/t/t6018-rev-list-glob.sh b/t/t6018-rev-list-glob.sh
index b31ff7e..fe2f3ce 100755
--- a/t/t6018-rev-list-glob.sh
+++ b/t/t6018-rev-list-glob.sh
@@ -32,11 +32,11 @@ test_expect_success 'setup' '
git checkout -b someref master &&
commit some &&
git checkout master &&
- commit master2 &&
+ commit topic_2 &&
git tag foo/bar master &&
- commit master3 &&
+ commit topic_3 &&
git update-ref refs/remotes/foo/baz master &&
- commit master4 &&
+ commit topic_4 &&
git update-ref refs/remotes/upstream/one subspace/one &&
git update-ref refs/remotes/upstream/two subspace/two &&
git update-ref refs/remotes/upstream/x subspace-x &&
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index b886529..aa22638 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -82,6 +82,13 @@ test_expect_success 'bisect fails if given any junk instead of revs' '
git bisect bad $HASH4
'
+test_expect_success 'bisect start without -- takes unknown arg as pathspec' '
+ git bisect reset &&
+ git bisect start foo bar &&
+ grep foo ".git/BISECT_NAMES" &&
+ grep bar ".git/BISECT_NAMES"
+'
+
test_expect_success 'bisect reset: back in the master branch' '
git bisect reset &&
echo "* master" > branch.expect &&
diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh
index ad1922b..50a934e 100755
--- a/t/t6040-tracking-info.sh
+++ b/t/t6040-tracking-info.sh
@@ -264,25 +264,25 @@ test_expect_success 'fail to track annotated tags' '
test_expect_success '--set-upstream-to does not change branch' '
git branch from-master master &&
git branch --set-upstream-to master from-master &&
- git branch from-master2 master &&
- test_must_fail git config branch.from-master2.merge > actual &&
- git rev-list from-master2 &&
- git update-ref refs/heads/from-master2 from-master2^ &&
- git rev-parse from-master2 >expect2 &&
- git branch --set-upstream-to master from-master2 &&
+ git branch from-topic_2 master &&
+ test_must_fail git config branch.from-topic_2.merge > actual &&
+ git rev-list from-topic_2 &&
+ git update-ref refs/heads/from-topic_2 from-topic_2^ &&
+ git rev-parse from-topic_2 >expect2 &&
+ git branch --set-upstream-to master from-topic_2 &&
git config branch.from-master.merge > actual &&
- git rev-parse from-master2 >actual2 &&
+ git rev-parse from-topic_2 >actual2 &&
grep -q "^refs/heads/master$" actual &&
cmp expect2 actual2
'
test_expect_success '--set-upstream-to @{-1}' '
git checkout follower &&
- git checkout from-master2 &&
- git config branch.from-master2.merge > expect2 &&
+ git checkout from-topic_2 &&
+ git config branch.from-topic_2.merge > expect2 &&
git branch --set-upstream-to @{-1} from-master &&
git config branch.from-master.merge > actual &&
- git config branch.from-master2.merge > actual2 &&
+ git config branch.from-topic_2.merge > actual2 &&
git branch --set-upstream-to follower from-master &&
git config branch.from-master.merge > expect &&
test_cmp expect2 actual2 &&
diff --git a/t/t6409-merge-subtree.sh b/t/t6409-merge-subtree.sh
index 793f0c8..1a0d0e2 100755
--- a/t/t6409-merge-subtree.sh
+++ b/t/t6409-merge-subtree.sh
@@ -94,10 +94,10 @@ test_expect_success 'merge update' '
echo git-gui2 > git-gui.sh &&
o3=$(git hash-object git-gui.sh) &&
git add git-gui.sh &&
- git checkout -b master2 &&
+ git checkout -b topic_2 &&
git commit -m "update git-gui" &&
cd ../git &&
- git pull -s subtree gui master2 &&
+ git pull -s subtree gui topic_2 &&
git ls-files -s >actual &&
(
echo "100644 $o3 0 git-gui/git-gui.sh" &&
@@ -109,7 +109,7 @@ test_expect_success 'merge update' '
test_expect_success 'initial ambiguous subtree' '
cd ../git &&
git reset --hard master &&
- git checkout -b master2 &&
+ git checkout -b topic_2 &&
git merge -s ours --no-commit gui/master &&
git read-tree --prefix=git-gui2/ -u gui/master &&
git commit -m "Merge git-gui2 as our subdirectory" &&
@@ -125,8 +125,8 @@ test_expect_success 'initial ambiguous subtree' '
test_expect_success 'merge using explicit' '
cd ../git &&
- git reset --hard master2 &&
- git pull -Xsubtree=git-gui gui master2 &&
+ git reset --hard topic_2 &&
+ git pull -Xsubtree=git-gui gui topic_2 &&
git ls-files -s >actual &&
(
echo "100644 $o3 0 git-gui/git-gui.sh" &&
@@ -138,8 +138,8 @@ test_expect_success 'merge using explicit' '
test_expect_success 'merge2 using explicit' '
cd ../git &&
- git reset --hard master2 &&
- git pull -Xsubtree=git-gui2 gui master2 &&
+ git reset --hard topic_2 &&
+ git pull -Xsubtree=git-gui2 gui topic_2 &&
git ls-files -s >actual &&
(
echo "100644 $o1 0 git-gui/git-gui.sh" &&
diff --git a/t/t6600-test-reach.sh b/t/t6600-test-reach.sh
index 475564b..f807276 100755
--- a/t/t6600-test-reach.sh
+++ b/t/t6600-test-reach.sh
@@ -110,6 +110,36 @@ test_expect_success 'in_merge_bases:miss' '
test_three_modes in_merge_bases
'
+test_expect_success 'in_merge_bases_many:hit' '
+ cat >input <<-\EOF &&
+ A:commit-6-8
+ X:commit-6-9
+ X:commit-5-7
+ EOF
+ echo "in_merge_bases_many(A,X):1" >expect &&
+ test_three_modes in_merge_bases_many
+'
+
+test_expect_success 'in_merge_bases_many:miss' '
+ cat >input <<-\EOF &&
+ A:commit-6-8
+ X:commit-7-7
+ X:commit-8-6
+ EOF
+ echo "in_merge_bases_many(A,X):0" >expect &&
+ test_three_modes in_merge_bases_many
+'
+
+test_expect_success 'in_merge_bases_many:miss-heuristic' '
+ cat >input <<-\EOF &&
+ A:commit-6-8
+ X:commit-7-5
+ X:commit-6-6
+ EOF
+ echo "in_merge_bases_many(A,X):0" >expect &&
+ test_three_modes in_merge_bases_many
+'
+
test_expect_success 'is_descendant_of:hit' '
cat >input <<-\EOF &&
A:commit-5-7
diff --git a/t/t7601-merge-pull-config.sh b/t/t7601-merge-pull-config.sh
index 0f97828..c5c4ea5 100755
--- a/t/t7601-merge-pull-config.sh
+++ b/t/t7601-merge-pull-config.sh
@@ -33,11 +33,18 @@ test_expect_success 'pull.rebase not set' '
test_i18ngrep "Pulling without specifying how to reconcile" err
'
+test_expect_success 'pull.rebase not set and pull.ff=true' '
+ git reset --hard c0 &&
+ test_config pull.ff true &&
+ git pull . c1 2>err &&
+ test_i18ngrep ! "Pulling without specifying how to reconcile" err
+'
+
test_expect_success 'pull.rebase not set and pull.ff=false' '
git reset --hard c0 &&
test_config pull.ff false &&
git pull . c1 2>err &&
- test_i18ngrep "Pulling without specifying how to reconcile" err
+ test_i18ngrep ! "Pulling without specifying how to reconcile" err
'
test_expect_success 'pull.rebase not set and pull.ff=only' '
@@ -59,6 +66,18 @@ test_expect_success 'pull.rebase not set and --no-rebase given' '
test_i18ngrep ! "Pulling without specifying how to reconcile" err
'
+test_expect_success 'pull.rebase not set and --ff given' '
+ git reset --hard c0 &&
+ git pull --ff . c1 2>err &&
+ test_i18ngrep ! "Pulling without specifying how to reconcile" err
+'
+
+test_expect_success 'pull.rebase not set and --no-ff given' '
+ git reset --hard c0 &&
+ git pull --no-ff . c1 2>err &&
+ test_i18ngrep ! "Pulling without specifying how to reconcile" err
+'
+
test_expect_success 'pull.rebase not set and --ff-only given' '
git reset --hard c0 &&
git pull --ff-only . c1 2>err &&
diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh
new file mode 100755
index 0000000..53c8835
--- /dev/null
+++ b/t/t7900-maintenance.sh
@@ -0,0 +1,65 @@
+#!/bin/sh
+
+test_description='git maintenance builtin'
+
+. ./test-lib.sh
+
+GIT_TEST_COMMIT_GRAPH=0
+
+test_expect_success 'help text' '
+ test_expect_code 129 git maintenance -h 2>err &&
+ test_i18ngrep "usage: git maintenance run" err &&
+ test_expect_code 128 git maintenance barf 2>err &&
+ test_i18ngrep "invalid subcommand: barf" err &&
+ test_expect_code 129 git maintenance 2>err &&
+ test_i18ngrep "usage: git maintenance" err
+'
+
+test_expect_success 'run [--auto|--quiet]' '
+ GIT_TRACE2_EVENT="$(pwd)/run-no-auto.txt" \
+ git maintenance run 2>/dev/null &&
+ GIT_TRACE2_EVENT="$(pwd)/run-auto.txt" \
+ git maintenance run --auto 2>/dev/null &&
+ GIT_TRACE2_EVENT="$(pwd)/run-no-quiet.txt" \
+ git maintenance run --no-quiet 2>/dev/null &&
+ test_subcommand git gc --quiet <run-no-auto.txt &&
+ test_subcommand ! git gc --auto --quiet <run-auto.txt &&
+ test_subcommand git gc --no-quiet <run-no-quiet.txt
+'
+
+test_expect_success 'maintenance.<task>.enabled' '
+ git config maintenance.gc.enabled false &&
+ git config maintenance.commit-graph.enabled true &&
+ GIT_TRACE2_EVENT="$(pwd)/run-config.txt" git maintenance run 2>err &&
+ test_subcommand ! git gc --quiet <run-config.txt &&
+ test_subcommand git commit-graph write --split --reachable --no-progress <run-config.txt
+'
+
+test_expect_success 'run --task=<task>' '
+ GIT_TRACE2_EVENT="$(pwd)/run-commit-graph.txt" \
+ git maintenance run --task=commit-graph 2>/dev/null &&
+ GIT_TRACE2_EVENT="$(pwd)/run-gc.txt" \
+ git maintenance run --task=gc 2>/dev/null &&
+ GIT_TRACE2_EVENT="$(pwd)/run-commit-graph.txt" \
+ git maintenance run --task=commit-graph 2>/dev/null &&
+ GIT_TRACE2_EVENT="$(pwd)/run-both.txt" \
+ git maintenance run --task=commit-graph --task=gc 2>/dev/null &&
+ test_subcommand ! git gc --quiet <run-commit-graph.txt &&
+ test_subcommand git gc --quiet <run-gc.txt &&
+ test_subcommand git gc --quiet <run-both.txt &&
+ test_subcommand git commit-graph write --split --reachable --no-progress <run-commit-graph.txt &&
+ test_subcommand ! git commit-graph write --split --reachable --no-progress <run-gc.txt &&
+ test_subcommand git commit-graph write --split --reachable --no-progress <run-both.txt
+'
+
+test_expect_success 'run --task=bogus' '
+ test_must_fail git maintenance run --task=bogus 2>err &&
+ test_i18ngrep "is not a valid task" err
+'
+
+test_expect_success 'run --task duplicate' '
+ test_must_fail git maintenance run --task=gc --task=gc 2>err &&
+ test_i18ngrep "cannot be selected multiple times" err
+'
+
+test_done
diff --git a/t/t8013-blame-ignore-revs.sh b/t/t8013-blame-ignore-revs.sh
index 36dc31e..24ae501 100755
--- a/t/t8013-blame-ignore-revs.sh
+++ b/t/t8013-blame-ignore-revs.sh
@@ -21,6 +21,7 @@ test_expect_success setup '
test_tick &&
git commit -m X &&
git tag X &&
+ git tag -a -m "X (annotated)" XT &&
git blame --line-porcelain file >blame_raw &&
@@ -31,20 +32,36 @@ test_expect_success setup '
grep -E "^[0-9a-f]+ [0-9]+ 2" blame_raw | sed -e "s/ .*//" >actual &&
git rev-parse X >expect &&
test_cmp expect actual
+'
+
+# Ensure bogus --ignore-rev requests are caught
+test_expect_success 'validate --ignore-rev' '
+ test_must_fail git blame --ignore-rev X^{tree} file
+'
+
+# Ensure bogus --ignore-revs-file requests are caught
+test_expect_success 'validate --ignore-revs-file' '
+ git rev-parse X^{tree} >ignore_x &&
+ test_must_fail git blame --ignore-revs-file ignore_x file
+'
+
+for I in X XT
+do
+ # Ignore X (or XT), make sure A is blamed for line 1 and B for line 2.
+ # Giving X (i.e. commit) and XT (i.e. annotated tag to commit) should
+ # produce the same result.
+ test_expect_success "ignore_rev_changing_lines ($I)" '
+ git blame --line-porcelain --ignore-rev $I file >blame_raw &&
+
+ grep -E "^[0-9a-f]+ [0-9]+ 1" blame_raw | sed -e "s/ .*//" >actual &&
+ git rev-parse A >expect &&
+ test_cmp expect actual &&
+
+ grep -E "^[0-9a-f]+ [0-9]+ 2" blame_raw | sed -e "s/ .*//" >actual &&
+ git rev-parse B >expect &&
+ test_cmp expect actual
'
-
-# Ignore X, make sure A is blamed for line 1 and B for line 2.
-test_expect_success ignore_rev_changing_lines '
- git blame --line-porcelain --ignore-rev X file >blame_raw &&
-
- grep -E "^[0-9a-f]+ [0-9]+ 1" blame_raw | sed -e "s/ .*//" >actual &&
- git rev-parse A >expect &&
- test_cmp expect actual &&
-
- grep -E "^[0-9a-f]+ [0-9]+ 2" blame_raw | sed -e "s/ .*//" >actual &&
- git rev-parse B >expect &&
- test_cmp expect actual
- '
+done
# For ignored revs that have added 'unblamable' lines, attribute those to the
# ignored commit.
@@ -67,7 +84,7 @@ test_expect_success ignore_rev_adding_unblamable_lines '
grep -E "^[0-9a-f]+ [0-9]+ 4" blame_raw | sed -e "s/ .*//" >actual &&
test_cmp expect actual
- '
+'
# Ignore X and Y, both in separate files. Lines 1 == A, 2 == B.
test_expect_success ignore_revs_from_files '
@@ -82,7 +99,7 @@ test_expect_success ignore_revs_from_files '
grep -E "^[0-9a-f]+ [0-9]+ 2" blame_raw | sed -e "s/ .*//" >actual &&
git rev-parse B >expect &&
test_cmp expect actual
- '
+'
# Ignore X from the config option, Y from a file.
test_expect_success ignore_revs_from_configs_and_files '
@@ -96,7 +113,7 @@ test_expect_success ignore_revs_from_configs_and_files '
grep -E "^[0-9a-f]+ [0-9]+ 2" blame_raw | sed -e "s/ .*//" >actual &&
git rev-parse B >expect &&
test_cmp expect actual
- '
+'
# Override blame.ignoreRevsFile (ignore_x) with an empty string. X should be
# blamed now for lines 1 and 2, since we are no longer ignoring X.
@@ -120,7 +137,7 @@ test_expect_success bad_files_and_revs '
echo NOREV >ignore_norev &&
test_must_fail git blame file --ignore-revs-file ignore_norev 2>err &&
test_i18ngrep "invalid object name: NOREV" err
- '
+'
# For ignored revs that have added 'unblamable' lines, mark those lines with a
# '*'
@@ -138,7 +155,7 @@ test_expect_success mark_unblamable_lines '
sed -n "4p" blame_raw | cut -c1 >actual &&
test_cmp expect actual
- '
+'
# Commit Z will touch the first two lines. Y touched all four.
# A--B--X--Y--Z
@@ -171,7 +188,7 @@ test_expect_success mark_ignored_lines '
sed -n "4p" blame_raw | cut -c1 >actual &&
! test_cmp expect actual
- '
+'
# For ignored revs that added 'unblamable' lines and more recent commits changed
# the blamable lines, mark the unblamable lines with a
@@ -190,7 +207,7 @@ test_expect_success mark_unblamable_lines_intermediate '
sed -n "4p" blame_raw | cut -c1 >actual &&
test_cmp expect actual
- '
+'
# The heuristic called by guess_line_blames() tries to find the size of a
# blame_entry 'e' in the parent's address space. Those calculations need to
@@ -227,7 +244,7 @@ test_expect_success ignored_chunk_negative_parent_size '
git tag C &&
git blame file --ignore-rev B >blame_raw
- '
+'
# Resetting the repo and creating:
#
@@ -269,6 +286,6 @@ test_expect_success ignore_merge '
grep -E "^[0-9a-f]+ [0-9]+ 9" blame_raw | sed -e "s/ .*//" >actual &&
git rev-parse C >expect &&
test_cmp expect actual
- '
+'
test_done
diff --git a/t/t9832-unshelve.sh b/t/t9832-unshelve.sh
index e9276c4..7194fb2 100755
--- a/t/t9832-unshelve.sh
+++ b/t/t9832-unshelve.sh
@@ -29,8 +29,11 @@ test_expect_success 'init depot' '
)
'
+# Create an initial clone, with a commit unrelated to the P4 change
+# on HEAD
test_expect_success 'initial clone' '
- git p4 clone --dest="$git" //depot/@all
+ git p4 clone --dest="$git" //depot/@all &&
+ test_commit -C "$git" "unrelated"
'
test_expect_success 'create shelved changelist' '
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 8425b9a..7b7bc6e 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -542,37 +542,37 @@ test_expect_success '__gitcomp - doesnt fail because of invalid variable name' '
'
read -r -d "" refs <<-\EOF
+main
maint
-master
next
seen
EOF
test_expect_success '__gitcomp_nl - trailing space' '
test_gitcomp_nl "m" "$refs" <<-EOF
+ main Z
maint Z
- master Z
EOF
'
test_expect_success '__gitcomp_nl - prefix' '
test_gitcomp_nl "--fixup=m" "$refs" "--fixup=" "m" <<-EOF
+ --fixup=main Z
--fixup=maint Z
- --fixup=master Z
EOF
'
test_expect_success '__gitcomp_nl - suffix' '
test_gitcomp_nl "branch.ma" "$refs" "branch." "ma" "." <<-\EOF
+ branch.main.Z
branch.maint.Z
- branch.master.Z
EOF
'
test_expect_success '__gitcomp_nl - no suffix' '
test_gitcomp_nl "ma" "$refs" "" "ma" "" <<-\EOF
+ mainZ
maintZ
- masterZ
EOF
'
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index f990406..8d59b90 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -1628,3 +1628,36 @@ test_path_is_hidden () {
case "$("$SYSTEMROOT"/system32/attrib "$1")" in *H*?:*) return 0;; esac
return 1
}
+
+# Check that the given command was invoked as part of the
+# trace2-format trace on stdin.
+#
+# test_subcommand [!] <command> <args>... < <trace>
+#
+# For example, to look for an invocation of "git upload-pack
+# /path/to/repo"
+#
+# GIT_TRACE2_EVENT=event.log git fetch ... &&
+# test_subcommand git upload-pack "$PATH" <event.log
+#
+# If the first parameter passed is !, this instead checks that
+# the given command was not called.
+#
+test_subcommand () {
+ local negate=
+ if test "$1" = "!"
+ then
+ negate=t
+ shift
+ fi
+
+ local expr=$(printf '"%s",' "$@")
+ expr="${expr%,}"
+
+ if test -n "$negate"
+ then
+ ! grep "\[$expr\]"
+ else
+ grep "\[$expr\]"
+ fi
+}
diff --git a/t/test-terminal.perl b/t/test-terminal.perl
index 46bf618..1bcf01a 100755
--- a/t/test-terminal.perl
+++ b/t/test-terminal.perl
@@ -81,24 +81,24 @@ if ($#ARGV < 1) {
die "usage: test-terminal program args";
}
$ENV{TERM} = 'vt100';
-my $master_in = new IO::Pty;
-my $master_out = new IO::Pty;
-my $master_err = new IO::Pty;
-$master_in->set_raw();
-$master_out->set_raw();
-$master_err->set_raw();
-$master_in->slave->set_raw();
-$master_out->slave->set_raw();
-$master_err->slave->set_raw();
-my $pid = start_child(\@ARGV, $master_in->slave, $master_out->slave, $master_err->slave);
-close $master_in->slave;
-close $master_out->slave;
-close $master_err->slave;
-my $in_pid = copy_stdin($master_in);
-copy_stdio($master_out, $master_err);
+my $parent_in = new IO::Pty;
+my $parent_out = new IO::Pty;
+my $parent_err = new IO::Pty;
+$parent_in->set_raw();
+$parent_out->set_raw();
+$parent_err->set_raw();
+$parent_in->slave->set_raw();
+$parent_out->slave->set_raw();
+$parent_err->slave->set_raw();
+my $pid = start_child(\@ARGV, $parent_in->slave, $parent_out->slave, $parent_err->slave);
+close $parent_in->slave;
+close $parent_out->slave;
+close $parent_err->slave;
+my $in_pid = copy_stdin($parent_in);
+copy_stdio($parent_out, $parent_err);
my $ret = finish_child($pid);
# If the child process terminates before our copy_stdin() process is able to
-# write all of its data to $master_in, the copy_stdin() process could stall.
+# write all of its data to $parent_in, the copy_stdin() process could stall.
# Send SIGTERM to it to ensure it terminates.
kill 'TERM', $in_pid;
finish_child($in_pid);
diff --git a/templates/hooks--pre-push.sample b/templates/hooks--pre-push.sample
index 6187dbf..4ce688d 100755
--- a/templates/hooks--pre-push.sample
+++ b/templates/hooks--pre-push.sample
@@ -14,7 +14,7 @@
# Information about the commits which are being pushed is supplied as lines to
# the standard input in the form:
#
-# <local ref> <local sha1> <remote ref> <remote sha1>
+# <local ref> <local oid> <remote ref> <remote oid>
#
# This sample shows how to prevent push of commits where the log message starts
# with "WIP" (work in progress).
@@ -22,27 +22,27 @@
remote="$1"
url="$2"
-z40=0000000000000000000000000000000000000000
+zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
-while read local_ref local_sha remote_ref remote_sha
+while read local_ref local_oid remote_ref remote_oid
do
- if [ "$local_sha" = $z40 ]
+ if test "$local_oid" = "$zero"
then
# Handle delete
:
else
- if [ "$remote_sha" = $z40 ]
+ if test "$remote_oid" = "$zero"
then
# New branch, examine all commits
- range="$local_sha"
+ range="$local_oid"
else
# Update to existing branch, examine new commits
- range="$remote_sha..$local_sha"
+ range="$remote_oid..$local_oid"
fi
# Check for WIP commit
- commit=`git rev-list -n 1 --grep '^WIP' "$range"`
- if [ -n "$commit" ]
+ commit=$(git rev-list -n 1 --grep '^WIP' "$range")
+ if test -n "$commit"
then
echo >&2 "Found WIP commit in $local_ref, not pushing"
exit 1
diff --git a/templates/hooks--update.sample b/templates/hooks--update.sample
index 5014c4b..c4d426b 100755
--- a/templates/hooks--update.sample
+++ b/templates/hooks--update.sample
@@ -60,7 +60,7 @@ esac
# --- Check types
# if $newrev is 0000...0000, it's a commit to delete a ref.
-zero="0000000000000000000000000000000000000000"
+zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
if [ "$newrev" = "$zero" ]; then
newrev_type=delete
else
diff --git a/trailer.c b/trailer.c
index 68dabc2..3f7391d 100644
--- a/trailer.c
+++ b/trailer.c
@@ -1183,3 +1183,39 @@ void format_trailers_from_commit(struct strbuf *out, const char *msg,
format_trailer_info(out, &info, opts);
trailer_info_release(&info);
}
+
+void trailer_iterator_init(struct trailer_iterator *iter, const char *msg)
+{
+ struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
+ strbuf_init(&iter->key, 0);
+ strbuf_init(&iter->val, 0);
+ opts.no_divider = 1;
+ trailer_info_get(&iter->info, msg, &opts);
+ iter->cur = 0;
+}
+
+int trailer_iterator_advance(struct trailer_iterator *iter)
+{
+ while (iter->cur < iter->info.trailer_nr) {
+ char *trailer = iter->info.trailers[iter->cur++];
+ int separator_pos = find_separator(trailer, separators);
+
+ if (separator_pos < 1)
+ continue; /* not a real trailer */
+
+ strbuf_reset(&iter->key);
+ strbuf_reset(&iter->val);
+ parse_trailer(&iter->key, &iter->val, NULL,
+ trailer, separator_pos);
+ unfold_value(&iter->val);
+ return 1;
+ }
+ return 0;
+}
+
+void trailer_iterator_release(struct trailer_iterator *iter)
+{
+ trailer_info_release(&iter->info);
+ strbuf_release(&iter->val);
+ strbuf_release(&iter->key);
+}
diff --git a/trailer.h b/trailer.h
index 203acf4..cd93e7d 100644
--- a/trailer.h
+++ b/trailer.h
@@ -2,8 +2,7 @@
#define TRAILER_H
#include "list.h"
-
-struct strbuf;
+#include "strbuf.h"
enum trailer_where {
WHERE_DEFAULT,
@@ -103,4 +102,46 @@ void trailer_info_release(struct trailer_info *info);
void format_trailers_from_commit(struct strbuf *out, const char *msg,
const struct process_trailer_options *opts);
+/*
+ * An interface for iterating over the trailers found in a particular commit
+ * message. Use like:
+ *
+ * struct trailer_iterator iter;
+ * trailer_iterator_init(&iter, msg);
+ * while (trailer_iterator_advance(&iter))
+ * ... do something with iter.key and iter.val ...
+ * trailer_iterator_release(&iter);
+ */
+struct trailer_iterator {
+ struct strbuf key;
+ struct strbuf val;
+
+ /* private */
+ struct trailer_info info;
+ size_t cur;
+};
+
+/*
+ * Initialize "iter" in preparation for walking over the trailers in the commit
+ * message "msg". The "msg" pointer must remain valid until the iterator is
+ * released.
+ *
+ * After initializing, note that key/val will not yet point to any trailer.
+ * Call advance() to parse the first one (if any).
+ */
+void trailer_iterator_init(struct trailer_iterator *iter, const char *msg);
+
+/*
+ * Advance to the next trailer of the iterator. Returns 0 if there is no such
+ * trailer, and 1 otherwise. The key and value of the trailer can be
+ * fetched from the iter->key and iter->value fields (which are valid
+ * only until the next advance).
+ */
+int trailer_iterator_advance(struct trailer_iterator *iter);
+
+/*
+ * Release all resources associated with the trailer iteration.
+ */
+void trailer_iterator_release(struct trailer_iterator *iter);
+
#endif /* TRAILER_H */
diff --git a/transport-helper.c b/transport-helper.c
index c52c99d..b573b6c 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -723,13 +723,61 @@ static int fetch(struct transport *transport,
return -1;
}
+struct push_update_ref_state {
+ struct ref *hint;
+ struct ref_push_report *report;
+ int new_report;
+};
+
static int push_update_ref_status(struct strbuf *buf,
- struct ref **ref,
+ struct push_update_ref_state *state,
struct ref *remote_refs)
{
char *refname, *msg;
int status, forced = 0;
+ if (starts_with(buf->buf, "option ")) {
+ struct object_id old_oid, new_oid;
+ const char *key, *val;
+ char *p;
+
+ if (!state->hint || !(state->report || state->new_report))
+ die(_("'option' without a matching 'ok/error' directive"));
+ if (state->new_report) {
+ if (!state->hint->report) {
+ state->hint->report = xcalloc(1, sizeof(struct ref_push_report));
+ state->report = state->hint->report;
+ } else {
+ state->report = state->hint->report;
+ while (state->report->next)
+ state->report = state->report->next;
+ state->report->next = xcalloc(1, sizeof(struct ref_push_report));
+ state->report = state->report->next;
+ }
+ state->new_report = 0;
+ }
+ key = buf->buf + 7;
+ p = strchr(key, ' ');
+ if (p)
+ *p++ = '\0';
+ val = p;
+ if (!strcmp(key, "refname"))
+ state->report->ref_name = xstrdup_or_null(val);
+ else if (!strcmp(key, "old-oid") && val &&
+ !parse_oid_hex(val, &old_oid, &val))
+ state->report->old_oid = oiddup(&old_oid);
+ else if (!strcmp(key, "new-oid") && val &&
+ !parse_oid_hex(val, &new_oid, &val))
+ state->report->new_oid = oiddup(&new_oid);
+ else if (!strcmp(key, "forced-update"))
+ state->report->forced_update = 1;
+ /* Not update remote namespace again. */
+ return 1;
+ }
+
+ state->report = NULL;
+ state->new_report = 0;
+
if (starts_with(buf->buf, "ok ")) {
status = REF_STATUS_OK;
refname = buf->buf + 3;
@@ -785,16 +833,16 @@ static int push_update_ref_status(struct strbuf *buf,
}
}
- if (*ref)
- *ref = find_ref_by_name(*ref, refname);
- if (!*ref)
- *ref = find_ref_by_name(remote_refs, refname);
- if (!*ref) {
+ if (state->hint)
+ state->hint = find_ref_by_name(state->hint, refname);
+ if (!state->hint)
+ state->hint = find_ref_by_name(remote_refs, refname);
+ if (!state->hint) {
warning(_("helper reported unexpected status of %s"), refname);
return 1;
}
- if ((*ref)->status != REF_STATUS_NONE) {
+ if (state->hint->status != REF_STATUS_NONE) {
/*
* Earlier, the ref was marked not to be pushed, so ignore the ref
* status reported by the remote helper if the latter is 'no match'.
@@ -803,9 +851,11 @@ static int push_update_ref_status(struct strbuf *buf,
return 1;
}
- (*ref)->status = status;
- (*ref)->forced_update |= forced;
- (*ref)->remote_status = msg;
+ if (status == REF_STATUS_OK)
+ state->new_report = 1;
+ state->hint->status = status;
+ state->hint->forced_update |= forced;
+ state->hint->remote_status = msg;
return !(status == REF_STATUS_OK);
}
@@ -813,37 +863,57 @@ static int push_update_refs_status(struct helper_data *data,
struct ref *remote_refs,
int flags)
{
+ struct ref *ref;
+ struct ref_push_report *report;
struct strbuf buf = STRBUF_INIT;
- struct ref *ref = remote_refs;
- int ret = 0;
+ struct push_update_ref_state state = { remote_refs, NULL, 0 };
for (;;) {
- char *private;
-
if (recvline(data, &buf)) {
- ret = 1;
- break;
+ strbuf_release(&buf);
+ return 1;
}
-
if (!buf.len)
break;
+ push_update_ref_status(&buf, &state, remote_refs);
+ }
+ strbuf_release(&buf);
- if (push_update_ref_status(&buf, &ref, remote_refs))
- continue;
+ if (flags & TRANSPORT_PUSH_DRY_RUN || !data->rs.nr || data->no_private_update)
+ return 0;
- if (flags & TRANSPORT_PUSH_DRY_RUN || !data->rs.nr || data->no_private_update)
- continue;
+ /* propagate back the update to the remote namespace */
+ for (ref = remote_refs; ref; ref = ref->next) {
+ char *private;
- /* propagate back the update to the remote namespace */
- private = apply_refspecs(&data->rs, ref->name);
- if (!private)
+ if (ref->status != REF_STATUS_OK)
continue;
- update_ref("update by helper", private, &ref->new_oid, NULL,
- 0, 0);
- free(private);
+
+ if (!ref->report) {
+ private = apply_refspecs(&data->rs, ref->name);
+ if (!private)
+ continue;
+ update_ref("update by helper", private, &(ref->new_oid),
+ NULL, 0, 0);
+ free(private);
+ } else {
+ for (report = ref->report; report; report = report->next) {
+ private = apply_refspecs(&data->rs,
+ report->ref_name
+ ? report->ref_name
+ : ref->name);
+ if (!private)
+ continue;
+ update_ref("update by helper", private,
+ report->new_oid
+ ? report->new_oid
+ : &(ref->new_oid),
+ NULL, 0, 0);
+ free(private);
+ }
+ }
}
- strbuf_release(&buf);
- return ret;
+ return 0;
}
static void set_common_push_options(struct transport *transport,
diff --git a/transport.c b/transport.c
index 43e24bf..ffe2115 100644
--- a/transport.c
+++ b/transport.c
@@ -432,38 +432,67 @@ int transport_refs_pushed(struct ref *ref)
return 0;
}
-void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int verbose)
+static void update_one_tracking_ref(struct remote *remote, char *refname,
+ struct object_id *new_oid, int deletion,
+ int verbose)
{
struct refspec_item rs;
- if (ref->status != REF_STATUS_OK && ref->status != REF_STATUS_UPTODATE)
- return;
-
memset(&rs, 0, sizeof(rs));
- rs.src = ref->name;
+ rs.src = refname;
rs.dst = NULL;
if (!remote_find_tracking(remote, &rs)) {
if (verbose)
fprintf(stderr, "updating local tracking ref '%s'\n", rs.dst);
- if (ref->deletion) {
+ if (deletion)
delete_ref(NULL, rs.dst, NULL, 0);
- } else
- update_ref("update by push", rs.dst, &ref->new_oid,
+ else
+ update_ref("update by push", rs.dst, new_oid,
NULL, 0, 0);
free(rs.dst);
}
}
+void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int verbose)
+{
+ char *refname;
+ struct object_id *new_oid;
+ struct ref_push_report *report;
+
+ if (ref->status != REF_STATUS_OK && ref->status != REF_STATUS_UPTODATE)
+ return;
+
+ report = ref->report;
+ if (!report)
+ update_one_tracking_ref(remote, ref->name, &ref->new_oid,
+ ref->deletion, verbose);
+ else
+ for (; report; report = report->next) {
+ refname = report->ref_name ? (char *)report->ref_name : ref->name;
+ new_oid = report->new_oid ? report->new_oid : &ref->new_oid;
+ update_one_tracking_ref(remote, refname, new_oid,
+ is_null_oid(new_oid), verbose);
+ }
+}
+
static void print_ref_status(char flag, const char *summary,
struct ref *to, struct ref *from, const char *msg,
+ struct ref_push_report *report,
int porcelain, int summary_width)
{
+ const char *to_name;
+
+ if (report && report->ref_name)
+ to_name = report->ref_name;
+ else
+ to_name = to->name;
+
if (porcelain) {
if (from)
- fprintf(stdout, "%c\t%s:%s\t", flag, from->name, to->name);
+ fprintf(stdout, "%c\t%s:%s\t", flag, from->name, to_name);
else
- fprintf(stdout, "%c\t:%s\t", flag, to->name);
+ fprintf(stdout, "%c\t:%s\t", flag, to_name);
if (msg)
fprintf(stdout, "%s (%s)\n", summary, msg);
else
@@ -477,9 +506,11 @@ static void print_ref_status(char flag, const char *summary,
fprintf(stderr, " %s%c %-*s%s ", red, flag, summary_width,
summary, reset);
if (from)
- fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
+ fprintf(stderr, "%s -> %s",
+ prettify_refname(from->name),
+ prettify_refname(to_name));
else
- fputs(prettify_refname(to->name), stderr);
+ fputs(prettify_refname(to_name), stderr);
if (msg) {
fputs(" (", stderr);
fputs(msg, stderr);
@@ -489,24 +520,52 @@ static void print_ref_status(char flag, const char *summary,
}
}
-static void print_ok_ref_status(struct ref *ref, int porcelain, int summary_width)
+static void print_ok_ref_status(struct ref *ref,
+ struct ref_push_report *report,
+ int porcelain, int summary_width)
{
+ struct object_id *old_oid;
+ struct object_id *new_oid;
+ const char *ref_name;
+ int forced_update;
+
+ if (report && report->old_oid)
+ old_oid = report->old_oid;
+ else
+ old_oid = &ref->old_oid;
+ if (report && report->new_oid)
+ new_oid = report->new_oid;
+ else
+ new_oid = &ref->new_oid;
+ if (report && report->forced_update)
+ forced_update = report->forced_update;
+ else
+ forced_update = ref->forced_update;
+ if (report && report->ref_name)
+ ref_name = report->ref_name;
+ else
+ ref_name = ref->name;
+
if (ref->deletion)
print_ref_status('-', "[deleted]", ref, NULL, NULL,
- porcelain, summary_width);
- else if (is_null_oid(&ref->old_oid))
+ report, porcelain, summary_width);
+ else if (is_null_oid(old_oid))
print_ref_status('*',
- (starts_with(ref->name, "refs/tags/") ? "[new tag]" :
- "[new branch]"),
- ref, ref->peer_ref, NULL, porcelain, summary_width);
+ (starts_with(ref_name, "refs/tags/")
+ ? "[new tag]"
+ : (starts_with(ref_name, "refs/heads/")
+ ? "[new branch]"
+ : "[new reference]")),
+ ref, ref->peer_ref, NULL,
+ report, porcelain, summary_width);
else {
struct strbuf quickref = STRBUF_INIT;
char type;
const char *msg;
- strbuf_add_unique_abbrev(&quickref, &ref->old_oid,
+ strbuf_add_unique_abbrev(&quickref, old_oid,
DEFAULT_ABBREV);
- if (ref->forced_update) {
+ if (forced_update) {
strbuf_addstr(&quickref, "...");
type = '+';
msg = "forced update";
@@ -515,16 +574,17 @@ static void print_ok_ref_status(struct ref *ref, int porcelain, int summary_widt
type = ' ';
msg = NULL;
}
- strbuf_add_unique_abbrev(&quickref, &ref->new_oid,
+ strbuf_add_unique_abbrev(&quickref, new_oid,
DEFAULT_ABBREV);
print_ref_status(type, quickref.buf, ref, ref->peer_ref, msg,
- porcelain, summary_width);
+ report, porcelain, summary_width);
strbuf_release(&quickref);
}
}
-static int print_one_push_status(struct ref *ref, const char *dest, int count,
+static int print_one_push_report(struct ref *ref, const char *dest, int count,
+ struct ref_push_report *report,
int porcelain, int summary_width)
{
if (!count) {
@@ -536,65 +596,89 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count,
switch(ref->status) {
case REF_STATUS_NONE:
print_ref_status('X', "[no match]", ref, NULL, NULL,
- porcelain, summary_width);
+ report, porcelain, summary_width);
break;
case REF_STATUS_REJECT_NODELETE:
print_ref_status('!', "[rejected]", ref, NULL,
"remote does not support deleting refs",
- porcelain, summary_width);
+ report, porcelain, summary_width);
break;
case REF_STATUS_UPTODATE:
print_ref_status('=', "[up to date]", ref,
- ref->peer_ref, NULL, porcelain, summary_width);
+ ref->peer_ref, NULL,
+ report, porcelain, summary_width);
break;
case REF_STATUS_REJECT_NONFASTFORWARD:
print_ref_status('!', "[rejected]", ref, ref->peer_ref,
- "non-fast-forward", porcelain, summary_width);
+ "non-fast-forward",
+ report, porcelain, summary_width);
break;
case REF_STATUS_REJECT_ALREADY_EXISTS:
print_ref_status('!', "[rejected]", ref, ref->peer_ref,
- "already exists", porcelain, summary_width);
+ "already exists",
+ report, porcelain, summary_width);
break;
case REF_STATUS_REJECT_FETCH_FIRST:
print_ref_status('!', "[rejected]", ref, ref->peer_ref,
- "fetch first", porcelain, summary_width);
+ "fetch first",
+ report, porcelain, summary_width);
break;
case REF_STATUS_REJECT_NEEDS_FORCE:
print_ref_status('!', "[rejected]", ref, ref->peer_ref,
- "needs force", porcelain, summary_width);
+ "needs force",
+ report, porcelain, summary_width);
break;
case REF_STATUS_REJECT_STALE:
print_ref_status('!', "[rejected]", ref, ref->peer_ref,
- "stale info", porcelain, summary_width);
+ "stale info",
+ report, porcelain, summary_width);
break;
case REF_STATUS_REJECT_SHALLOW:
print_ref_status('!', "[rejected]", ref, ref->peer_ref,
"new shallow roots not allowed",
- porcelain, summary_width);
+ report, porcelain, summary_width);
break;
case REF_STATUS_REMOTE_REJECT:
print_ref_status('!', "[remote rejected]", ref,
ref->deletion ? NULL : ref->peer_ref,
- ref->remote_status, porcelain, summary_width);
+ ref->remote_status,
+ report, porcelain, summary_width);
break;
case REF_STATUS_EXPECTING_REPORT:
print_ref_status('!', "[remote failure]", ref,
ref->deletion ? NULL : ref->peer_ref,
"remote failed to report status",
- porcelain, summary_width);
+ report, porcelain, summary_width);
break;
case REF_STATUS_ATOMIC_PUSH_FAILED:
print_ref_status('!', "[rejected]", ref, ref->peer_ref,
- "atomic push failed", porcelain, summary_width);
+ "atomic push failed",
+ report, porcelain, summary_width);
break;
case REF_STATUS_OK:
- print_ok_ref_status(ref, porcelain, summary_width);
+ print_ok_ref_status(ref, report, porcelain, summary_width);
break;
}
return 1;
}
+static int print_one_push_status(struct ref *ref, const char *dest, int count,
+ int porcelain, int summary_width)
+{
+ struct ref_push_report *report;
+ int n = 0;
+
+ if (!ref->report)
+ return print_one_push_report(ref, dest, count,
+ NULL, porcelain, summary_width);
+
+ for (report = ref->report; report; report = report->next)
+ print_one_push_report(ref, dest, count + n++,
+ report, porcelain, summary_width);
+ return n;
+}
+
static int measure_abbrev(const struct object_id *oid, int sofar)
{
char hex[GIT_MAX_HEXSZ + 1];
diff --git a/tree-diff.c b/tree-diff.c
index 6ebad1a..7cebbb3 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -434,7 +434,7 @@ static struct combine_diff_path *ll_diff_tree_paths(
if (diff_can_quit_early(opt))
break;
- if (opt->max_changes && opt->num_changes > opt->max_changes)
+ if (opt->max_changes && diff_queued_diff.nr > opt->max_changes)
break;
if (opt->pathspec.nr) {
@@ -521,7 +521,6 @@ static struct combine_diff_path *ll_diff_tree_paths(
/* t↓ */
update_tree_entry(&t);
- opt->num_changes++;
}
/* t > p[imin] */
@@ -539,7 +538,6 @@ static struct combine_diff_path *ll_diff_tree_paths(
skip_emit_tp:
/* ∀ pi=p[imin] pi↓ */
update_tp_entries(tp, nparent);
- opt->num_changes++;
}
}
@@ -557,7 +555,6 @@ struct combine_diff_path *diff_tree_paths(
const struct object_id **parents_oid, int nparent,
struct strbuf *base, struct diff_options *opt)
{
- opt->num_changes = 0;
p = ll_diff_tree_paths(p, oid, parents_oid, nparent, base, opt);
/*
diff --git a/worktree.c b/worktree.c
index 46a5fb8..f84ceae 100644
--- a/worktree.c
+++ b/worktree.c
@@ -21,7 +21,7 @@ void free_worktrees(struct worktree **worktrees)
}
/**
- * Update head_sha1, head_ref and is_detached of the given worktree
+ * Update head_oid, head_ref and is_detached of the given worktree
*/
static void add_head_info(struct worktree *wt)
{
@@ -352,13 +352,12 @@ int is_worktree_being_rebased(const struct worktree *wt,
memset(&state, 0, sizeof(state));
found_rebase = wt_status_check_rebase(wt, &state) &&
- ((state.rebase_in_progress ||
- state.rebase_interactive_in_progress) &&
- state.branch &&
- starts_with(target, "refs/heads/") &&
- !strcmp(state.branch, target + strlen("refs/heads/")));
- free(state.branch);
- free(state.onto);
+ (state.rebase_in_progress ||
+ state.rebase_interactive_in_progress) &&
+ state.branch &&
+ skip_prefix(target, "refs/heads/", &target) &&
+ !strcmp(state.branch, target);
+ wt_status_state_free_buffers(&state);
return found_rebase;
}
@@ -366,15 +365,15 @@ int is_worktree_being_bisected(const struct worktree *wt,
const char *target)
{
struct wt_status_state state;
- int found_rebase;
+ int found_bisect;
memset(&state, 0, sizeof(state));
- found_rebase = wt_status_check_bisect(wt, &state) &&
- state.branch &&
- starts_with(target, "refs/heads/") &&
- !strcmp(state.branch, target + strlen("refs/heads/"));
- free(state.branch);
- return found_rebase;
+ found_bisect = wt_status_check_bisect(wt, &state) &&
+ state.branch &&
+ skip_prefix(target, "refs/heads/", &target) &&
+ !strcmp(state.branch, target);
+ wt_status_state_free_buffers(&state);
+ return found_bisect;
}
/*
@@ -537,18 +536,10 @@ void strbuf_worktree_ref(const struct worktree *wt,
strbuf_addstr(sb, refname);
}
-const char *worktree_ref(const struct worktree *wt, const char *refname)
-{
- static struct strbuf sb = STRBUF_INIT;
-
- strbuf_reset(&sb);
- strbuf_worktree_ref(wt, &sb, refname);
- return sb.buf;
-}
-
int other_head_refs(each_ref_fn fn, void *cb_data)
{
struct worktree **worktrees, **p;
+ struct strbuf refname = STRBUF_INIT;
int ret = 0;
worktrees = get_worktrees();
@@ -560,15 +551,18 @@ int other_head_refs(each_ref_fn fn, void *cb_data)
if (wt->is_current)
continue;
+ strbuf_reset(&refname);
+ strbuf_worktree_ref(wt, &refname, "HEAD");
if (!refs_read_ref_full(get_main_ref_store(the_repository),
- worktree_ref(wt, "HEAD"),
+ refname.buf,
RESOLVE_REF_READING,
&oid, &flag))
- ret = fn(worktree_ref(wt, "HEAD"), &oid, flag, cb_data);
+ ret = fn(refname.buf, &oid, flag, cb_data);
if (ret)
break;
}
free_worktrees(worktrees);
+ strbuf_release(&refname);
return ret;
}
diff --git a/worktree.h b/worktree.h
index ff7b62e..f38e6fd 100644
--- a/worktree.h
+++ b/worktree.h
@@ -159,11 +159,4 @@ void strbuf_worktree_ref(const struct worktree *wt,
struct strbuf *sb,
const char *refname);
-/*
- * Return a refname suitable for access from the current ref
- * store. The result will be destroyed at the next call.
- */
-const char *worktree_ref(const struct worktree *wt,
- const char *refname);
-
#endif
diff --git a/wt-status.c b/wt-status.c
index 160d149..7074bbd 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -776,9 +776,14 @@ void wt_status_collect(struct wt_status *s)
void wt_status_collect_free_buffers(struct wt_status *s)
{
- free(s->state.branch);
- free(s->state.onto);
- free(s->state.detached_from);
+ wt_status_state_free_buffers(&s->state);
+}
+
+void wt_status_state_free_buffers(struct wt_status_state *state)
+{
+ FREE_AND_NULL(state->branch);
+ FREE_AND_NULL(state->onto);
+ FREE_AND_NULL(state->detached_from);
}
static void wt_longstatus_print_unmerged(struct wt_status *s)
@@ -1225,7 +1230,7 @@ static int split_commit_in_progress(struct wt_status *s)
* The function assumes that the line does not contain useless spaces
* before or after the command.
*/
-static void abbrev_sha1_in_line(struct strbuf *line)
+static void abbrev_oid_in_line(struct strbuf *line)
{
struct strbuf **split;
int i;
@@ -1275,7 +1280,7 @@ static int read_rebase_todolist(const char *fname, struct string_list *lines)
strbuf_trim(&line);
if (!line.len)
continue;
- abbrev_sha1_in_line(&line);
+ abbrev_oid_in_line(&line);
string_list_append(lines, line.buf);
}
fclose(f);
@@ -1568,9 +1573,9 @@ static void wt_status_get_detached_from(struct repository *r,
}
if (dwim_ref(cb.buf.buf, cb.buf.len, &oid, &ref, 1) == 1 &&
- /* sha1 is a commit? match without further lookup */
+ /* oid is a commit? match without further lookup */
(oideq(&cb.noid, &oid) ||
- /* perhaps sha1 is a tag, try to dereference to a commit */
+ /* perhaps oid is a tag, try to dereference to a commit */
((commit = lookup_commit_reference_gently(r, &oid, 1)) != NULL &&
oideq(&cb.noid, &commit->object.oid)))) {
const char *from = ref;
@@ -1799,29 +1804,36 @@ static void wt_longstatus_print(struct wt_status *s)
; /* nothing */
else if (s->workdir_dirty) {
if (s->hints)
- printf(_("no changes added to commit "
- "(use \"git add\" and/or \"git commit -a\")\n"));
+ fprintf(s->fp, _("no changes added to commit "
+ "(use \"git add\" and/or "
+ "\"git commit -a\")\n"));
else
- printf(_("no changes added to commit\n"));
+ fprintf(s->fp, _("no changes added to "
+ "commit\n"));
} else if (s->untracked.nr) {
if (s->hints)
- printf(_("nothing added to commit but untracked files "
- "present (use \"git add\" to track)\n"));
+ fprintf(s->fp, _("nothing added to commit but "
+ "untracked files present (use "
+ "\"git add\" to track)\n"));
else
- printf(_("nothing added to commit but untracked files present\n"));
+ fprintf(s->fp, _("nothing added to commit but "
+ "untracked files present\n"));
} else if (s->is_initial) {
if (s->hints)
- printf(_("nothing to commit (create/copy files "
- "and use \"git add\" to track)\n"));
+ fprintf(s->fp, _("nothing to commit (create/"
+ "copy files and use \"git "
+ "add\" to track)\n"));
else
- printf(_("nothing to commit\n"));
+ fprintf(s->fp, _("nothing to commit\n"));
} else if (!s->show_untracked_files) {
if (s->hints)
- printf(_("nothing to commit (use -u to show untracked files)\n"));
+ fprintf(s->fp, _("nothing to commit (use -u to "
+ "show untracked files)\n"));
else
- printf(_("nothing to commit\n"));
+ fprintf(s->fp, _("nothing to commit\n"));
} else
- printf(_("nothing to commit, working tree clean\n"));
+ fprintf(s->fp, _("nothing to commit, working tree "
+ "clean\n"));
}
if(s->show_stash)
wt_longstatus_print_stash_summary(s);
@@ -1844,12 +1856,12 @@ static void wt_shortstatus_unmerged(struct string_list_item *it,
}
color_fprintf(s->fp, color(WT_STATUS_UNMERGED, s), "%s", how);
if (s->null_termination) {
- fprintf(stdout, " %s%c", it->string, 0);
+ fprintf(s->fp, " %s%c", it->string, 0);
} else {
struct strbuf onebuf = STRBUF_INIT;
const char *one;
one = quote_path(it->string, s->prefix, &onebuf, QUOTE_PATH_QUOTE_SP);
- printf(" %s\n", one);
+ fprintf(s->fp, " %s\n", one);
strbuf_release(&onebuf);
}
}
@@ -1862,16 +1874,16 @@ static void wt_shortstatus_status(struct string_list_item *it,
if (d->index_status)
color_fprintf(s->fp, color(WT_STATUS_UPDATED, s), "%c", d->index_status);
else
- putchar(' ');
+ fputc(' ', s->fp);
if (d->worktree_status)
color_fprintf(s->fp, color(WT_STATUS_CHANGED, s), "%c", d->worktree_status);
else
- putchar(' ');
- putchar(' ');
+ fputc(' ', s->fp);
+ fputc(' ', s->fp);
if (s->null_termination) {
- fprintf(stdout, "%s%c", it->string, 0);
+ fprintf(s->fp, "%s%c", it->string, 0);
if (d->rename_source)
- fprintf(stdout, "%s%c", d->rename_source, 0);
+ fprintf(s->fp, "%s%c", d->rename_source, 0);
} else {
struct strbuf onebuf = STRBUF_INIT;
const char *one;
@@ -1879,11 +1891,11 @@ static void wt_shortstatus_status(struct string_list_item *it,
if (d->rename_source) {
one = quote_path(d->rename_source, s->prefix, &onebuf,
QUOTE_PATH_QUOTE_SP);
- printf("%s -> ", one);
+ fprintf(s->fp, "%s -> ", one);
strbuf_release(&onebuf);
}
one = quote_path(it->string, s->prefix, &onebuf, QUOTE_PATH_QUOTE_SP);
- printf("%s\n", one);
+ fprintf(s->fp, "%s\n", one);
strbuf_release(&onebuf);
}
}
@@ -1892,13 +1904,13 @@ static void wt_shortstatus_other(struct string_list_item *it,
struct wt_status *s, const char *sign)
{
if (s->null_termination) {
- fprintf(stdout, "%s %s%c", sign, it->string, 0);
+ fprintf(s->fp, "%s %s%c", sign, it->string, 0);
} else {
struct strbuf onebuf = STRBUF_INIT;
const char *one;
one = quote_path(it->string, s->prefix, &onebuf, QUOTE_PATH_QUOTE_SP);
color_fprintf(s->fp, color(WT_STATUS_UNTRACKED, s), "%s", sign);
- printf(" %s\n", one);
+ fprintf(s->fp, " %s\n", one);
strbuf_release(&onebuf);
}
}
diff --git a/wt-status.h b/wt-status.h
index f1fa0ec..35b44c3 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -151,7 +151,14 @@ void wt_status_add_cut_line(FILE *fp);
void wt_status_prepare(struct repository *r, struct wt_status *s);
void wt_status_print(struct wt_status *s);
void wt_status_collect(struct wt_status *s);
+/*
+ * Frees the buffers allocated by wt_status_collect.
+ */
void wt_status_collect_free_buffers(struct wt_status *s);
+/*
+ * Frees the buffers of the wt_status_state.
+ */
+void wt_status_state_free_buffers(struct wt_status_state *s);
void wt_status_get_state(struct repository *repo,
struct wt_status_state *state,
int get_detached_from);