Compare commits

..

67 Commits

Author SHA1 Message Date
d0654dc308 Git 2.25
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-01-13 10:16:43 -08:00
b4615e40a8 Merge tag 'l10n-2.25.0-rnd1' of git://github.com/git-l10n/git-po
l10n-2.25.0-rnd1

* tag 'l10n-2.25.0-rnd1' of git://github.com/git-l10n/git-po:
  l10n: zh_CN: for git v2.25.0 l10n round 1
  l10n: Update Catalan translation
  l10n: de.po: Update German translation v2.25.0 round 1
  l10n: de.po: Reword generation numbers
  l10n: bg.po: Updated Bulgarian translation (4800t)
  l10n: es: 2.25.0 round #1
  l10n: sv.po: Update Swedish translation (4800t0f0u)
  l10n: fr.po v2.25.0 rnd 1
  l10n: vi(4800t): Updated Vietnamese translation v2.25.0
  l10n: zh_TW.po: update translation for v2.25.0 round 1
  l10n: it.po: update the Italian translation for Git 2.25.0
  l10n: git.pot: v2.25.0 round 1 (119 new, 13 removed)
  l10n: Update Catalan translation
  l10n: zh_TW: add translation for v2.24.0
2020-01-12 13:28:13 -08:00
4d924528d8 Revert "Merge branch 'ra/rebase-i-more-options'"
This reverts commit 5d9324e0f4, reversing
changes made to c58ae96fc4.

The topic turns out to be too buggy for real use.

cf. <f2fe7437-8a48-3315-4d3f-8d51fe4bb8f1@gmail.com>
2020-01-12 13:25:18 -08:00
ddc12c429b l10n: zh_CN: for git v2.25.0 l10n round 1
Translate 119 new messages (4800t0f0u) for git 2.25.0.

Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
2020-01-12 19:22:02 +08:00
e23b95e75b Merge branch 'master' of github.com:Softcatala/git-po into git-po-master
* 'master' of github.com:Softcatala/git-po:
  l10n: Update Catalan translation
2020-01-11 16:04:21 +08:00
1cf4836865 Merge branch 'js/mingw-loosen-overstrict-tree-entry-checks'
Further tweak to a "no backslash in indexed paths" for Windows port
we applied earlier.

* js/mingw-loosen-overstrict-tree-entry-checks:
  mingw: safeguard better against backslashes in file names
2020-01-10 14:45:27 -08:00
d78a1968c5 Merge branch 'ma/config-advice-markup-fix'
Documentation markup fix.

* ma/config-advice-markup-fix:
  config/advice.txt: fix description list separator
2020-01-10 14:45:26 -08:00
a20ae3ee29 l10n: Update Catalan translation
Signed-off-by: Jordi Mas <jmas@softcatala.org>
2020-01-10 22:21:55 +01:00
49e268e23e mingw: safeguard better against backslashes in file names
In 224c7d70fa (mingw: only test index entries for backslashes, not tree
entries, 2019-12-31), we relaxed the check for backslashes in tree
entries to check only index entries.

However, the code change was incorrect: it was added to
`add_index_entry_with_check()`, not to `add_index_entry()`, so under
certain circumstances it was possible to side-step the protection.

Besides, the description of that commit purported that all index entries
would be checked when in fact they were only checked when being added to
the index (there are code paths that do not do that, constructing
"transient" index entries).

In any case, it was pointed out in one insightful review at
https://github.com/git-for-windows/git/pull/2437#issuecomment-566771835
that it would be a much better idea to teach `verify_path()` to perform
the check for a backslash. This is safer, even if it comes with two
notable drawbacks:

- `verify_path()` cannot say _what_ is wrong with the path, therefore
  the user will no longer be told that there was a backslash in the
  path, only that the path was invalid.

- The `git apply` command also calls the `verify_path()` function, and
  might have been able to handle Windows-style paths (i.e. with
  backslashes instead of forward slashes). This will no longer be
  possible unless the user (temporarily) sets `core.protectNTFS=false`.

Note that `git add <windows-path>` will _still_ work because
`normalize_path_copy_len()` will convert the backslashes to forward
slashes before hitting the code path that creates an index entry.

The clear advantage is that `verify_path()`'s purpose is to check the
validity of the file name, therefore we naturally tap into all the code
paths that need safeguarding, also implicitly into future code paths.

The benefits of that approach outweigh the downsides, so let's move the
check from `add_index_entry_with_check()` to `verify_path()`.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-01-10 12:29:07 -08:00
63a5650a49 l10n: de.po: Update German translation v2.25.0 round 1
Signed-off-by: Matthias Rüster <matthias.ruester@gmail.com>
Reviewed-by: Ralf Thielow <ralf.thielow@gmail.com>
Reviewed-by: Phillip Szelat <phillip.szelat@gmail.com>
2020-01-10 12:04:03 +01:00
75449c1b39 l10n: de.po: Reword generation numbers
The english term generation is here not used in the sense of "to
generate" but in the sense of "generations of beings".

This corrects the initial translation from cf4c0c25 (l10n: update German
translation, 2018-12-06).

Fixed-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Ralf Thielow <ralf.thielow@gmail.com>
2020-01-10 12:04:03 +01:00
6b6a9803fb l10n: bg.po: Updated Bulgarian translation (4800t)
Signed-off-by: Alexander Shopov <ash@kambanaria.org>
2020-01-09 16:32:25 +01:00
3901d2c6bd config/advice.txt: fix description list separator
The whole submoduleAlternateErrorStrategyDie item is interpreted as
being part of the supporting content of the preceding item. This is
because we don't give a double-colon "::" for the separator, but just a
single colon, ":". Let's fix that.

There are a few other matches for [^:]:\s*$ in Documentation/config, but
I didn't spot any similar bugs among them.

Signed-off-by: Martin Ågren <martin.agren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-01-08 13:38:24 -08:00
7a6a90c6ec Git 2.25-rc2
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-01-08 12:44:13 -08:00
1f5f3ffe5c Merge branch 'ds/graph-assert-fix'
Since recent updates to the log graph rendering code, drawing
certain merges started triggering an assert on a condition that
would no longer hold true, which has been corrected.

* ds/graph-assert-fix:
  graph: fix lack of color in horizontal lines
  graph: drop assert() for merge with two collapsing parents
2020-01-08 12:44:13 -08:00
a4e4140ac9 Merge branch 'tm/doc-submodule-absorb-fix'
Typofix.

* tm/doc-submodule-absorb-fix:
  doc: submodule: fix typo for command absorbgitdirs
2020-01-08 12:44:12 -08:00
202f68b252 Merge branch 'pm/am-in-body-header-doc-update'
Doc update.

* pm/am-in-body-header-doc-update:
  am: document that Date: can appear as an in-body header
2020-01-08 12:44:12 -08:00
7e65f8638e Merge branch 'jb/doc-multi-pack-idx-fix'
Typofix.

* jb/doc-multi-pack-idx-fix:
  multi-pack-index: correct configuration in documentation
2020-01-08 12:44:12 -08:00
c5dc20638b Merge branch 'do/gitweb-typofix-in-comments'
Typofix.

* do/gitweb-typofix-in-comments:
  gitweb: fix a couple spelling errors in comments
2020-01-08 12:44:11 -08:00
fe47c9cb5f Merge https://github.com/prati0100/git-gui
* https://github.com/prati0100/git-gui:
  git-gui: allow opening currently selected file in default app
  git-gui: allow closing console window with Escape
  git gui: fix branch name encoding error
  git-gui: revert untracked files by deleting them
  git-gui: update status bar to track operations
  git-gui: consolidate naming conventions
2020-01-08 11:18:06 -08:00
a1087c9367 graph: fix lack of color in horizontal lines
In some cases, horizontal lines in rendered graphs can lose their
coloring. This is due to a use of graph_line_addch() instead of
graph_line_write_column(). Using a ternary operator to pick the
character is nice for compact code, but we actually need a column to
provide the color.

Add a test to t4215-log-skewed-merges.sh to prevent regression.

Reported-by: Jeff King <peff@peff.net>
Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-01-08 09:37:18 -08:00
0d251c3291 graph: drop assert() for merge with two collapsing parents
When "git log --graph" shows a merge commit that has two collapsing
lines, like:

    | | | | *
    | |_|_|/|
    |/| | |/
    | | |/|
    | |/| |
    | * | |
    * | | |

we trigger an assert():

        graph.c:1228: graph_output_collapsing_line: Assertion
                      `graph->mapping[i - 3] == target' failed.

The assert was introduced by eaf158f8 ("graph API: Use horizontal
lines for more compact graphs", 2009-04-21), which is quite old.
This assert is trying to say that when we complete a horizontal
line with a single slash, it is because we have reached our target.

It is actually the _second_ collapsing line that hits this assert.
The reason we are in this code path is because we are collapsing
the first line, and in that case we are hitting our target now
that the horizontal line is complete. However, the second line
cannot be a horizontal line, so it will collapse without horizontal
lines. In this case, it is inappropriate to assert that we have
reached our target, as we need to continue for another column
before reaching the target. Dropping the assert is safe here.

The new behavior in 0f0f389f12 (graph: tidy up display of
left-skewed merges, 2019-10-15) caused the behavior change that
made this assertion failure possible. In addition to making the
assert possible, it also changed how multiple edges collapse.

In a larger example, the current code will output a collapse
as follows:

	| | | | | | *
	| |_|_|_|_|/|\
	|/| | | | |/ /
	| | | | |/| /
	| | | |/| |/
	| | |/| |/|
	| |/| |/| |
	| | |/| | |
	| | * | | |

However, the intended collapse should allow multiple horizontal lines
as follows:

	| | | | | | *
	| |_|_|_|_|/|\
	|/| | | | |/ /
	| | |_|_|/| /
	| |/| | | |/
	| | | |_|/|
	| | |/| | |
	| | * | | |

This behavior is not corrected by this change, but is noted for a later
update.

Helped-by: Jeff King <peff@peff.net>
Reported-by: Bradley Smith <brad@brad-smith.co.uk>
Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-01-08 09:35:07 -08:00
042ed3e048 The final batch before -rc2
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-01-06 14:17:51 -08:00
0f1930cd1b Merge branch 'ds/sparse-cone'
Code cleanup.

* ds/sparse-cone:
  Documentation/git-sparse-checkout.txt: fix a typo
  sparse-checkout: use extern for global variables
2020-01-06 14:17:51 -08:00
037f067587 Merge branch 'ds/commit-graph-set-size-mult'
The code to write split commit-graph file(s) upon fetching computed
bogus value for the parameter used in splitting the resulting
files, which has been corrected.

* ds/commit-graph-set-size-mult:
  commit-graph: prefer default size_mult when given zero
2020-01-06 14:17:51 -08:00
f25f04edca Merge branch 'en/merge-recursive-oid-eq-simplify'
Code cleanup.

* en/merge-recursive-oid-eq-simplify:
  merge-recursive: remove unnecessary oid_eq function
2020-01-06 14:17:51 -08:00
c20d4fd44a Merge branch 'ds/sparse-list-in-cone-mode'
"git sparse-checkout list" subcommand learned to give its output in
a more concise form when the "cone" mode is in effect.

* ds/sparse-list-in-cone-mode:
  sparse-checkout: document interactions with submodules
  sparse-checkout: list directories in cone mode
2020-01-06 14:17:51 -08:00
a578ef9e63 Merge branch 'js/mingw-loosen-overstrict-tree-entry-checks'
An earlier update to Git for Windows declared that a tree object is
invalid if it has a path component with backslash in it, which was
overly strict, which has been corrected.  The only protection the
Windows users need is to prevent such path (or any path that their
filesystem cannot check out) from entering the index.

* js/mingw-loosen-overstrict-tree-entry-checks:
  mingw: only test index entries for backslashes, not tree entries
2020-01-06 14:17:50 -08:00
c4117fcb97 Merge branch 'pb/clarify-line-log-doc'
Doc update.

* pb/clarify-line-log-doc:
  doc: log, gitk: line-log arguments must exist in starting revision
  doc: log, gitk: document accepted line-log diff formats
2020-01-06 14:17:50 -08:00
556f0258df Merge branch 'ew/packfile-syscall-optim'
Code cleanup.

* ew/packfile-syscall-optim:
  packfile: replace lseek+read with pread
  packfile: remove redundant fcntl F_GETFD/F_SETFD
2020-01-06 14:17:50 -08:00
5814d44d9b doc: submodule: fix typo for command absorbgitdirs
The sentence wants to talk about the superproject's possesive, not plural form.

Signed-off-by: Thomas Menzel <dev@tomsit.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-01-06 09:24:46 -08:00
7fdc5f296f l10n: es: 2.25.0 round #1
Signed-off-by: Christopher Diaz Riveros <christopher.diaz.riv@gmail.com>
2020-01-06 09:18:43 -05:00
f8740c586b am: document that Date: can appear as an in-body header
Similar to "From:" and "Subject:" already mentioned in the
documentation, "Date:" can also appear as an in-body header
to override the value in the e-mail headers.  Document it.

Signed-off-by: Paul Menzel <pmenzel@molgen.mpg.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-01-04 15:12:39 -08:00
4e2c4c0d4f gitweb: fix a couple spelling errors in comments
Signed-off-by: Denis Ovsienko <denis@ovsienko.info>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-01-04 15:09:33 -08:00
421c0ffb02 multi-pack-index: correct configuration in documentation
It's core.multiPackIndex, not pack.multiIndex.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-01-04 15:02:06 -08:00
757ff352bd Documentation/git-sparse-checkout.txt: fix a typo
This typo was introduced in 94c0956b60 (sparse-checkout: create builtin
with 'list' subcommand, 2019-11-21).

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Acked-by: Derrick Stolee <dstolee@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-01-04 14:40:29 -08:00
0d2116c644 Merge branch 'zs/open-current-file'
Allow opening the currently selected file in its default app by clicking
on its name.

* zs/open-current-file:
  git-gui: allow opening currently selected file in default app
2020-01-05 02:38:03 +05:30
9d48668cd5 l10n: sv.po: Update Swedish translation (4800t0f0u)
Signed-off-by: Peter Krefting <peter@softwolves.pp.se>
2020-01-04 19:53:30 +01:00
3a05aacddd Merge branch 'fr_v2.25.0_rnd1' of github.com:jnavila/git into master
* 'fr_v2.25.0_rnd1' of github.com:jnavila/git:
  l10n: fr.po v2.25.0 rnd 1
2020-01-04 08:46:36 +08:00
4c5081614c l10n: fr.po v2.25.0 rnd 1
Signed-off-by: Jean-Noël Avila <jn.avila@free.fr>
2020-01-03 18:47:15 +01:00
5bb457409c l10n: vi(4800t): Updated Vietnamese translation v2.25.0
Signed-off-by: Tran Ngoc Quan <vnwildman@gmail.com>
2020-01-03 14:12:58 +07:00
63020f175f commit-graph: prefer default size_mult when given zero
In 50f26bd ("fetch: add fetch.writeCommitGraph config setting",
2019-09-02), the fetch builtin added the capability to write a
commit-graph using the "--split" feature. This feature creates
multiple commit-graph files, and those can merge based on a set
of "split options" including a size multiple. The default size
multiple is 2, which intends to provide a log_2 N depth of the
commit-graph chain where N is the number of commits.

However, I noticed during dogfooding that my commit-graph chains
were becoming quite large when left only to builds by 'git fetch'.
It turns out that in split_graph_merge_strategy(), we default the
size_mult variable to 2 except we override it with the context's
split_opts if they exist. In builtin/fetch.c, we create such a
split_opts, but do not populate it with values.

This problem is due to two failures:

 1. It is unclear that we can add the flag COMMIT_GRAPH_WRITE_SPLIT
    with a NULL split_opts.
 2. If we have a non-NULL split_opts, then we override the default
    values even if a zero value is given.

Correct both of these issues. First, do not override size_mult when
the options provide a zero value. Second, stop creating a split_opts
in the fetch builtin.

Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-01-02 13:46:34 -08:00
224c7d70fa mingw: only test index entries for backslashes, not tree entries
During a clone of a repository that contained a file with a backslash in
its name in the past, as of v2.24.1(2), Git for Windows prints errors
like this:

	error: filename in tree entry contains backslash: '\'

The idea is to prevent Git from even trying to write files with
backslashes in their file names: while these characters are valid in
file names on other platforms, on Windows it is interpreted as directory
separator (which would obviously lead to ambiguities, e.g. when there is
a file `a\b` and there is also a file `a/b`).

Arguably, this is the wrong layer for that error: As long as the user
never checks out the files whose names contain backslashes, there should
not be any problem in the first place.

So let's loosen the requirements: we now leave tree entries with
backslashes in their file names alone, but we do require any entries
that are added to the Git index to contain no backslashes on Windows.

Note: just as before, the check is guarded by `core.protectNTFS` (to
allow overriding the check by toggling that config setting), and it
is _only_ performed on Windows, as the backslash is not a directory
separator elsewhere, even when writing to NTFS-formatted volumes.

An alternative approach would be to try to prevent creating files with
backslashes in their file names. However, that comes with its own set of
problems. For example, `git config -f C:\ProgramData\Git\config ...` is
a very valid way to specify a custom config location, and we obviously
do _not_ want to prevent that. Therefore, the approach chosen in this
patch would appear to be better.

This addresses https://github.com/git-for-windows/git/issues/2435

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-01-02 12:56:08 -08:00
763a59e71c merge-recursive: remove unnecessary oid_eq function
Back when merge-recursive was first introduced in commit 6d297f8137
(Status update on merge-recursive in C, 2006-07-08), it created a
sha_eq() function.  This function pre-dated the introduction of
hashcmp() to cache.h by about a month, but was switched over to using
hashcmp() as part of commit 9047ebbc22 (Split out merge_recursive() to
merge-recursive.c, 2008-08-12).  In commit b4da9d62f9 (merge-recursive:
convert leaf functions to use struct object_id, 2016-06-24), sha_eq() was
renamed to oid_eq() and its hashcmp() call was switched to oideq().

oid_eq() is basically just a wrapper around oideq() that has some extra
checks to protect against NULL arguments or to allow short-circuiting if
one of the arguments is NULL.  I don't know if any caller ever tried to
call with NULL arguments, but certainly none do now which means the
extra checks serve no purpose.  (Also, if these checks were genuinely
useful, then they probably should be added to the main oideq() so all
callers could benefit from them.)

Reduce the cognitive overhead of having both oid_eq() and oideq(), by
getting rid of merge-recursive's special oid_eq() wrapper.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-01-02 10:35:24 -08:00
44143583b7 sparse-checkout: use extern for global variables
When the core.sparseCheckoutCone config setting was added in
879321eb0b ("sparse-checkout: add 'cone' mode" 2019-11-21), the
variables storing the config values for core.sparseCheckout and
core.sparseCheckoutCone were rearranged in cache.h, but in doing
so the "extern" keyword was dropped.

While we are tending to drop the "extern" keyword for function
declarations, it is still necessary for global variables used
across multiple *.c files. The impact of not having the extern
keyword may be unpredictable.

Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-01-02 10:18:42 -08:00
d6a6263f5f Merge branch 'translation_191231' of github.com:l10n-tw/git-po into git-po-master
* 'translation_191231' of github.com:l10n-tw/git-po:
  l10n: zh_TW.po: update translation for v2.25.0 round 1
2020-01-01 11:15:05 +08:00
13185fd241 l10n: zh_TW.po: update translation for v2.25.0 round 1
Signed-off-by: pan93412 <pan93412@gmail.com>
2019-12-31 21:17:41 +08:00
786f4d2405 git-gui: allow opening currently selected file in default app
Many times there's the need to quickly open a source file (the one you're
looking at in Git GUI) in the predefined text editor / IDE. Of course,
the file can be searched for in your preferred file manager or directly
in the text editor, but having the option to directly open the current
file from Git GUI would be just faster. This change enables just that by:
 - clicking the diff header path (which is now highlighted as a hyperlink)
 - or diff header path context menu -> Open

Note: executable files will be run and not opened for editing.

Signed-off-by: Zoli Szabó <zoli.szabo@gmail.com>
Signed-off-by: Pratyush Yadav <me@yadavpratyush.com>
2019-12-31 01:07:53 +05:30
4fd683b6a3 sparse-checkout: document interactions with submodules
Using 'git submodule (init|deinit)' a user can select a subset of
submodules to populate. This behaves very similar to the sparse-checkout
feature, but those directories contain their own .git directory
including an object database and ref space. To have the sparse-checkout
file also determine if those files should exist would easily cause
problems. Therefore, keeping these features independent in this way
is the best way forward.

Also create a test that demonstrates this behavior to make sure
it doesn't change as the sparse-checkout feature evolves.

Reported-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-12-30 09:07:20 -08:00
de11951b03 sparse-checkout: list directories in cone mode
When core.sparseCheckoutCone is enabled, the 'git sparse-checkout set'
command takes a list of directories as input, then creates an ordered
list of sparse-checkout patterns such that those directories are
recursively included and all sibling entries along the parent directories
are also included. Listing the patterns is less user-friendly than the
directories themselves.

In cone mode, and as long as the patterns match the expected cone-mode
pattern types, change the output of 'git sparse-checkout list' to only
show the directories that created the patterns.

With this change, the following piped commands would not change the
working directory:

	git sparse-checkout list | git sparse-checkout set --stdin

The only time this would not work is if core.sparseCheckoutCone is
true, but the sparse-checkout file contains patterns that do not
match the expected pattern types for cone mode.

Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-12-30 09:07:18 -08:00
0d3ce942b0 l10n: it.po: update the Italian translation for Git 2.25.0
Signed-off-by: Alessandro Menti <alessandro.menti@alessandromenti.it>
2019-12-30 09:48:44 +01:00
578c793731 l10n: git.pot: v2.25.0 round 1 (119 new, 13 removed)
Generate po/git.pot from v2.25.0-rc0 for git v2.25.0 l10n round 1.

Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
2019-12-30 08:52:42 +08:00
173fff68da Merge tag 'v2.25.0-rc0' into git-po-master
Git 2.25-rc0

* tag 'v2.25.0-rc0': (531 commits)
  Git 2.25-rc0
  sparse-checkout: improve OS ls compatibility
  dir.c: use st_add3() for allocation size
  dir: consolidate similar code in treat_directory()
  dir: synchronize treat_leading_path() and read_directory_recursive()
  dir: fix checks on common prefix directory
  t4015: improve coverage of function context test
  commit: forbid --pathspec-from-file --all
  t3434: mark successful test as such
  notes.h: fix typos in comment
  t6030: don't create unused file
  t5580: don't create unused file
  t3501: don't create unused file
  bisect--helper: convert `*_warning` char pointers to char arrays.
  The sixth batch
  fix-typo: consecutive-word duplications
  Makefile: drop GEN_HDRS
  built-in add -p: show helpful hint when nothing can be staged
  built-in add -p: only show the applicable parts of the help text
  built-in add -p: implement the 'q' ("quit") command
  ...
2019-12-30 08:47:27 +08:00
9e341f62ca l10n: Update Catalan translation
Signed-off-by: Jordi Mas <jmas@softcatala.org>
2019-12-27 18:23:20 +01:00
4e61b2214d packfile: replace lseek+read with pread
We already have pread emulation for portability, so there's
there's no reason to make two syscalls where one suffices.

Furthermore, readers of the packfile will be using mmap
(or pread to emulate mmap), anyways, so the file description
offset does not matter in this case.

Signed-off-by: Eric Wong <e@80x24.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-12-26 11:57:46 -08:00
ace0f86c7f doc: log, gitk: line-log arguments must exist in starting revision
The line number, regex or offset parameters <start> and <end> in
`git log -L <start>,<end>:<file>`, or the function name regex in
`git log -L :<funcname>:<file>` must exist in the starting
revision, or else the command exits with a fatal error.

This is not obvious in the documentation, so add a note to that
effect.

Signed-off-by: Philippe Blain <levraiphilippeblain@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-12-26 11:00:15 -08:00
2be45868a8 doc: log, gitk: document accepted line-log diff formats
Currently the line-log functionality (git log -L) only supports
displaying patch output (`-p | --patch`, its default behavior) and suppressing it
(`-s | --no-patch`). A check was added in the code to that effect in 5314efaea
(line-log: detect unsupported formats, 2019-03-10) but the documentation was not
updated.

Explicitly mention that `-L` implies `-p`, that patch output can be
suppressed using `-s`, and that all other diff formats are not allowed.

Signed-off-by: Philippe Blain <levraiphilippeblain@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-12-26 11:00:13 -08:00
280738c36e packfile: remove redundant fcntl F_GETFD/F_SETFD
git_open sets close-on-exec since cd66ada065
("sha1_file: open window into packfiles with O_CLOEXEC").
There's no reason to keep using fcntl to set the close-on-exec
flag, anymore.

Signed-off-by: Eric Wong <e@80x24.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-12-26 10:09:35 -08:00
23cbe427c4 Merge branch 'py/console-close-esc'
Allow closing console window with Escape once the command is completed.

* py/console-close-esc:
  git-gui: allow closing console window with Escape
2019-12-20 01:24:05 +05:30
1e1ccbfdd3 git-gui: allow closing console window with Escape
This gives users a quick shortcut to close the window. But since the
window can also show commands in progress, closing the window on Escape
can give the perception that the command has been cancelled even though
it hasn't been. So, only enable this binding when the command is done.

Signed-off-by: Pratyush Yadav <me@yadavpratyush.com>
2019-12-19 01:22:53 +05:30
d32e065a91 Merge branch 'kk/branch-name-encoding'
Fix UTF-8 refnames not displaying properly because the encoding was not
set to UTF-8.

* kk/branch-name-encoding:
  git gui: fix branch name encoding error
2019-12-11 21:32:29 +05:30
39acfa3d22 git gui: fix branch name encoding error
After "git checkout -b '漢字'" to create a branch with UTF-8 character
in it, "git gui" shows the branch name incorrectly, as it forgets to
turn the bytes read from the "git for-each-ref" and read from "HEAD"
file into Unicode characters.

Signed-off-by: Kazuhiro Kato <kato-k@ksysllc.co.jp>
Signed-off-by: Pratyush Yadav <me@yadavpratyush.com>
2019-12-10 02:43:55 +05:30
2763530048 Merge branch 'jg/revert-untracked'
git-gui learned to delete untracked files when the "Revert Changes"
option is selected. Since there are two types of revert operations (one
for tracked files and one for untracked ones), the "checkout" and
"deletion" operations are done in parallel. The status bar is updated
to allow both to use it in parallel.

* jg/revert-untracked:
  git-gui: revert untracked files by deleting them
  git-gui: update status bar to track operations
  git-gui: consolidate naming conventions
2019-12-06 00:40:55 +05:30
fa38ab68b0 git-gui: revert untracked files by deleting them
Update the revert_helper proc to check for untracked files as well as
changes, and then handle changes to be reverted and untracked files with
independent blocks of code. Prompt the user independently for untracked
files, since the underlying action is fundamentally different (rm -f).
If after deleting untracked files, the directory containing them becomes
empty, then remove the directory as well. Migrate unlocking of the index
out of _close_updateindex to a responsibility of the caller, to permit
paths that don't directly unlock the index, and refactor the error
handling added in d4e890e5 so that callers can make flow control
decisions in the event of errors. Update Tcl/Tk dependency from 8.4 to
8.6 in git-gui.sh.

A new proc delete_files takes care of actually deleting the files in
batches, using the Tcler's Wiki recommended approach for keeping the UI
responsive.

Since the checkout_index and delete_files calls are both asynchronous
and could potentially complete in any order, a "chord" is used to
coordinate unlocking the index and returning the UI to a usable state
only after both operations are complete. The `SimpleChord` class,
based on TclOO (Tcl/Tk 8.6), is added in this commit.

Signed-off-by: Jonathan Gilbert <JonathanG@iQmetrix.com>
Signed-off-by: Pratyush Yadav <me@yadavpratyush.com>
2019-12-06 00:12:15 +05:30
d9c6469f38 git-gui: update status bar to track operations
Update the status bar to track updates as individual "operations" that
can overlap. Update all call sites to interact with the new status bar
mechanism. Update initialization to explicitly clear status text,
since otherwise it may persist across future operations.

Signed-off-by: Jonathan Gilbert <JonathanG@iQmetrix.com>
Signed-off-by: Pratyush Yadav <me@yadavpratyush.com>
2019-12-06 00:12:15 +05:30
29a9366052 git-gui: consolidate naming conventions
A few variables in this file use camelCase, while the overall standard
is snake_case. A consistent naming scheme will improve readability of
future changes. To avoid mixing naming changes with semantic changes,
this commit contains only naming changes.

Signed-off-by: Jonathan Gilbert <JonathanG@iQmetrix.com>
Signed-off-by: Pratyush Yadav <me@yadavpratyush.com>
2019-12-06 00:12:15 +05:30
9917eca794 l10n: zh_TW: add translation for v2.24.0
Based on commit a5cd71ca4a ("l10n: zh_CN: for git v2.24.0 l10n round
1~2", 2019-10-29).

Signed-off-by: Yi-Jyun Pan <pan93412@gmail.com>
Reviewed-by: Franklin Weng <franklin@goodhorse.idv.tw>
Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
2019-11-25 10:07:12 +08:00
50 changed files with 54982 additions and 25009 deletions

View File

@ -53,9 +53,6 @@ UI, Workflows & Features
or a named file, instead of taking it as the command line
arguments, with the "--pathspec-from-file" option.
* "git rebase -i" learned a few options that are known by "git
rebase" proper.
* "git submodule" learned a subcommand "set-url".
* "git log" family learned "--pretty=reference" that gives the name
@ -72,6 +69,9 @@ UI, Workflows & Features
* Miscellaneous small UX improvements on "git-p4".
* "git sparse-checkout list" subcommand learned to give its output in
a more concise form when the "cone" mode is in effect.
Performance, Internal Implementation, Development Support etc.
@ -143,8 +143,6 @@ Performance, Internal Implementation, Development Support etc.
* The code has been made to avoid gmtime() and localtime() and prefer
their reentrant counterparts.
* The effort to reimplement "git add -i" in C continues.
* In a repository with many packfiles, the cost of the procedure that
avoids registering the same packfile twice was unnecessarily high
by using an inefficient search algorithm, which has been corrected.
@ -315,6 +313,18 @@ Fixes since v2.24
in C, which has been corrected.
(merge 4fe7e43c53 en/rebase-signoff-fix later to maint).
* An earlier update to Git for Windows declared that a tree object is
invalid if it has a path component with backslash in it, which was
overly strict, which has been corrected. The only protection the
Windows users need is to prevent such path (or any path that their
filesystem cannot check out) from entering the index.
(merge 224c7d70fa js/mingw-loosen-overstrict-tree-entry-checks later to maint).
* The code to write split commit-graph file(s) upon fetching computed
bogus value for the parameter used in splitting the resulting
files, which has been corrected.
(merge 63020f175f ds/commit-graph-set-size-mult later to maint).
* Other code cleanup, docfix, build fix, etc.
(merge 80736d7c5e jc/am-show-current-patch-docfix later to maint).
(merge 8b656572ca sg/commit-graph-usage-fix later to maint).
@ -351,3 +361,10 @@ Fixes since v2.24
(merge df5be01669 ja/doc-markup-cleanup later to maint).
(merge 7c5cea7242 mr/bisect-save-pointer-to-const-string later to maint).
(merge 20a67e8ce9 js/use-test-tool-on-path later to maint).
(merge 4e61b2214d ew/packfile-syscall-optim later to maint).
(merge ace0f86c7f pb/clarify-line-log-doc later to maint).
(merge 763a59e71c en/merge-recursive-oid-eq-simplify later to maint).
(merge 4e2c4c0d4f do/gitweb-typofix-in-comments later to maint).
(merge 421c0ffb02 jb/doc-multi-pack-idx-fix later to maint).
(merge f8740c586b pm/am-in-body-header-doc-update later to maint).
(merge 5814d44d9b tm/doc-submodule-absorb-fix later to maint).

View File

@ -107,7 +107,7 @@ advice.*::
editor input from the user.
nestedTag::
Advice shown if a user attempts to recursively tag a tag object.
submoduleAlternateErrorStrategyDie:
submoduleAlternateErrorStrategyDie::
Advice shown when a submodule.alternateErrorStrategy option
configured to "die" causes a fatal error.
--

View File

@ -190,8 +190,8 @@ the commit, after stripping common prefix "[PATCH <anything>]".
The "Subject: " line is supposed to concisely describe what the
commit is about in one line of text.
"From: " and "Subject: " lines starting the body override the respective
commit author name and title values taken from the headers.
"From: ", "Date: ", and "Subject: " lines starting the body override the
respective commit author name and title values taken from the headers.
The commit message is formed by the title taken from the
"Subject: ", a blank line and the body of the message up to

View File

@ -76,8 +76,12 @@ produced by `--stat`, etc.
(or the function name regex <funcname>) within the <file>. You may
not give any pathspec limiters. This is currently limited to
a walk starting from a single revision, i.e., you may only
give zero or one positive revision arguments.
You can specify this option more than once.
give zero or one positive revision arguments, and
<start> and <end> (or <funcname>) must exist in the starting revision.
You can specify this option more than once. Implies `--patch`.
Patch output can be suppressed using `--no-patch`, but other diff formats
(namely `--raw`, `--numstat`, `--shortstat`, `--dirstat`, `--summary`,
`--name-only`, `--name-status`, `--check`) are not currently implemented.
+
include::line-range-format.txt[]

View File

@ -393,31 +393,16 @@ your branch contains commits which were dropped, this option can be used
with `--keep-base` in order to drop those commits from your branch.
--ignore-whitespace::
Behaves differently depending on which backend is selected.
+
'am' backend: When applying a patch, ignore changes in whitespace in
context lines if necessary.
+
'interactive' backend: Treat lines with only whitespace changes as
unchanged for the sake of a three-way merge.
--whitespace=<option>::
This flag is passed to the 'git apply' program
These flag are passed to the 'git apply' program
(see linkgit:git-apply[1]) that applies the patch.
+
See also INCOMPATIBLE OPTIONS below.
--committer-date-is-author-date::
Instead of recording the time the rebased commits are
created as the committer date, reuse the author date
as the committer date. This implies --force-rebase.
--ignore-date::
--reset-author-date::
By default, the author date of the original commit is used
as the author date for the resulting commit. This option
tells Git to use the current timestamp instead and implies
`--force-rebase`.
These flags are passed to 'git am' to easily change the dates
of the rebased commits (see linkgit:git-am[1]).
+
See also INCOMPATIBLE OPTIONS below.
@ -554,7 +539,10 @@ INCOMPATIBLE OPTIONS
The following options:
* --committer-date-is-author-date
* --ignore-date
* --whitespace
* --ignore-whitespace
* -C
are incompatible with the following options:
@ -577,9 +565,6 @@ In addition, the following pairs of options are incompatible:
* --preserve-merges and --interactive
* --preserve-merges and --signoff
* --preserve-merges and --rebase-merges
* --preserve-merges and --ignore-whitespace
* --preserve-merges and --committer-date-is-author-date
* --preserve-merges and --ignore-date
* --keep-base and --onto
* --keep-base and --root

View File

@ -5,7 +5,7 @@ NAME
----
git-sparse-checkout - Initialize and modify the sparse-checkout
configuration, which reduces the checkout to a set of paths
given by a list of atterns.
given by a list of patterns.
SYNOPSIS
@ -28,7 +28,7 @@ THE FUTURE.
COMMANDS
--------
'list'::
Provide a list of the contents in the sparse-checkout file.
Describe the patterns in the sparse-checkout file.
'init'::
Enable the `core.sparseCheckout` setting. If the
@ -150,11 +150,30 @@ expecting patterns of these types. Git will warn if the patterns do not match.
If the patterns do match the expected format, then Git will use faster hash-
based algorithms to compute inclusion in the sparse-checkout.
In the cone mode case, the `git sparse-checkout list` subcommand will list the
directories that define the recursive patterns. For the example sparse-checkout
file above, the output is as follows:
--------------------------
$ git sparse-checkout list
A/B/C
--------------------------
If `core.ignoreCase=true`, then the pattern-matching algorithm will use a
case-insensitive check. This corrects for case mismatched filenames in the
'git sparse-checkout set' command to reflect the expected cone in the working
directory.
SUBMODULES
----------
If your repository contains one or more submodules, then those submodules will
appear based on which you initialized with the `git submodule` command. If
your sparse-checkout patterns exclude an initialized submodule, then that
submodule will still appear in your working directory.
SEE ALSO
--------

View File

@ -248,7 +248,7 @@ registered submodules, and sync any nested submodules within.
absorbgitdirs::
If a git directory of a submodule is inside the submodule,
move the git directory of the submodule into its superprojects
move the git directory of the submodule into its superproject's
`$GIT_DIR/modules` path and then connect the git directory and
its working directory by setting the `core.worktree` and adding
a .git file pointing to the git directory embedded in the

View File

@ -105,8 +105,12 @@ linkgit:git-rev-list[1] for a complete list.
(or the function name regex <funcname>) within the <file>. You may
not give any pathspec limiters. This is currently limited to
a walk starting from a single revision, i.e., you may only
give zero or one positive revision arguments.
You can specify this option more than once.
give zero or one positive revision arguments, and
<start> and <end> (or <funcname>) must exist in the starting revision.
You can specify this option more than once. Implies `--patch`.
Patch output can be suppressed using `--no-patch`, but other diff formats
(namely `--raw`, `--numstat`, `--shortstat`, `--dirstat`, `--summary`,
`--name-only`, `--name-status`, `--check`) are not currently implemented.
+
*Note:* gitk (unlike linkgit:git-log[1]) currently only understands
this option if you specify it "glued together" with its argument. Do

View File

@ -36,7 +36,7 @@ Design Details
directory of an alternate. It refers only to packfiles in that
same directory.
- The pack.multiIndex config setting must be on to consume MIDX files.
- The core.multiPackIndex config setting must be on to consume MIDX files.
- The file format includes parameters for the object ID hash
function, so a future change of hash algorithm does not require

View File

@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
DEF_VER=v2.25.0-rc1
DEF_VER=v2.25.0
LF='
'

View File

@ -1866,15 +1866,13 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
(fetch_write_commit_graph < 0 &&
the_repository->settings.fetch_write_commit_graph)) {
int commit_graph_flags = COMMIT_GRAPH_WRITE_SPLIT;
struct split_commit_graph_opts split_opts;
memset(&split_opts, 0, sizeof(struct split_commit_graph_opts));
if (progress)
commit_graph_flags |= COMMIT_GRAPH_WRITE_PROGRESS;
write_commit_graph_reachable(get_object_directory(),
commit_graph_flags,
&split_opts);
NULL);
}
close_object_store(the_repository->objects);

View File

@ -79,11 +79,8 @@ struct rebase_options {
int allow_rerere_autoupdate;
int keep_empty;
int autosquash;
int ignore_whitespace;
char *gpg_sign_opt;
int autostash;
int committer_date_is_author_date;
int ignore_date;
char *cmd;
int allow_empty_message;
int rebase_merges, rebase_cousins;
@ -102,7 +99,6 @@ struct rebase_options {
static struct replay_opts get_replay_opts(const struct rebase_options *opts)
{
struct strbuf strategy_buf = STRBUF_INIT;
struct replay_opts replay = REPLAY_OPTS_INIT;
replay.action = REPLAY_INTERACTIVE_REBASE;
@ -116,20 +112,10 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)
replay.allow_empty_message = opts->allow_empty_message;
replay.verbose = opts->flags & REBASE_VERBOSE;
replay.reschedule_failed_exec = opts->reschedule_failed_exec;
replay.committer_date_is_author_date =
opts->committer_date_is_author_date;
replay.ignore_date = opts->ignore_date;
replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);
replay.strategy = opts->strategy;
if (opts->strategy_opts)
strbuf_addstr(&strategy_buf, opts->strategy_opts);
if (opts->ignore_whitespace)
strbuf_addstr(&strategy_buf, " --ignore-space-change");
if (strategy_buf.len)
parse_strategy_opts(&replay, strategy_buf.buf);
strbuf_release(&strategy_buf);
parse_strategy_opts(&replay, opts->strategy_opts);
if (opts->squash_onto) {
oidcpy(&replay.squash_onto, opts->squash_onto);
@ -531,8 +517,6 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, options,
builtin_rebase_interactive_usage, PARSE_OPT_KEEP_ARGV0);
opts.strategy_opts = xstrdup_or_null(opts.strategy_opts);
if (!is_null_oid(&squash_onto))
opts.squash_onto = &squash_onto;
@ -986,12 +970,6 @@ static int run_am(struct rebase_options *opts)
am.git_cmd = 1;
argv_array_push(&am.args, "am");
if (opts->ignore_whitespace)
argv_array_push(&am.args, "--ignore-whitespace");
if (opts->committer_date_is_author_date)
argv_array_push(&opts->git_am_opts, "--committer-date-is-author-date");
if (opts->ignore_date)
argv_array_push(&opts->git_am_opts, "--ignore-date");
if (opts->action && !strcmp("continue", opts->action)) {
argv_array_push(&am.args, "--resolved");
argv_array_pushf(&am.args, "--resolvemsg=%s", resolvemsg);
@ -1459,17 +1437,16 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
PARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },
OPT_BOOL(0, "signoff", &options.signoff,
N_("add a Signed-off-by: line to each commit")),
OPT_BOOL(0, "committer-date-is-author-date",
&options.committer_date_is_author_date,
N_("make committer date match author date")),
OPT_BOOL(0, "reset-author-date", &options.ignore_date,
N_("ignore author date and use current date")),
OPT_HIDDEN_BOOL(0, "ignore-date", &options.ignore_date,
N_("synonym of --reset-author-date")),
OPT_PASSTHRU_ARGV(0, "ignore-whitespace", &options.git_am_opts,
NULL, N_("passed to 'git am'"),
PARSE_OPT_NOARG),
OPT_PASSTHRU_ARGV(0, "committer-date-is-author-date",
&options.git_am_opts, NULL,
N_("passed to 'git am'"), PARSE_OPT_NOARG),
OPT_PASSTHRU_ARGV(0, "ignore-date", &options.git_am_opts, NULL,
N_("passed to 'git am'"), PARSE_OPT_NOARG),
OPT_PASSTHRU_ARGV('C', NULL, &options.git_am_opts, N_("n"),
N_("passed to 'git apply'"), 0),
OPT_BOOL(0, "ignore-whitespace", &options.ignore_whitespace,
N_("ignore changes in whitespace")),
OPT_PASSTHRU_ARGV(0, "whitespace", &options.git_am_opts,
N_("action"), N_("passed to 'git apply'"), 0),
OPT_BIT('f', "force-rebase", &options.flags,
@ -1742,13 +1719,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
state_dir_base, cmd_live_rebase, buf.buf);
}
if (options.committer_date_is_author_date ||
options.ignore_date)
options.flags |= REBASE_FORCE;
for (i = 0; i < options.git_am_opts.argc; i++) {
const char *option = options.git_am_opts.argv[i], *p;
if (!strcmp(option, "--whitespace=fix") ||
if (!strcmp(option, "--committer-date-is-author-date") ||
!strcmp(option, "--ignore-date") ||
!strcmp(option, "--whitespace=fix") ||
!strcmp(option, "--whitespace=strip"))
options.flags |= REBASE_FORCE;
else if (skip_prefix(option, "-C", &p)) {

View File

@ -53,6 +53,8 @@ static int sparse_checkout_list(int argc, const char **argv)
memset(&pl, 0, sizeof(pl));
pl.use_cone_patterns = core_sparse_checkout_cone;
sparse_filename = get_sparse_checkout_filename();
res = add_patterns_from_file_to_list(sparse_filename, "", 0, &pl, NULL);
free(sparse_filename);
@ -62,6 +64,25 @@ static int sparse_checkout_list(int argc, const char **argv)
return 0;
}
if (pl.use_cone_patterns) {
int i;
struct pattern_entry *pe;
struct hashmap_iter iter;
struct string_list sl = STRING_LIST_INIT_DUP;
hashmap_for_each_entry(&pl.recursive_hashmap, &iter, pe, ent) {
/* pe->pattern starts with "/", skip it */
string_list_insert(&sl, pe->pattern + 1);
}
string_list_sort(&sl);
for (i = 0; i < sl.nr; i++)
printf("%s\n", sl.items[i].string);
return 0;
}
write_patterns_to_file(stdout, &pl);
clear_pattern_list(&pl);

View File

@ -958,8 +958,8 @@ extern int protect_hfs;
extern int protect_ntfs;
extern const char *core_fsmonitor;
int core_apply_sparse_checkout;
int core_sparse_checkout_cone;
extern int core_apply_sparse_checkout;
extern int core_sparse_checkout_cone;
/*
* Include broken refs in all ref iterations, which will

View File

@ -1542,7 +1542,9 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)
if (ctx->split_opts) {
max_commits = ctx->split_opts->max_commits;
size_mult = ctx->split_opts->size_multiple;
if (ctx->split_opts->size_multiple)
size_mult = ctx->split_opts->size_multiple;
}
g = ctx->r->objects->commit_graph;

View File

@ -30,8 +30,8 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.}]
##
## Tcl/Tk sanity check
if {[catch {package require Tcl 8.4} err]
|| [catch {package require Tk 8.4} err]
if {[catch {package require Tcl 8.6} err]
|| [catch {package require Tk 8.6} err]
} {
catch {wm withdraw .}
tk_messageBox \
@ -684,6 +684,7 @@ proc load_current_branch {} {
global current_branch is_detached
set fd [open [gitdir HEAD] r]
fconfigure $fd -translation binary -encoding utf-8
if {[gets $fd ref] < 1} {
set ref {}
}
@ -1797,10 +1798,10 @@ proc ui_status {msg} {
}
}
proc ui_ready {{test {}}} {
proc ui_ready {} {
global main_status
if {[info exists main_status]} {
$main_status show [mc "Ready."] $test
$main_status show [mc "Ready."]
}
}
@ -2150,8 +2151,6 @@ proc incr_font_size {font {amt 1}} {
##
## ui commands
set starting_gitk_msg [mc "Starting gitk... please wait..."]
proc do_gitk {revs {is_submodule false}} {
global current_diff_path file_states current_diff_side ui_index
global _gitdir _gitworktree
@ -2206,10 +2205,11 @@ proc do_gitk {revs {is_submodule false}} {
set env(GIT_WORK_TREE) $_gitworktree
cd $pwd
ui_status $::starting_gitk_msg
after 10000 {
ui_ready $starting_gitk_msg
}
set status_operation [$::main_status \
start \
[mc "Starting %s... please wait..." "gitk"]]
after 3500 [list $status_operation stop]
}
}
@ -2240,16 +2240,16 @@ proc do_git_gui {} {
set env(GIT_WORK_TREE) $_gitworktree
cd $pwd
ui_status $::starting_gitk_msg
after 10000 {
ui_ready $starting_gitk_msg
}
set status_operation [$::main_status \
start \
[mc "Starting %s... please wait..." "git-gui"]]
after 3500 [list $status_operation stop]
}
}
proc do_explore {} {
global _gitworktree
set explorer {}
# Get the system-specific explorer app/command.
proc get_explorer {} {
if {[is_Cygwin] || [is_Windows]} {
set explorer "explorer.exe"
} elseif {[is_MacOSX]} {
@ -2258,9 +2258,23 @@ proc do_explore {} {
# freedesktop.org-conforming system is our best shot
set explorer "xdg-open"
}
return $explorer
}
proc do_explore {} {
global _gitworktree
set explorer [get_explorer]
eval exec $explorer [list [file nativename $_gitworktree]] &
}
# Open file relative to the working tree by the default associated app.
proc do_file_open {file} {
global _gitworktree
set explorer [get_explorer]
set full_file_path [file join $_gitworktree $file]
exec $explorer [file nativename $full_file_path] &
}
set is_quitting 0
set ret_code 1
@ -3512,9 +3526,11 @@ tlabel .vpane.lower.diff.header.file \
-justify left
tlabel .vpane.lower.diff.header.path \
-background gold \
-foreground black \
-foreground blue \
-anchor w \
-justify left
-justify left \
-font [eval font create [font configure font_ui] -underline 1] \
-cursor hand2
pack .vpane.lower.diff.header.status -side left
pack .vpane.lower.diff.header.file -side left
pack .vpane.lower.diff.header.path -fill x
@ -3529,8 +3545,12 @@ $ctxm add command \
-type STRING \
-- $current_diff_path
}
$ctxm add command \
-label [mc Open] \
-command {do_file_open $current_diff_path}
lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
bind_button3 .vpane.lower.diff.header.path "tk_popup $ctxm %X %Y"
bind .vpane.lower.diff.header.path <Button-1> {do_file_open $current_diff_path}
# -- Diff Body
#
@ -4159,6 +4179,9 @@ if {$picked && [is_config_true gui.autoexplore]} {
do_explore
}
# Clear "Initializing..." status
after 500 {$main_status show ""}
# Local variables:
# mode: tcl
# indent-tabs-mode: t

View File

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

View File

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

View File

@ -341,9 +341,9 @@ method _readtree {} {
global HEAD
set readtree_d {}
$::main_status start \
set status_bar_operation [$::main_status start \
[mc "Updating working directory to '%s'..." [_name $this]] \
[mc "files checked out"]
[mc "files checked out"]]
set fd [git_read --stderr read-tree \
-m \
@ -354,26 +354,27 @@ method _readtree {} {
$new_hash \
]
fconfigure $fd -blocking 0 -translation binary
fileevent $fd readable [cb _readtree_wait $fd]
fileevent $fd readable [cb _readtree_wait $fd $status_bar_operation]
}
method _readtree_wait {fd} {
method _readtree_wait {fd status_bar_operation} {
global current_branch
set buf [read $fd]
$::main_status update_meter $buf
$status_bar_operation update_meter $buf
append readtree_d $buf
fconfigure $fd -blocking 1
if {![eof $fd]} {
fconfigure $fd -blocking 0
$status_bar_operation stop
return
}
if {[catch {close $fd}]} {
set err $readtree_d
regsub {^fatal: } $err {} err
$::main_status stop [mc "Aborted checkout of '%s' (file level merging is required)." [_name $this]]
$status_bar_operation stop [mc "Aborted checkout of '%s' (file level merging is required)." [_name $this]]
warn_popup [strcat [mc "File level merge required."] "
$err
@ -384,7 +385,7 @@ $err
return
}
$::main_status stop
$status_bar_operation stop
_after_readtree $this
}

View File

@ -9,6 +9,18 @@ field w_body ; # Widget holding the center content
field w_next ; # Next button
field w_quit ; # Quit button
field o_cons ; # Console object (if active)
# Status mega-widget instance during _do_clone2 (used by _copy_files and
# _link_files). Widget is destroyed before _do_clone2 calls
# _do_clone_checkout
field o_status
# Operation displayed by status mega-widget during _do_clone_checkout =>
# _readtree_wait => _postcheckout_wait => _do_clone_submodules =>
# _do_validate_submodule_cloning. The status mega-widget is a different
# instance than that stored in $o_status in earlier operations.
field o_status_op
field w_types ; # List of type buttons in clone
field w_recentlist ; # Listbox containing recent repositories
field w_localpath ; # Entry widget bound to local_path
@ -659,12 +671,12 @@ method _do_clone2 {} {
switch -exact -- $clone_type {
hardlink {
set o_cons [status_bar::two_line $w_body]
set o_status [status_bar::two_line $w_body]
pack $w_body -fill x -padx 10 -pady 10
$o_cons start \
set status_op [$o_status start \
[mc "Counting objects"] \
[mc "buckets"]
[mc "buckets"]]
update
if {[file exists [file join $objdir info alternates]]} {
@ -689,6 +701,7 @@ method _do_clone2 {} {
} err]} {
catch {cd $pwd}
_clone_failed $this [mc "Unable to copy objects/info/alternates: %s" $err]
$status_op stop
return
}
}
@ -700,7 +713,7 @@ method _do_clone2 {} {
-directory [file join $objdir] ??]
set bcnt [expr {[llength $buckets] + 2}]
set bcur 1
$o_cons update $bcur $bcnt
$status_op update $bcur $bcnt
update
file mkdir [file join .git objects pack]
@ -708,7 +721,7 @@ method _do_clone2 {} {
-directory [file join $objdir pack] *] {
lappend tolink [file join pack $i]
}
$o_cons update [incr bcur] $bcnt
$status_op update [incr bcur] $bcnt
update
foreach i $buckets {
@ -717,10 +730,10 @@ method _do_clone2 {} {
-directory [file join $objdir $i] *] {
lappend tolink [file join $i $j]
}
$o_cons update [incr bcur] $bcnt
$status_op update [incr bcur] $bcnt
update
}
$o_cons stop
$status_op stop
if {$tolink eq {}} {
info_popup [strcat \
@ -747,6 +760,8 @@ method _do_clone2 {} {
if {!$i} return
destroy $w_body
set o_status {}
}
full {
set o_cons [console::embed \
@ -781,9 +796,9 @@ method _do_clone2 {} {
}
method _copy_files {objdir tocopy} {
$o_cons start \
set status_op [$o_status start \
[mc "Copying objects"] \
[mc "KiB"]
[mc "KiB"]]
set tot 0
set cmp 0
foreach p $tocopy {
@ -798,7 +813,7 @@ method _copy_files {objdir tocopy} {
while {![eof $f_in]} {
incr cmp [fcopy $f_in $f_cp -size 16384]
$o_cons update \
$status_op update \
[expr {$cmp / 1024}] \
[expr {$tot / 1024}]
update
@ -808,17 +823,19 @@ method _copy_files {objdir tocopy} {
close $f_cp
} err]} {
_clone_failed $this [mc "Unable to copy object: %s" $err]
$status_op stop
return 0
}
}
$status_op stop
return 1
}
method _link_files {objdir tolink} {
set total [llength $tolink]
$o_cons start \
set status_op [$o_status start \
[mc "Linking objects"] \
[mc "objects"]
[mc "objects"]]
for {set i 0} {$i < $total} {} {
set p [lindex $tolink $i]
if {[catch {
@ -827,15 +844,17 @@ method _link_files {objdir tolink} {
[file join $objdir $p]
} err]} {
_clone_failed $this [mc "Unable to hardlink object: %s" $err]
$status_op stop
return 0
}
incr i
if {$i % 5 == 0} {
$o_cons update $i $total
$status_op update $i $total
update
}
}
$status_op stop
return 1
}
@ -958,11 +977,26 @@ method _do_clone_checkout {HEAD} {
return
}
set o_cons [status_bar::two_line $w_body]
set status [status_bar::two_line $w_body]
pack $w_body -fill x -padx 10 -pady 10
$o_cons start \
# We start the status operation here.
#
# This function calls _readtree_wait as a callback.
#
# _readtree_wait in turn either calls _do_clone_submodules directly,
# or calls _postcheckout_wait as a callback which then calls
# _do_clone_submodules.
#
# _do_clone_submodules calls _do_validate_submodule_cloning.
#
# _do_validate_submodule_cloning stops the status operation.
#
# There are no other calls into this chain from other code.
set o_status_op [$status start \
[mc "Creating working directory"] \
[mc "files"]
[mc "files"]]
set readtree_err {}
set fd [git_read --stderr read-tree \
@ -976,33 +1010,9 @@ method _do_clone_checkout {HEAD} {
fileevent $fd readable [cb _readtree_wait $fd]
}
method _do_validate_submodule_cloning {ok} {
if {$ok} {
$o_cons done $ok
set done 1
} else {
_clone_failed $this [mc "Cannot clone submodules."]
}
}
method _do_clone_submodules {} {
if {$recursive eq {true}} {
destroy $w_body
set o_cons [console::embed \
$w_body \
[mc "Cloning submodules"]]
pack $w_body -fill both -expand 1 -padx 10
$o_cons exec \
[list git submodule update --init --recursive] \
[cb _do_validate_submodule_cloning]
} else {
set done 1
}
}
method _readtree_wait {fd} {
set buf [read $fd]
$o_cons update_meter $buf
$o_status_op update_meter $buf
append readtree_err $buf
fconfigure $fd -blocking 1
@ -1050,6 +1060,34 @@ method _postcheckout_wait {fd_ph} {
fconfigure $fd_ph -blocking 0
}
method _do_clone_submodules {} {
if {$recursive eq {true}} {
$o_status_op stop
set o_status_op {}
destroy $w_body
set o_cons [console::embed \
$w_body \
[mc "Cloning submodules"]]
pack $w_body -fill both -expand 1 -padx 10
$o_cons exec \
[list git submodule update --init --recursive] \
[cb _do_validate_submodule_cloning]
} else {
set done 1
}
}
method _do_validate_submodule_cloning {ok} {
if {$ok} {
$o_cons done $ok
set done 1
} else {
_clone_failed $this [mc "Cannot clone submodules."]
}
}
######################################################################
##
## Open Existing Repository

160
git-gui/lib/chord.tcl Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -741,7 +741,7 @@ sub evaluate_gitweb_config {
$GITWEB_CONFIG_SYSTEM = "" if ($GITWEB_CONFIG_SYSTEM eq $GITWEB_CONFIG_COMMON);
# Common system-wide settings for convenience.
# Those settings can be ovverriden by GITWEB_CONFIG or GITWEB_CONFIG_SYSTEM.
# Those settings can be overridden by GITWEB_CONFIG or GITWEB_CONFIG_SYSTEM.
read_config_file($GITWEB_CONFIG_COMMON);
# Use first config file that exists. This means use the per-instance
@ -5285,7 +5285,7 @@ sub format_ctx_rem_add_lines {
# + c
# + d
#
# Otherwise the highlightling would be confusing.
# Otherwise the highlighting would be confusing.
if ($is_combined) {
for (my $i = 0; $i < @$add; $i++) {
my $prefix_rem = substr($rem->[$i], 0, $num_parents);

17
graph.c
View File

@ -1063,7 +1063,7 @@ static void graph_output_post_merge_line(struct git_graph *graph, struct graph_l
int i, j;
struct commit_list *first_parent = first_interesting_parent(graph);
int seen_parent = 0;
struct column *parent_col = NULL;
/*
* Output the post-merge row
@ -1117,12 +1117,17 @@ static void graph_output_post_merge_line(struct git_graph *graph, struct graph_l
graph_line_addch(line, ' ');
} else {
graph_line_write_column(line, col, '|');
if (graph->merge_layout != 0 || i != graph->commit_index - 1)
graph_line_addch(line, seen_parent ? '_' : ' ');
if (graph->merge_layout != 0 || i != graph->commit_index - 1) {
if (parent_col)
graph_line_write_column(
line, parent_col, '_');
else
graph_line_addch(line, ' ');
}
}
if (col_commit == first_parent->item)
seen_parent = 1;
parent_col = col;
}
/*
@ -1219,13 +1224,9 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct graph_l
*
* The space just to the left of this
* branch should always be empty.
*
* The branch to the left of that space
* should be our eventual target.
*/
assert(graph->mapping[i - 1] > target);
assert(graph->mapping[i - 2] < 0);
assert(graph->mapping[i - 3] == target);
graph->mapping[i - 2] = target;
/*
* Mark this branch as the horizontal edge to

View File

@ -224,17 +224,6 @@ static struct commit *make_virtual_commit(struct repository *repo,
return commit;
}
/*
* Since we use get_tree_entry(), which does not put the read object into
* the object pool, we cannot rely on a == b.
*/
static int oid_eq(const struct object_id *a, const struct object_id *b)
{
if (!a && !b)
return 2;
return a && b && oideq(a, b);
}
enum rename_type {
RENAME_NORMAL = 0,
RENAME_VIA_DIR,
@ -805,7 +794,7 @@ static int was_tracked_and_matches(struct merge_options *opt, const char *path,
/* See if the file we were tracking before matches */
ce = opt->priv->orig_index.cache[pos];
return (oid_eq(&ce->oid, &blob->oid) && ce->ce_mode == blob->mode);
return (oideq(&ce->oid, &blob->oid) && ce->ce_mode == blob->mode);
}
/*
@ -1317,7 +1306,7 @@ static int merge_mode_and_contents(struct merge_options *opt,
oidcpy(&result->blob.oid, &b->oid);
}
} else {
if (!oid_eq(&a->oid, &o->oid) && !oid_eq(&b->oid, &o->oid))
if (!oideq(&a->oid, &o->oid) && !oideq(&b->oid, &o->oid))
result->merge = 1;
/*
@ -1333,9 +1322,9 @@ static int merge_mode_and_contents(struct merge_options *opt,
}
}
if (oid_eq(&a->oid, &b->oid) || oid_eq(&a->oid, &o->oid))
if (oideq(&a->oid, &b->oid) || oideq(&a->oid, &o->oid))
oidcpy(&result->blob.oid, &b->oid);
else if (oid_eq(&b->oid, &o->oid))
else if (oideq(&b->oid, &o->oid))
oidcpy(&result->blob.oid, &a->oid);
else if (S_ISREG(a->mode)) {
mmbuffer_t result_buf;
@ -1368,7 +1357,7 @@ static int merge_mode_and_contents(struct merge_options *opt,
switch (opt->recursive_variant) {
case MERGE_VARIANT_NORMAL:
oidcpy(&result->blob.oid, &a->oid);
if (!oid_eq(&a->oid, &b->oid))
if (!oideq(&a->oid, &b->oid))
result->clean = 0;
break;
case MERGE_VARIANT_OURS:
@ -2836,15 +2825,15 @@ static int process_renames(struct merge_options *opt,
dst_other.mode = ren1->dst_entry->stages[other_stage].mode;
try_merge = 0;
if (oid_eq(&src_other.oid, &null_oid) &&
if (oideq(&src_other.oid, &null_oid) &&
ren1->dir_rename_original_type == 'A') {
setup_rename_conflict_info(RENAME_VIA_DIR,
opt, ren1, NULL);
} else if (oid_eq(&src_other.oid, &null_oid)) {
} else if (oideq(&src_other.oid, &null_oid)) {
setup_rename_conflict_info(RENAME_DELETE,
opt, ren1, NULL);
} else if ((dst_other.mode == ren1->pair->two->mode) &&
oid_eq(&dst_other.oid, &ren1->pair->two->oid)) {
oideq(&dst_other.oid, &ren1->pair->two->oid)) {
/*
* Added file on the other side identical to
* the file being renamed: clean merge.
@ -2859,7 +2848,7 @@ static int process_renames(struct merge_options *opt,
1, /* update_cache */
0 /* update_wd */))
clean_merge = -1;
} else if (!oid_eq(&dst_other.oid, &null_oid)) {
} else if (!oideq(&dst_other.oid, &null_oid)) {
/*
* Probably not a clean merge, but it's
* premature to set clean_merge to 0 here,
@ -3037,7 +3026,7 @@ static int blob_unchanged(struct merge_options *opt,
if (a->mode != o->mode)
return 0;
if (oid_eq(&o->oid, &a->oid))
if (oideq(&o->oid, &a->oid))
return 1;
if (!renormalize)
return 0;
@ -3478,7 +3467,7 @@ static int merge_trees_internal(struct merge_options *opt,
opt->subtree_shift);
}
if (oid_eq(&merge_base->object.oid, &merge->object.oid)) {
if (oideq(&merge_base->object.oid, &merge->object.oid)) {
output(opt, 0, _("Already up to date!"));
*result = head;
return 1;

View File

@ -510,7 +510,6 @@ static int open_packed_git_1(struct packed_git *p)
struct pack_header hdr;
unsigned char hash[GIT_MAX_RAWSZ];
unsigned char *idx_hash;
long fd_flag;
ssize_t read_result;
const unsigned hashsz = the_hash_algo->rawsz;
@ -554,16 +553,6 @@ static int open_packed_git_1(struct packed_git *p)
} else if (p->pack_size != st.st_size)
return error("packfile %s size changed", p->pack_name);
/* We leave these file descriptors open with sliding mmap;
* there is no point keeping them open across exec(), though.
*/
fd_flag = fcntl(p->pack_fd, F_GETFD, 0);
if (fd_flag < 0)
return error("cannot determine file descriptor flags");
fd_flag |= FD_CLOEXEC;
if (fcntl(p->pack_fd, F_SETFD, fd_flag) == -1)
return error("cannot set FD_CLOEXEC");
/* Verify we recognize this pack file format. */
read_result = read_in_full(p->pack_fd, &hdr, sizeof(hdr));
if (read_result < 0)
@ -587,9 +576,8 @@ static int open_packed_git_1(struct packed_git *p)
" while index indicates %"PRIu32" objects",
p->pack_name, ntohl(hdr.hdr_entries),
p->num_objects);
if (lseek(p->pack_fd, p->pack_size - hashsz, SEEK_SET) == -1)
return error("end of packfile %s is unavailable", p->pack_name);
read_result = read_in_full(p->pack_fd, hash, hashsz);
read_result = pread_in_full(p->pack_fd, hash, hashsz,
p->pack_size - hashsz);
if (read_result < 0)
return error_errno("error reading from %s", p->pack_name);
if (read_result != hashsz)

View File

@ -67,3 +67,8 @@ Leader: Jiang Xin <worldhello.net AT gmail.com>
Members: Ray Chen <oldsharp AT gmail.com>
依云 <lilydjwg AT gmail.com>
Fangyi Zhou <me AT fangyi.io>
Language: zh_TW (Traditional Chinese)
Respository: https://github.com/l10n-tw/git-po
Leader: Yi-Jyun Pan <pan93412 AT gmail.com>
Members: Franklin Weng <franklin AT goodhorse.idv.tw>

5258
po/bg.po

File diff suppressed because it is too large Load Diff

8131
po/ca.po

File diff suppressed because it is too large Load Diff

5130
po/de.po

File diff suppressed because it is too large Load Diff

5120
po/es.po

File diff suppressed because it is too large Load Diff

5071
po/fr.po

File diff suppressed because it is too large Load Diff

5025
po/git.pot

File diff suppressed because it is too large Load Diff

5131
po/it.po

File diff suppressed because it is too large Load Diff

5107
po/sv.po

File diff suppressed because it is too large Load Diff

5112
po/vi.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

24000
po/zh_TW.po Normal file

File diff suppressed because it is too large Load Diff

View File

@ -959,7 +959,7 @@ static int verify_dotfile(const char *rest, unsigned mode)
int verify_path(const char *path, unsigned mode)
{
char c;
char c = 0;
if (has_dos_drive_prefix(path))
return 0;
@ -974,6 +974,7 @@ int verify_path(const char *path, unsigned mode)
if (is_dir_sep(c)) {
inside:
if (protect_hfs) {
if (is_hfs_dotgit(path))
return 0;
if (S_ISLNK(mode)) {
@ -982,6 +983,10 @@ inside:
}
}
if (protect_ntfs) {
#ifdef GIT_WINDOWS_NATIVE
if (c == '\\')
return 0;
#endif
if (is_ntfs_dotgit(path))
return 0;
if (S_ISLNK(mode)) {

View File

@ -147,8 +147,6 @@ static GIT_PATH_FUNC(rebase_path_refs_to_delete, "rebase-merge/refs-to-delete")
* command-line.
*/
static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, "rebase-merge/gpg_sign_opt")
static GIT_PATH_FUNC(rebase_path_cdate_is_adate, "rebase-merge/cdate_is_adate")
static GIT_PATH_FUNC(rebase_path_ignore_date, "rebase-merge/ignore_date")
static GIT_PATH_FUNC(rebase_path_orig_head, "rebase-merge/orig-head")
static GIT_PATH_FUNC(rebase_path_verbose, "rebase-merge/verbose")
static GIT_PATH_FUNC(rebase_path_quiet, "rebase-merge/quiet")
@ -825,19 +823,9 @@ int read_author_script(const char *path, char **name, char **email, char **date,
error(_("missing 'GIT_AUTHOR_DATE'"));
if (date_i < 0 || email_i < 0 || date_i < 0 || err)
goto finish;
if (name)
*name = kv.items[name_i].util;
else
free(kv.items[name_i].util);
if (email)
*email = kv.items[email_i].util;
else
free(kv.items[email_i].util);
if (date)
*date = kv.items[date_i].util;
else
free(kv.items[date_i].util);
*name = kv.items[name_i].util;
*email = kv.items[email_i].util;
*date = kv.items[date_i].util;
retval = 0;
finish:
string_list_clear(&kv, !!retval);
@ -880,47 +868,6 @@ static char *get_author(const char *message)
return NULL;
}
/* Returns a "date" string that needs to be free()'d by the caller */
static char *read_author_date_or_null(void)
{
char *date;
if (read_author_script(rebase_path_author_script(),
NULL, NULL, &date, 0))
return NULL;
return date;
}
/* Construct a free()able author string with current time as the author date */
static char *ignore_author_date(const char *author)
{
int len = strlen(author);
struct ident_split ident;
struct strbuf new_author = STRBUF_INIT;
if (split_ident_line(&ident, author, len) < 0) {
error(_("malformed ident line"));
return NULL;
}
len = ident.mail_end - ident.name_begin + 1;
strbuf_addf(&new_author, "%.*s ", len, ident.name_begin);
datestamp(&new_author);
return strbuf_detach(&new_author, NULL);
}
static void push_dates(struct child_process *child, int change_committer_date)
{
time_t now = time(NULL);
struct strbuf date = STRBUF_INIT;
strbuf_addf(&date, "@%"PRIuMAX, (uintmax_t)now);
argv_array_pushf(&child->env_array, "GIT_AUTHOR_DATE=%s", date.buf);
if (change_committer_date)
argv_array_pushf(&child->env_array, "GIT_COMMITTER_DATE=%s", date.buf);
strbuf_release(&date);
}
static const char staged_changes_advice[] =
N_("you have staged changes in your working tree\n"
"If these changes are meant to be squashed into the previous commit, run:\n"
@ -980,25 +927,6 @@ static int run_git_commit(struct repository *r,
cmd.git_cmd = 1;
if (opts->committer_date_is_author_date) {
int res = -1;
struct strbuf datebuf = STRBUF_INIT;
char *date = read_author_date_or_null();
if (!date)
return -1;
strbuf_addf(&datebuf, "@%s", date);
res = setenv("GIT_COMMITTER_DATE",
opts->ignore_date ? "" : datebuf.buf, 1);
strbuf_release(&datebuf);
free(date);
if (res)
return -1;
}
if (is_rebase_i(opts) && read_env_script(&cmd.env_array)) {
const char *gpg_opt = gpg_sign_opt_quoted(opts);
@ -1014,8 +942,6 @@ static int run_git_commit(struct repository *r,
argv_array_push(&cmd.args, "--amend");
if (opts->gpg_sign)
argv_array_pushf(&cmd.args, "-S%s", opts->gpg_sign);
if (opts->ignore_date)
push_dates(&cmd, opts->committer_date_is_author_date);
if (defmsg)
argv_array_pushl(&cmd.args, "-F", defmsg, NULL);
else if (!(flags & EDIT_MSG))
@ -1384,13 +1310,14 @@ static int try_to_commit(struct repository *r,
struct commit_extra_header *extra = NULL;
struct strbuf err = STRBUF_INIT;
struct strbuf commit_msg = STRBUF_INIT;
char *author_to_free = NULL;
char *amend_author = NULL;
const char *hook_commit = NULL;
enum commit_msg_cleanup_mode cleanup;
int res = 0;
if (parse_head(r, &current_head))
return -1;
if (flags & AMEND_MSG) {
const char *exclude_gpgsig[] = { "gpgsig", NULL };
const char *out_enc = get_commit_output_encoding();
@ -1405,7 +1332,7 @@ static int try_to_commit(struct repository *r,
strbuf_addstr(msg, orig_message);
hook_commit = "HEAD";
}
author = author_to_free = get_author(message);
author = amend_author = get_author(message);
unuse_commit_buffer(current_head, message);
if (!author) {
res = error(_("unable to parse commit author"));
@ -1418,31 +1345,6 @@ static int try_to_commit(struct repository *r,
commit_list_insert(current_head, &parents);
}
if (opts->committer_date_is_author_date) {
int len = strlen(author);
struct ident_split ident;
struct strbuf date = STRBUF_INIT;
if (split_ident_line(&ident, author, len) < 0) {
res = error(_("malformed ident line"));
goto out;
}
if (!ident.date_begin) {
res = error(_("corrupted author without date information"));
goto out;
}
strbuf_addf(&date, "@%.*s %.*s",
(int)(ident.date_end - ident.date_begin), ident.date_begin,
(int)(ident.tz_end - ident.tz_begin), ident.tz_begin);
res = setenv("GIT_COMMITTER_DATE",
opts->ignore_date ? "" : date.buf, 1);
strbuf_release(&date);
if (res)
goto out;
}
if (write_index_as_tree(&tree, r->index, r->index_file, 0, NULL)) {
res = error(_("git write-tree failed to write a tree"));
goto out;
@ -1502,15 +1404,6 @@ static int try_to_commit(struct repository *r,
reset_ident_date();
if (opts->ignore_date) {
author = ignore_author_date(author);
if (!author) {
res = -1;
goto out;
}
free(author_to_free);
author_to_free = (char *)author;
}
if (commit_tree_extended(msg->buf, msg->len, &tree, parents,
oid, author, opts->gpg_sign, extra)) {
res = error(_("failed to write commit object"));
@ -1531,7 +1424,7 @@ out:
free_commit_extra_headers(extra);
strbuf_release(&err);
strbuf_release(&commit_msg);
free(author_to_free);
free(amend_author);
return res;
}
@ -2599,16 +2492,6 @@ static int read_populate_opts(struct replay_opts *opts)
opts->signoff = 1;
}
if (file_exists(rebase_path_cdate_is_adate())) {
opts->allow_ff = 0;
opts->committer_date_is_author_date = 1;
}
if (file_exists(rebase_path_ignore_date())) {
opts->allow_ff = 0;
opts->ignore_date = 1;
}
if (file_exists(rebase_path_reschedule_failed_exec()))
opts->reschedule_failed_exec = 1;
@ -2691,10 +2574,6 @@ int write_basic_state(struct replay_opts *opts, const char *head_name,
write_file(rebase_path_gpg_sign_opt(), "-S%s\n", opts->gpg_sign);
if (opts->signoff)
write_file(rebase_path_signoff(), "--signoff\n");
if (opts->committer_date_is_author_date)
write_file(rebase_path_cdate_is_adate(), "%s", "");
if (opts->ignore_date)
write_file(rebase_path_ignore_date(), "%s", "");
if (opts->reschedule_failed_exec)
write_file(rebase_path_reschedule_failed_exec(), "%s", "");
@ -3635,8 +3514,6 @@ static int do_merge(struct repository *r,
argv_array_push(&cmd.args, git_path_merge_msg(r));
if (opts->gpg_sign)
argv_array_push(&cmd.args, opts->gpg_sign);
if (opts->ignore_date)
push_dates(&cmd, opts->committer_date_is_author_date);
/* Add the tips to be merged */
for (j = to_merge; j; j = j->next)
@ -3909,9 +3786,7 @@ static int pick_commits(struct repository *r,
setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
if (opts->allow_ff)
assert(!(opts->signoff || opts->no_commit ||
opts->record_origin || opts->edit ||
opts->committer_date_is_author_date ||
opts->ignore_date));
opts->record_origin || opts->edit));
if (read_and_refresh_cache(r, opts))
return -1;

View File

@ -43,8 +43,6 @@ struct replay_opts {
int verbose;
int quiet;
int reschedule_failed_exec;
int committer_date_is_author_date;
int ignore_date;
int mainline;

View File

@ -246,6 +246,17 @@ test_expect_success 'cone mode: init and set' '
test_cmp expect dir
'
test_expect_success 'cone mode: list' '
cat >expect <<-EOF &&
folder1
folder2
EOF
git -C repo sparse-checkout set --stdin <expect &&
git -C repo sparse-checkout list >actual 2>err &&
test_must_be_empty err &&
test_cmp expect actual
'
test_expect_success 'cone mode: set with nested folders' '
git -C repo sparse-checkout set deep deep/deeper1/deepest 2>err &&
test_line_count = 0 err &&
@ -329,4 +340,32 @@ test_expect_success 'cone mode: set with core.ignoreCase=true' '
test_cmp expect dir
'
test_expect_success 'interaction with submodules' '
git clone repo super &&
(
cd super &&
mkdir modules &&
git submodule add ../repo modules/child &&
git add . &&
git commit -m "add submodule" &&
git sparse-checkout init --cone &&
git sparse-checkout set folder1
) &&
list_files super >dir &&
cat >expect <<-\EOF &&
a
folder1
modules
EOF
test_cmp expect dir &&
list_files super/modules/child >dir &&
cat >expect <<-\EOF &&
a
deep
folder1
folder2
EOF
test_cmp expect dir
'
test_done

View File

@ -61,6 +61,8 @@ test_rebase_am_only () {
}
test_rebase_am_only --whitespace=fix
test_rebase_am_only --ignore-whitespace
test_rebase_am_only --committer-date-is-author-date
test_rebase_am_only -C4
test_expect_success REBASE_P '--preserve-merges incompatible with --signoff' '

View File

@ -1,131 +0,0 @@
#!/bin/sh
#
# Copyright (c) 2019 Rohit Ashiwal
#
test_description='tests to ensure compatibility between am and interactive backends'
. ./test-lib.sh
GIT_AUTHOR_DATE="1999-04-02T08:03:20+05:30"
export GIT_AUTHOR_DATE
# This is a special case in which both am and interactive backends
# provide the same output. It was done intentionally because
# both the backends fall short of optimal behaviour.
test_expect_success 'setup' '
git checkout -b topic &&
q_to_tab >file <<-\EOF &&
line 1
Qline 2
line 3
EOF
git add file &&
git commit -m "add file" &&
cat >file <<-\EOF &&
line 1
new line 2
line 3
EOF
git commit -am "update file" &&
git tag side &&
test_commit commit1 foo foo1 &&
test_commit commit2 foo foo2 &&
test_commit commit3 foo foo3 &&
git checkout --orphan master &&
git rm --cached foo &&
rm foo &&
sed -e "s/^|//" >file <<-\EOF &&
|line 1
| line 2
|line 3
EOF
git add file &&
git commit -m "add file" &&
git tag main
'
test_expect_success '--ignore-whitespace works with am backend' '
cat >expect <<-\EOF &&
line 1
new line 2
line 3
EOF
test_must_fail git rebase main side &&
git rebase --abort &&
git rebase --ignore-whitespace main side &&
test_cmp expect file
'
test_expect_success '--ignore-whitespace works with interactive backend' '
cat >expect <<-\EOF &&
line 1
new line 2
line 3
EOF
test_must_fail git rebase --merge main side &&
git rebase --abort &&
git rebase --merge --ignore-whitespace main side &&
test_cmp expect file
'
test_expect_success '--committer-date-is-author-date works with am backend' '
git commit --amend &&
git rebase --committer-date-is-author-date HEAD^ &&
git show HEAD --pretty="format:%ai" >authortime &&
git show HEAD --pretty="format:%ci" >committertime &&
test_cmp authortime committertime
'
test_expect_success '--committer-date-is-author-date works with interactive backend' '
git commit --amend &&
git rebase -i --committer-date-is-author-date HEAD^ &&
git show HEAD --pretty="format:%ai" >authortime &&
git show HEAD --pretty="format:%ci" >committertime &&
test_cmp authortime committertime
'
test_expect_success '--committer-date-is-author-date works with rebase -r' '
git checkout side &&
git merge --no-ff commit3 &&
git rebase -r --root --committer-date-is-author-date &&
git rev-list HEAD >rev_list &&
while read HASH
do
git show $HASH --pretty="format:%ai" >authortime
git show $HASH --pretty="format:%ci" >committertime
test_cmp authortime committertime
done <rev_list
'
# Checking for +0000 in author time is enough since default
# timezone is UTC, but the timezone used while committing
# sets to +0530.
test_expect_success '--ignore-date works with am backend' '
git commit --amend --date="$GIT_AUTHOR_DATE" &&
git rebase --ignore-date HEAD^ &&
git show HEAD --pretty="format:%ai" >authortime &&
grep "+0000" authortime
'
test_expect_success '--ignore-date works with interactive backend' '
git commit --amend --date="$GIT_AUTHOR_DATE" &&
git rebase --ignore-date -i HEAD^ &&
git show HEAD --pretty="format:%ai" >authortime &&
grep "+0000" authortime
'
test_expect_success '--ignore-date works with rebase -r' '
git checkout side &&
git merge --no-ff commit3 &&
git rebase -r --root --ignore-date &&
git rev-list HEAD >rev_list &&
while read HASH
do
git show $HASH --pretty="format:%ai" >authortime
grep "+0000" authortime
done <rev_list
'
test_done

View File

@ -240,4 +240,75 @@ test_expect_success 'log --graph with octopus merge with column joining its penu
EOF
'
test_expect_success 'log --graph with multiple tips' '
git checkout --orphan 6_1 &&
test_commit 6_A &&
git branch 6_2 &&
git branch 6_4 &&
test_commit 6_B &&
git branch 6_3 &&
test_commit 6_C &&
git checkout 6_2 && test_commit 6_D &&
git checkout 6_3 && test_commit 6_E &&
git checkout -b 6_5 6_1 &&
git merge --no-ff 6_2 -m 6_F &&
git checkout 6_4 && test_commit 6_G &&
git checkout 6_3 &&
git merge --no-ff 6_4 -m 6_H &&
git checkout 6_1 &&
git merge --no-ff 6_2 -m 6_I &&
check_graph 6_1 6_3 6_5 <<-\EOF
* 6_I
|\
| | * 6_H
| | |\
| | | * 6_G
| | * | 6_E
| | | | * 6_F
| |_|_|/|
|/| | |/
| | |/|
| |/| |
| * | | 6_D
| | |/
| |/|
* | | 6_C
| |/
|/|
* | 6_B
|/
* 6_A
EOF
'
test_expect_success 'log --graph with multiple tips and colors' '
test_config log.graphColors red,green,yellow,blue,magenta,cyan &&
cat >expect.colors <<-\EOF &&
* 6_I
<RED>|<RESET><GREEN>\<RESET>
<RED>|<RESET> <GREEN>|<RESET> * 6_H
<RED>|<RESET> <GREEN>|<RESET> <YELLOW>|<RESET><BLUE>\<RESET>
<RED>|<RESET> <GREEN>|<RESET> <YELLOW>|<RESET> * 6_G
<RED>|<RESET> <GREEN>|<RESET> <YELLOW>|<RESET> <BLUE>|<RESET> * 6_F
<RED>|<RESET> <GREEN>|<RESET><RED>_<RESET><YELLOW>|<RESET><RED>_<RESET><BLUE>|<RESET><RED>/<RESET><GREEN>|<RESET>
<RED>|<RESET><RED>/<RESET><GREEN>|<RESET> <YELLOW>|<RESET> <BLUE>|<RESET><GREEN>/<RESET>
<RED>|<RESET> <GREEN>|<RESET> <YELLOW>|<RESET><GREEN>/<RESET><BLUE>|<RESET>
<RED>|<RESET> <GREEN>|<RESET><GREEN>/<RESET><YELLOW>|<RESET> <BLUE>|<RESET>
<RED>|<RESET> <GREEN>|<RESET> * <BLUE>|<RESET> 6_E
<RED>|<RESET> * <CYAN>|<RESET> <BLUE>|<RESET> 6_D
<RED>|<RESET> <BLUE>|<RESET> <CYAN>|<RESET><BLUE>/<RESET>
<RED>|<RESET> <BLUE>|<RESET><BLUE>/<RESET><CYAN>|<RESET>
* <BLUE>|<RESET> <CYAN>|<RESET> 6_C
<CYAN>|<RESET> <BLUE>|<RESET><CYAN>/<RESET>
<CYAN>|<RESET><CYAN>/<RESET><BLUE>|<RESET>
* <BLUE>|<RESET> 6_B
<BLUE>|<RESET><BLUE>/<RESET>
* 6_A
EOF
git log --color=always --graph --date-order --pretty=tformat:%s 6_1 6_3 6_5 >actual.colors.raw &&
test_decode_color <actual.colors.raw | sed "s/ *\$//" >actual.colors &&
test_cmp expect.colors actual.colors
'
test_done

View File

@ -207,6 +207,9 @@ test_expect_success MINGW 'prevent git~1 squatting on Windows' '
git hash-object -w --stdin)" &&
rev="$(git rev-parse --verify HEAD)" &&
hash="$(echo x | git hash-object -w --stdin)" &&
test_must_fail git update-index --add \
--cacheinfo 160000,$rev,d\\a 2>err &&
test_i18ngrep "Invalid path" err &&
git -c core.protectNTFS=false update-index --add \
--cacheinfo 100644,$modules,.gitmodules \
--cacheinfo 160000,$rev,c \
@ -214,9 +217,7 @@ test_expect_success MINGW 'prevent git~1 squatting on Windows' '
--cacheinfo 100644,$hash,d./a/x \
--cacheinfo 100644,$hash,d./a/..git &&
test_tick &&
git -c core.protectNTFS=false commit -m "module" &&
test_must_fail git show HEAD: 2>err &&
test_i18ngrep backslash err
git -c core.protectNTFS=false commit -m "module"
) &&
test_must_fail git -c core.protectNTFS=false \
clone --recurse-submodules squatting squatting-clone 2>err &&

View File

@ -43,12 +43,6 @@ static int decode_tree_entry(struct tree_desc *desc, const char *buf, unsigned l
strbuf_addstr(err, _("empty filename in tree entry"));
return -1;
}
#ifdef GIT_WINDOWS_NATIVE
if (protect_ntfs && strchr(path, '\\')) {
strbuf_addf(err, _("filename in tree entry contains backslash: '%s'"), path);
return -1;
}
#endif
len = strlen(path) + 1;
/* Initialize the descriptor entry */