mirror of
https://github.com/git/git.git
synced 2026-03-13 10:23:30 +01:00
Merge branch 'master' of git://repo.or.cz/alt-git
This commit is contained in:
@@ -16,6 +16,9 @@ Fixes since v1.6.0.3
|
||||
* 'git push --mirror' tried and failed to push the stash; there is no
|
||||
point in sending it to begin with.
|
||||
|
||||
* 'git push' did not update the remote tracking reference if the corresponding
|
||||
ref on the remote end happened to be already up to date.
|
||||
|
||||
* 'git pull $there $branch:$current_branch' did not work when you were on
|
||||
a branch yet to be born.
|
||||
|
||||
@@ -29,12 +32,8 @@ Fixes since v1.6.0.3
|
||||
|
||||
* 'git svn' used deprecated 'git-foo' form of subcommand invocaition.
|
||||
|
||||
* 'git update-ref -d' to remove a reference did not honor --no-deref option.
|
||||
|
||||
* Plugged small memleaks here and there.
|
||||
|
||||
* Also contains many documentation updates.
|
||||
|
||||
--
|
||||
exec >/var/tmp/1
|
||||
O=v1.6.0.3-34-gf6276b7
|
||||
echo O=$(git describe maint)
|
||||
git shortlog --no-merges $O..maint
|
||||
|
||||
21
Documentation/RelNotes-1.6.0.5.txt
Normal file
21
Documentation/RelNotes-1.6.0.5.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
GIT v1.6.0.5 Release Notes
|
||||
==========================
|
||||
|
||||
Fixes since v1.6.0.4
|
||||
--------------------
|
||||
|
||||
* 'git checkout' used to crash when your HEAD was pointing at a deleted
|
||||
branch.
|
||||
|
||||
* 'git checkout' from an un-checked-out state did not allow switching out
|
||||
of the current branch.
|
||||
|
||||
* 'git pack-objects' did not make its best effort to honor --max-pack-size
|
||||
option when a single first object already busted the given limit and
|
||||
placed many objects in a single pack.
|
||||
|
||||
* 'make check' cannot be run without sparse; people may have meant to say
|
||||
'make test' instead, so suggest that.
|
||||
|
||||
* Many unsafe call to sprintf() style varargs functions are corrected.
|
||||
|
||||
@@ -27,6 +27,8 @@ on.
|
||||
|
||||
* Sample pre-auto-gc script has OS X support.
|
||||
|
||||
* Makefile has support for (ancient) FreeBSD 4.9.
|
||||
|
||||
(performance)
|
||||
|
||||
* The underlying diff machinery to produce textual output has been
|
||||
@@ -53,6 +55,10 @@ on.
|
||||
to a non-zero value to accept the suggestion when git can uniquely
|
||||
guess.
|
||||
|
||||
* The packfile machinery hopefully is more robust when dealilng with
|
||||
corrupt packs if redundant objects involved in the corruption are
|
||||
available elsehwere.
|
||||
|
||||
* "git add -N path..." adds the named paths as an empty blob, so that
|
||||
subsequent "git diff" will show a diff as if they are creation events.
|
||||
|
||||
@@ -110,8 +116,18 @@ on.
|
||||
* "git diff" learned --dirstat-by-file to count changed files, not number
|
||||
of lines, when summarizing the global picture.
|
||||
|
||||
* "git diff" learned "textconv" filters --- a binary or hard-to-read
|
||||
contents can be munged into human readable form and the difference
|
||||
between the results of the conversion can be viewed (obviously this
|
||||
cannot produce a patch that can be applied, so this is disabled in
|
||||
format-patch among other things).
|
||||
|
||||
* "git diff" hunk header pattern for ObjC has been added.
|
||||
|
||||
* "--cached" option to "git diff has an easier to remember synonym "--staged",
|
||||
to ask "what is the difference between the given commit and the
|
||||
contents staged in the index?"
|
||||
|
||||
* a "textconv" filter that makes binary files textual form for human
|
||||
consumption can be specified as an attribute for paths; "git diff"
|
||||
learnt to make use of it.
|
||||
@@ -138,6 +154,12 @@ on.
|
||||
* "git log" learned --simplify-merges, a milder variant of --full-history;
|
||||
"gitk --simplify-merges" is easier to view than with --full-history.
|
||||
|
||||
* "git log" learned "--source" to show what ref each commit was reached
|
||||
from.
|
||||
|
||||
* "git log" also learned "--simplify-by-decration" to show the
|
||||
birds-eye-view of the topology of the history.
|
||||
|
||||
* "git log --pretty=format:" learned "%d" format element that inserts
|
||||
names of tags that point at the commit.
|
||||
|
||||
@@ -213,6 +235,9 @@ release, unless otherwise noted.
|
||||
|
||||
* "git filter-branch" failed to rewrite a tag name with slashes in it.
|
||||
|
||||
* "git repack" used to grab objects out of packs marked with .keep
|
||||
into a new pack (fix scheduled to be further downmerged to maint).
|
||||
|
||||
* "git push --tags --all $there" failed with generic usage message without
|
||||
telling saying these two options are incompatible.
|
||||
|
||||
@@ -220,8 +245,15 @@ release, unless otherwise noted.
|
||||
timestamp part, exposing internal implementation detail. Also these did
|
||||
not work with --fixed-strings match at all.
|
||||
|
||||
* "git tag" did not complain about incompatible combination of options
|
||||
e.g. "tag -l -d" (fix scheduled to be further downmerged to maint).
|
||||
|
||||
* Internal diff machinery had a corner case performance bug that choked on a
|
||||
large file with many repeated contents (fix scheduled to be further cherry-
|
||||
picked to maint).
|
||||
|
||||
--
|
||||
exec >/var/tmp/1
|
||||
O=v1.6.0.3-639-ga1a846a
|
||||
O=v1.6.0.4-697-g168d5bd
|
||||
echo O=$(git describe master)
|
||||
git shortlog --no-merges $O..master ^maint
|
||||
|
||||
@@ -796,6 +796,14 @@ gui.diffcontext::
|
||||
Specifies how many context lines should be used in calls to diff
|
||||
made by the linkgit:git-gui[1]. The default is "5".
|
||||
|
||||
gui.encoding::
|
||||
Specifies the default encoding to use for displaying of
|
||||
file contents in linkgit:git-gui[1] and linkgit:gitk[1].
|
||||
It can be overridden by setting the 'encoding' attribute
|
||||
for relevant files (see linkgit:gitattributes[5]).
|
||||
If this option is not set, the tools default to the
|
||||
locale encoding.
|
||||
|
||||
gui.matchtrackingbranch::
|
||||
Determines if new branches created with linkgit:git-gui[1] should
|
||||
default to tracking remote branches with matching names or
|
||||
@@ -818,6 +826,22 @@ gui.spellingdictionary::
|
||||
the linkgit:git-gui[1]. When set to "none" spell checking is turned
|
||||
off.
|
||||
|
||||
gui.fastcopyblame::
|
||||
If true, 'git gui blame' uses '-C' instead of '-C -C' for original
|
||||
location detection. It makes blame significantly faster on huge
|
||||
repositories at the expense of less thorough copy detection.
|
||||
|
||||
gui.copyblamethreshold::
|
||||
Specifies the theshold to use in 'git gui blame' original location
|
||||
detection, measured in alphanumeric characters. See the
|
||||
linkgit:git-blame[1] manual for more information on copy detection.
|
||||
|
||||
gui.blamehistoryctx::
|
||||
Specifies the radius of history context in days to show in
|
||||
linkgit:gitk[1] for the selected commit, when the `Show History
|
||||
Context` menu item is invoked from 'git gui blame'. If this
|
||||
variable is set to zero, the whole history is shown.
|
||||
|
||||
help.browser::
|
||||
Specify the browser that will be used to display help in the
|
||||
'web' format. See linkgit:git-help[1].
|
||||
@@ -1198,6 +1222,15 @@ receive.denyNonFastForwards::
|
||||
even if that push is forced. This configuration variable is
|
||||
set when initializing a shared repository.
|
||||
|
||||
receive.denyCurrentBranch::
|
||||
If set to true or "refuse", receive-pack will deny a ref update
|
||||
to the currently checked out branch of a non-bare repository.
|
||||
Such a push is potentially dangerous because it brings the HEAD
|
||||
out of sync with the index and working tree. If set to "warn",
|
||||
print a warning of such a push to stderr, but allow the push to
|
||||
proceed. If set to false or "ignore", allow such pushes with no
|
||||
message. Defaults to "warn".
|
||||
|
||||
transfer.unpackLimit::
|
||||
When `fetch.unpackLimit` or `receive.unpackLimit` are
|
||||
not set, the value of this variable is used instead.
|
||||
|
||||
@@ -26,7 +26,7 @@ on the subcommand:
|
||||
git bisect log
|
||||
git bisect run <cmd>...
|
||||
|
||||
This command uses 'git-rev-list --bisect' to help drive the
|
||||
This command uses 'git rev-list --bisect' to help drive the
|
||||
binary search process to find which change introduced a bug, given an
|
||||
old "good" commit object name and a later "bad" commit object name.
|
||||
|
||||
@@ -101,7 +101,7 @@ $ git bisect visualize
|
||||
to see the currently remaining suspects in 'gitk'. `visualize` is a bit
|
||||
too long to type and `view` is provided as a synonym.
|
||||
|
||||
If 'DISPLAY' environment variable is not set, 'git-log' is used
|
||||
If 'DISPLAY' environment variable is not set, 'git log' is used
|
||||
instead. You can even give command line options such as `-p` and
|
||||
`--stat`.
|
||||
|
||||
@@ -215,7 +215,7 @@ tweaks (e.g., s/#define DEBUG 0/#define DEBUG 1/ in a header file, or
|
||||
work around other problem this bisection is not interested in")
|
||||
applied to the revision being tested.
|
||||
|
||||
To cope with such a situation, after the inner 'git-bisect' finds the
|
||||
To cope with such a situation, after the inner 'git bisect' finds the
|
||||
next revision to test, with the "run" script, you can apply that tweak
|
||||
before compiling, run the real test, and after the test decides if the
|
||||
revision (possibly with the needed tweaks) passed the test, rewind the
|
||||
|
||||
@@ -3,7 +3,7 @@ git-check-attr(1)
|
||||
|
||||
NAME
|
||||
----
|
||||
git-check-attr - Display gitattributes information.
|
||||
git-check-attr - Display gitattributes information
|
||||
|
||||
|
||||
SYNOPSIS
|
||||
|
||||
@@ -33,6 +33,7 @@ forced by --no-index.
|
||||
commit relative to the named <commit>. Typically you
|
||||
would want comparison with the latest commit, so if you
|
||||
do not give <commit>, it defaults to HEAD.
|
||||
--staged is a synonym of --cached.
|
||||
|
||||
'git diff' [--options] <commit> [--] [<path>...]::
|
||||
|
||||
|
||||
@@ -65,9 +65,28 @@ git gui blame v0.99.8 Makefile::
|
||||
example the file is read from the object database and not
|
||||
the working directory.
|
||||
|
||||
git gui blame --line=100 Makefile::
|
||||
|
||||
Loads annotations as described above and automatically
|
||||
scrolls the view to center on line '100'.
|
||||
|
||||
git gui citool::
|
||||
|
||||
Make one commit and return to the shell when it is complete.
|
||||
This command returns a non-zero exit code if the window was
|
||||
closed in any way other than by making a commit.
|
||||
|
||||
git gui citool --amend::
|
||||
|
||||
Automatically enter the 'Amend Last Commit' mode of
|
||||
the interface.
|
||||
|
||||
git gui citool --nocommit::
|
||||
|
||||
Behave as normal citool, but instead of making a commit
|
||||
simply terminate with a zero exit code. It still checks
|
||||
that the index does not contain any unmerged entries, so
|
||||
you can use it as a GUI version of linkgit:git-mergetool[1]
|
||||
|
||||
git citool::
|
||||
|
||||
|
||||
@@ -40,6 +40,10 @@ include::diff-options.txt[]
|
||||
--decorate::
|
||||
Print out the ref names of any commits that are shown.
|
||||
|
||||
--source::
|
||||
Print out the ref name given on the command line by which each
|
||||
commit was reached.
|
||||
|
||||
--full-diff::
|
||||
Without this flag, "git log -p <path>..." shows commits that
|
||||
touch the specified paths, and diffs about the same specified
|
||||
|
||||
@@ -109,6 +109,11 @@ base-name::
|
||||
The default is unlimited, unless the config variable
|
||||
`pack.packSizeLimit` is set.
|
||||
|
||||
--honor-pack-keep::
|
||||
This flag causes an object already in a local pack that
|
||||
has a .keep file to be ignored, even if it appears in the
|
||||
standard input.
|
||||
|
||||
--incremental::
|
||||
This flag causes an object already in a pack ignored
|
||||
even if it appears in the standard input.
|
||||
@@ -116,7 +121,7 @@ base-name::
|
||||
--local::
|
||||
This flag is similar to `--incremental`; instead of
|
||||
ignoring all packed objects, it only ignores objects
|
||||
that are packed and not in the local object store
|
||||
that are packed and/or not in the local object store
|
||||
(i.e. borrowed from an alternate).
|
||||
|
||||
--non-empty::
|
||||
|
||||
@@ -11,6 +11,7 @@ SYNOPSIS
|
||||
[verse]
|
||||
'git remote' [-v | --verbose]
|
||||
'git remote add' [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>
|
||||
'git remote rename' <old> <new>
|
||||
'git remote rm' <name>
|
||||
'git remote show' [-n] <name>
|
||||
'git remote prune' [-n | --dry-run] <name>
|
||||
@@ -61,6 +62,15 @@ only makes sense in bare repositories. If a remote uses mirror
|
||||
mode, furthermore, `git push` will always behave as if `\--mirror`
|
||||
was passed.
|
||||
|
||||
'rename'::
|
||||
|
||||
Rename the remote named <old> to <new>. All remote tracking branches and
|
||||
configuration settings for the remote are updated.
|
||||
+
|
||||
In case <old> and <new> are the same, and <old> is a file under
|
||||
`$GIT_DIR/remotes` or `$GIT_DIR/branches`, the remote is converted to
|
||||
the configuration file format.
|
||||
|
||||
'rm'::
|
||||
|
||||
Remove the remote named <name>. All remote tracking branches and
|
||||
|
||||
@@ -38,12 +38,11 @@ OPTIONS
|
||||
dangling.
|
||||
|
||||
-A::
|
||||
Same as `-a`, but any unreachable objects in a previous
|
||||
pack become loose, unpacked objects, instead of being
|
||||
left in the old pack. Unreachable objects are never
|
||||
intentionally added to a pack, even when repacking.
|
||||
When used with '-d', this option
|
||||
prevents unreachable objects from being immediately
|
||||
Same as `-a`, unless '-d' is used. Then any unreachable
|
||||
objects in a previous pack become loose, unpacked objects,
|
||||
instead of being left in the old pack. Unreachable objects
|
||||
are never intentionally added to a pack, even when repacking.
|
||||
This option prevents unreachable objects from being immediately
|
||||
deleted by way of being left in the old pack and then
|
||||
removed. Instead, the loose unreachable objects
|
||||
will be pruned according to normal expiry rules
|
||||
|
||||
@@ -544,6 +544,8 @@ have each person clone that repository with 'git-clone':
|
||||
git remote add origin server:/pub/project
|
||||
git config --add remote.origin.fetch '+refs/remotes/*:refs/remotes/*'
|
||||
git fetch
|
||||
# Create a local branch from one of the branches just fetched
|
||||
git checkout -b master FETCH_HEAD
|
||||
# Initialize git-svn locally (be sure to use the same URL and -T/-b/-t options as were used on server)
|
||||
git svn init http://svn.example.com/project
|
||||
# Pull the latest changes from Subversion
|
||||
|
||||
@@ -43,9 +43,11 @@ unreleased) version of git, that is available from 'master'
|
||||
branch of the `git.git` repository.
|
||||
Documentation for older releases are available here:
|
||||
|
||||
* link:v1.6.0.2/git.html[documentation for release 1.6.0.2]
|
||||
* link:v1.6.0.4/git.html[documentation for release 1.6.0.4]
|
||||
|
||||
* release notes for
|
||||
link:RelNotes-1.6.0.4.txt[1.6.0.4],
|
||||
link:RelNotes-1.6.0.3.txt[1.6.0.3],
|
||||
link:RelNotes-1.6.0.2.txt[1.6.0.2],
|
||||
link:RelNotes-1.6.0.1.txt[1.6.0.1],
|
||||
link:RelNotes-1.6.0.txt[1.6.0].
|
||||
|
||||
@@ -216,10 +216,12 @@ Generating diff text
|
||||
`diff`
|
||||
^^^^^^
|
||||
|
||||
The attribute `diff` affects if 'git-diff' generates textual
|
||||
patch for the path or just says `Binary files differ`. It also
|
||||
can affect what line is shown on the hunk header `@@ -k,l +n,m @@`
|
||||
line.
|
||||
The attribute `diff` affects how 'git' generates diffs for particular
|
||||
files. It can tell git whether to generate a textual patch for the path
|
||||
or to treat the path as a binary file. It can also affect what line is
|
||||
shown on the hunk header `@@ -k,l +n,m @@` line, tell git to use an
|
||||
external command to generate the diff, or ask git to convert binary
|
||||
files to a text format before generating the diff.
|
||||
|
||||
Set::
|
||||
|
||||
@@ -230,7 +232,8 @@ Set::
|
||||
Unset::
|
||||
|
||||
A path to which the `diff` attribute is unset will
|
||||
generate `Binary files differ`.
|
||||
generate `Binary files differ` (or a binary patch, if
|
||||
binary patches are enabled).
|
||||
|
||||
Unspecified::
|
||||
|
||||
@@ -241,21 +244,21 @@ Unspecified::
|
||||
|
||||
String::
|
||||
|
||||
Diff is shown using the specified custom diff driver.
|
||||
The driver program is given its input using the same
|
||||
calling convention as used for GIT_EXTERNAL_DIFF
|
||||
program. This name is also used for custom hunk header
|
||||
selection.
|
||||
Diff is shown using the specified diff driver. Each driver may
|
||||
specify one or more options, as described in the following
|
||||
section. The options for the diff driver "foo" are defined
|
||||
by the configuration variables in the "diff.foo" section of the
|
||||
git config file.
|
||||
|
||||
|
||||
Defining a custom diff driver
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Defining an external diff driver
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The definition of a diff driver is done in `gitconfig`, not
|
||||
`gitattributes` file, so strictly speaking this manual page is a
|
||||
wrong place to talk about it. However...
|
||||
|
||||
To define a custom diff driver `jcdiff`, add a section to your
|
||||
To define an external diff driver `jcdiff`, add a section to your
|
||||
`$GIT_DIR/config` file (or `$HOME/.gitconfig` file) like this:
|
||||
|
||||
----------------------------------------------------------------
|
||||
@@ -331,6 +334,43 @@ patterns are available:
|
||||
- `tex` suitable for source code for LaTeX documents.
|
||||
|
||||
|
||||
Performing text diffs of binary files
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Sometimes it is desirable to see the diff of a text-converted
|
||||
version of some binary files. For example, a word processor
|
||||
document can be converted to an ASCII text representation, and
|
||||
the diff of the text shown. Even though this conversion loses
|
||||
some information, the resulting diff is useful for human
|
||||
viewing (but cannot be applied directly).
|
||||
|
||||
The `textconv` config option is used to define a program for
|
||||
performing such a conversion. The program should take a single
|
||||
argument, the name of a file to convert, and produce the
|
||||
resulting text on stdout.
|
||||
|
||||
For example, to show the diff of the exif information of a
|
||||
file instead of the binary information (assuming you have the
|
||||
exif tool installed):
|
||||
|
||||
------------------------
|
||||
[diff "jpg"]
|
||||
textconv = exif
|
||||
------------------------
|
||||
|
||||
NOTE: The text conversion is generally a one-way conversion;
|
||||
in this example, we lose the actual image contents and focus
|
||||
just on the text data. This means that diffs generated by
|
||||
textconv are _not_ suitable for applying. For this reason,
|
||||
only `git diff` and the `git log` family of commands (i.e.,
|
||||
log, whatchanged, show) will perform text conversion. `git
|
||||
format-patch` will never generate this output. If you want to
|
||||
send somebody a text-converted diff of a binary file (e.g.,
|
||||
because it quickly conveys the changes you have made), you
|
||||
should generate it separately and send it as a comment _in
|
||||
addition to_ the usual binary diff that you might send.
|
||||
|
||||
|
||||
Performing a three-way merge
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -495,6 +535,23 @@ in the file. E.g. the string `$Format:%H$` will be replaced by the
|
||||
commit hash.
|
||||
|
||||
|
||||
Viewing files in GUI tools
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
`encoding`
|
||||
^^^^^^^^^^
|
||||
|
||||
The value of this attribute specifies the character encoding that should
|
||||
be used by GUI tools (e.g. linkgit:gitk[1] and linkgit:git-gui[1]) to
|
||||
display the contents of the relevant file. Note that due to performance
|
||||
considerations linkgit:gitk[1] does not use this attribute unless you
|
||||
manually enable per-file encodings in its options.
|
||||
|
||||
If this attribute is not set or has an invalid value, the value of the
|
||||
`gui.encoding` configuration variable is used instead
|
||||
(See linkgit:git-config[1]).
|
||||
|
||||
|
||||
USING ATTRIBUTE MACROS
|
||||
----------------------
|
||||
|
||||
|
||||
@@ -1690,8 +1690,10 @@ to follow, not easier.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
linkgit:gittutorial[7], linkgit:gittutorial-2[7],
|
||||
linkgit:everyday[7], linkgit:gitcvs-migration[7],
|
||||
linkgit:gittutorial[7],
|
||||
linkgit:gittutorial-2[7],
|
||||
linkgit:gitcvs-migration[7],
|
||||
link:everyday.html[Everyday git],
|
||||
link:user-manual.html[The Git User's Manual]
|
||||
|
||||
GIT
|
||||
|
||||
@@ -16,8 +16,10 @@ include::glossary-content.txt[]
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
linkgit:gittutorial[7], linkgit:gittutorial-2[7],
|
||||
linkgit:everyday[7], linkgit:gitcvs-migration[7],
|
||||
linkgit:gittutorial[7],
|
||||
linkgit:gittutorial-2[7],
|
||||
linkgit:gitcvs-migration[7],
|
||||
link:everyday.html[Everyday git],
|
||||
link:user-manual.html[The Git User's Manual]
|
||||
|
||||
GIT
|
||||
|
||||
@@ -56,6 +56,11 @@ frequently used options.
|
||||
Use this instead of explicitly specifying <revs> if the set of
|
||||
commits to show may vary between refreshes.
|
||||
|
||||
--select-commit=<ref>::
|
||||
|
||||
Automatically select the specified commit after loading the graph.
|
||||
Default behavior is equivalent to specifying '--select-commit=HEAD'.
|
||||
|
||||
<revs>::
|
||||
|
||||
Limit the revisions to show. This can be either a single revision
|
||||
|
||||
@@ -285,8 +285,52 @@ See also linkgit:git-reflog[1].
|
||||
History Simplification
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When optional paths are given, 'git-rev-list' simplifies commits with
|
||||
various strategies, according to the options you have selected.
|
||||
Sometimes you are only interested in parts of the history, for example the
|
||||
commits modifying a particular <path>. But there are two parts of
|
||||
'History Simplification', one part is selecting the commits and the other
|
||||
is how to do it, as there are various strategies to simplify the history.
|
||||
|
||||
The following options select the commits to be shown:
|
||||
|
||||
<paths>::
|
||||
|
||||
Commits modifying the given <paths> are selected.
|
||||
|
||||
--simplify-by-decoration::
|
||||
|
||||
Commits that are referred by some branch or tag are selected.
|
||||
|
||||
Note that extra commits can be shown to give a meaningful history.
|
||||
|
||||
The following options affect the way the simplification is performed:
|
||||
|
||||
Default mode::
|
||||
|
||||
Simplifies the history to the simplest history explaining the
|
||||
final state of the tree. Simplest because it prunes some side
|
||||
branches if the end result is the same (i.e. merging branches
|
||||
with the same content)
|
||||
|
||||
--full-history::
|
||||
|
||||
As the default mode but does not prune some history.
|
||||
|
||||
--dense::
|
||||
|
||||
Only the selected commits are shown, plus some to have a
|
||||
meaningful history.
|
||||
|
||||
--sparse::
|
||||
|
||||
All commits in the simplified history are shown.
|
||||
|
||||
--simplify-merges::
|
||||
|
||||
Additional option to '--full-history' to remove some needless
|
||||
merges from the resulting history, as there are no selected
|
||||
commits contributing to this merge.
|
||||
|
||||
A more detailed explanation follows.
|
||||
|
||||
Suppose you specified `foo` as the <paths>. We shall call commits
|
||||
that modify `foo` !TREESAME, and the rest TREESAME. (In a diff
|
||||
@@ -456,6 +500,14 @@ Note the major differences in `N` and `P` over '\--full-history':
|
||||
removed completely, because it had one parent and is TREESAME.
|
||||
--
|
||||
|
||||
The '\--simplify-by-decoration' option allows you to view only the
|
||||
big picture of the topology of the history, by omitting commits
|
||||
that are not referenced by tags. Commits are marked as !TREESAME
|
||||
(in other words, kept after history simplification rules described
|
||||
above) if (1) they are referenced by tags, or (2) they change the
|
||||
contents of the paths given on the command line. All other
|
||||
commits are marked as TREESAME (subject to be simplified away).
|
||||
|
||||
ifdef::git-rev-list[]
|
||||
Bisection Helpers
|
||||
~~~~~~~~~~~~~~~~~
|
||||
@@ -466,14 +518,14 @@ Limit output to the one commit object which is roughly halfway between
|
||||
the included and excluded commits. Thus, if
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
$ git-rev-list --bisect foo ^bar ^baz
|
||||
$ git rev-list --bisect foo ^bar ^baz
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
outputs 'midpoint', the output of the two commands
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
$ git-rev-list foo ^midpoint
|
||||
$ git-rev-list midpoint ^bar ^baz
|
||||
$ git rev-list foo ^midpoint
|
||||
$ git rev-list midpoint ^bar ^baz
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
would be of roughly the same length. Finding the change which
|
||||
|
||||
@@ -68,13 +68,22 @@ This file should have the following format:
|
||||
------------
|
||||
|
||||
`<url>` is required; `#<head>` is optional.
|
||||
When you do not provide a refspec on the command line,
|
||||
git will use the following refspec, where `<head>` defaults to `master`,
|
||||
and `<repository>` is the name of this file
|
||||
you provided in the command line.
|
||||
|
||||
Depending on the operation, git will use one of the following
|
||||
refspecs, if you don't provide one on the command line.
|
||||
`<branch>` is the name of this file in `$GIT_DIR/branches` and
|
||||
`<head>` defaults to `master`.
|
||||
|
||||
git fetch uses:
|
||||
|
||||
------------
|
||||
refs/heads/<head>:<repository>
|
||||
refs/heads/<head>:refs/heads/<branch>
|
||||
------------
|
||||
|
||||
git push uses:
|
||||
|
||||
------------
|
||||
HEAD:refs/heads/<head>
|
||||
------------
|
||||
|
||||
|
||||
|
||||
22
Makefile
22
Makefile
@@ -229,6 +229,7 @@ INSTALL = install
|
||||
RPMBUILD = rpmbuild
|
||||
TCL_PATH = tclsh
|
||||
TCLTK_PATH = wish
|
||||
PTHREAD_LIBS = -lpthread
|
||||
|
||||
export TCL_PATH TCLTK_PATH
|
||||
|
||||
@@ -690,6 +691,11 @@ ifeq ($(uname_S),FreeBSD)
|
||||
BASIC_LDFLAGS += -L/usr/local/lib
|
||||
DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease
|
||||
THREADED_DELTA_SEARCH = YesPlease
|
||||
ifeq ($(shell expr "$(uname_R)" : '4\.'),2)
|
||||
PTHREAD_LIBS = -pthread
|
||||
NO_UINTMAX_T = YesPlease
|
||||
NO_STRTOUMAX = YesPlease
|
||||
endif
|
||||
endif
|
||||
ifeq ($(uname_S),OpenBSD)
|
||||
NO_STRCASESTR = YesPlease
|
||||
@@ -949,6 +955,9 @@ endif
|
||||
ifdef NO_IPV6
|
||||
BASIC_CFLAGS += -DNO_IPV6
|
||||
endif
|
||||
ifdef NO_UINTMAX_T
|
||||
BASIC_CFLAGS += -Duintmax_t=uint32_t
|
||||
endif
|
||||
ifdef NO_SOCKADDR_STORAGE
|
||||
ifdef NO_IPV6
|
||||
BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in
|
||||
@@ -1010,7 +1019,7 @@ endif
|
||||
|
||||
ifdef THREADED_DELTA_SEARCH
|
||||
BASIC_CFLAGS += -DTHREADED_DELTA_SEARCH
|
||||
EXTLIBS += -lpthread
|
||||
EXTLIBS += $(PTHREAD_LIBS)
|
||||
LIB_OBJS += thread-utils.o
|
||||
endif
|
||||
ifdef DIR_HAS_BSD_GROUP_SEMANTICS
|
||||
@@ -1355,7 +1364,16 @@ check-sha1:: test-sha1$X
|
||||
./test-sha1.sh
|
||||
|
||||
check: common-cmds.h
|
||||
for i in *.c; do sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; done
|
||||
if sparse; \
|
||||
then \
|
||||
for i in *.c; \
|
||||
do \
|
||||
sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; \
|
||||
done; \
|
||||
else \
|
||||
echo 2>&1 "Did you mean 'make test'?"; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
remove-dashes:
|
||||
./fixup-builtins $(BUILT_INS) $(PROGRAMS) $(SCRIPTS)
|
||||
|
||||
207
builtin-blame.c
207
builtin-blame.c
@@ -442,131 +442,6 @@ static struct origin *find_rename(struct scoreboard *sb,
|
||||
return porigin;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parsing of patch chunks...
|
||||
*/
|
||||
struct chunk {
|
||||
/* line number in postimage; up to but not including this
|
||||
* line is the same as preimage
|
||||
*/
|
||||
int same;
|
||||
|
||||
/* preimage line number after this chunk */
|
||||
int p_next;
|
||||
|
||||
/* postimage line number after this chunk */
|
||||
int t_next;
|
||||
};
|
||||
|
||||
struct patch {
|
||||
struct chunk *chunks;
|
||||
int num;
|
||||
};
|
||||
|
||||
struct blame_diff_state {
|
||||
struct patch *ret;
|
||||
unsigned hunk_post_context;
|
||||
unsigned hunk_in_pre_context : 1;
|
||||
};
|
||||
|
||||
static void process_u_diff(void *state_, char *line, unsigned long len)
|
||||
{
|
||||
struct blame_diff_state *state = state_;
|
||||
struct chunk *chunk;
|
||||
int off1, off2, len1, len2, num;
|
||||
|
||||
num = state->ret->num;
|
||||
if (len < 4 || line[0] != '@' || line[1] != '@') {
|
||||
if (state->hunk_in_pre_context && line[0] == ' ')
|
||||
state->ret->chunks[num - 1].same++;
|
||||
else {
|
||||
state->hunk_in_pre_context = 0;
|
||||
if (line[0] == ' ')
|
||||
state->hunk_post_context++;
|
||||
else
|
||||
state->hunk_post_context = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (num && state->hunk_post_context) {
|
||||
chunk = &state->ret->chunks[num - 1];
|
||||
chunk->p_next -= state->hunk_post_context;
|
||||
chunk->t_next -= state->hunk_post_context;
|
||||
}
|
||||
state->ret->num = ++num;
|
||||
state->ret->chunks = xrealloc(state->ret->chunks,
|
||||
sizeof(struct chunk) * num);
|
||||
chunk = &state->ret->chunks[num - 1];
|
||||
if (parse_hunk_header(line, len, &off1, &len1, &off2, &len2)) {
|
||||
state->ret->num--;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Line numbers in patch output are one based. */
|
||||
off1--;
|
||||
off2--;
|
||||
|
||||
chunk->same = len2 ? off2 : (off2 + 1);
|
||||
|
||||
chunk->p_next = off1 + (len1 ? len1 : 1);
|
||||
chunk->t_next = chunk->same + len2;
|
||||
state->hunk_in_pre_context = 1;
|
||||
state->hunk_post_context = 0;
|
||||
}
|
||||
|
||||
static struct patch *compare_buffer(mmfile_t *file_p, mmfile_t *file_o,
|
||||
int context)
|
||||
{
|
||||
struct blame_diff_state state;
|
||||
xpparam_t xpp;
|
||||
xdemitconf_t xecfg;
|
||||
xdemitcb_t ecb;
|
||||
|
||||
xpp.flags = xdl_opts;
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
xecfg.ctxlen = context;
|
||||
memset(&state, 0, sizeof(state));
|
||||
state.ret = xmalloc(sizeof(struct patch));
|
||||
state.ret->chunks = NULL;
|
||||
state.ret->num = 0;
|
||||
|
||||
xdi_diff_outf(file_p, file_o, process_u_diff, &state, &xpp, &xecfg, &ecb);
|
||||
|
||||
if (state.ret->num) {
|
||||
struct chunk *chunk;
|
||||
chunk = &state.ret->chunks[state.ret->num - 1];
|
||||
chunk->p_next -= state.hunk_post_context;
|
||||
chunk->t_next -= state.hunk_post_context;
|
||||
}
|
||||
return state.ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run diff between two origins and grab the patch output, so that
|
||||
* we can pass blame for lines origin is currently suspected for
|
||||
* to its parent.
|
||||
*/
|
||||
static struct patch *get_patch(struct origin *parent, struct origin *origin)
|
||||
{
|
||||
mmfile_t file_p, file_o;
|
||||
struct patch *patch;
|
||||
|
||||
fill_origin_blob(parent, &file_p);
|
||||
fill_origin_blob(origin, &file_o);
|
||||
if (!file_p.ptr || !file_o.ptr)
|
||||
return NULL;
|
||||
patch = compare_buffer(&file_p, &file_o, 0);
|
||||
num_get_patch++;
|
||||
return patch;
|
||||
}
|
||||
|
||||
static void free_patch(struct patch *p)
|
||||
{
|
||||
free(p->chunks);
|
||||
free(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Link in a new blame entry to the scoreboard. Entries that cover the
|
||||
* same line range have been removed from the scoreboard previously.
|
||||
@@ -813,6 +688,22 @@ static void blame_chunk(struct scoreboard *sb,
|
||||
}
|
||||
}
|
||||
|
||||
struct blame_chunk_cb_data {
|
||||
struct scoreboard *sb;
|
||||
struct origin *target;
|
||||
struct origin *parent;
|
||||
long plno;
|
||||
long tlno;
|
||||
};
|
||||
|
||||
static void blame_chunk_cb(void *data, long same, long p_next, long t_next)
|
||||
{
|
||||
struct blame_chunk_cb_data *d = data;
|
||||
blame_chunk(d->sb, d->tlno, d->plno, same, d->target, d->parent);
|
||||
d->plno = p_next;
|
||||
d->tlno = t_next;
|
||||
}
|
||||
|
||||
/*
|
||||
* We are looking at the origin 'target' and aiming to pass blame
|
||||
* for the lines it is suspected to its parent. Run diff to find
|
||||
@@ -822,26 +713,28 @@ static int pass_blame_to_parent(struct scoreboard *sb,
|
||||
struct origin *target,
|
||||
struct origin *parent)
|
||||
{
|
||||
int i, last_in_target, plno, tlno;
|
||||
struct patch *patch;
|
||||
int last_in_target;
|
||||
mmfile_t file_p, file_o;
|
||||
struct blame_chunk_cb_data d = { sb, target, parent, 0, 0 };
|
||||
xpparam_t xpp;
|
||||
xdemitconf_t xecfg;
|
||||
|
||||
last_in_target = find_last_in_target(sb, target);
|
||||
if (last_in_target < 0)
|
||||
return 1; /* nothing remains for this target */
|
||||
|
||||
patch = get_patch(parent, target);
|
||||
plno = tlno = 0;
|
||||
for (i = 0; i < patch->num; i++) {
|
||||
struct chunk *chunk = &patch->chunks[i];
|
||||
fill_origin_blob(parent, &file_p);
|
||||
fill_origin_blob(target, &file_o);
|
||||
num_get_patch++;
|
||||
|
||||
blame_chunk(sb, tlno, plno, chunk->same, target, parent);
|
||||
plno = chunk->p_next;
|
||||
tlno = chunk->t_next;
|
||||
}
|
||||
memset(&xpp, 0, sizeof(xpp));
|
||||
xpp.flags = xdl_opts;
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
xecfg.ctxlen = 0;
|
||||
xdi_diff_hunks(&file_p, &file_o, blame_chunk_cb, &d, &xpp, &xecfg);
|
||||
/* The rest (i.e. anything after tlno) are the same as the parent */
|
||||
blame_chunk(sb, tlno, plno, last_in_target, target, parent);
|
||||
blame_chunk(sb, d.tlno, d.plno, last_in_target, target, parent);
|
||||
|
||||
free_patch(patch);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -933,6 +826,23 @@ static void handle_split(struct scoreboard *sb,
|
||||
}
|
||||
}
|
||||
|
||||
struct handle_split_cb_data {
|
||||
struct scoreboard *sb;
|
||||
struct blame_entry *ent;
|
||||
struct origin *parent;
|
||||
struct blame_entry *split;
|
||||
long plno;
|
||||
long tlno;
|
||||
};
|
||||
|
||||
static void handle_split_cb(void *data, long same, long p_next, long t_next)
|
||||
{
|
||||
struct handle_split_cb_data *d = data;
|
||||
handle_split(d->sb, d->ent, d->tlno, d->plno, same, d->parent, d->split);
|
||||
d->plno = p_next;
|
||||
d->tlno = t_next;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the lines from parent that are the same as ent so that
|
||||
* we can pass blames to it. file_p has the blob contents for
|
||||
@@ -947,8 +857,9 @@ static void find_copy_in_blob(struct scoreboard *sb,
|
||||
const char *cp;
|
||||
int cnt;
|
||||
mmfile_t file_o;
|
||||
struct patch *patch;
|
||||
int i, plno, tlno;
|
||||
struct handle_split_cb_data d = { sb, ent, parent, split, 0, 0 };
|
||||
xpparam_t xpp;
|
||||
xdemitconf_t xecfg;
|
||||
|
||||
/*
|
||||
* Prepare mmfile that contains only the lines in ent.
|
||||
@@ -963,24 +874,18 @@ static void find_copy_in_blob(struct scoreboard *sb,
|
||||
}
|
||||
file_o.size = cp - file_o.ptr;
|
||||
|
||||
patch = compare_buffer(file_p, &file_o, 1);
|
||||
|
||||
/*
|
||||
* file_o is a part of final image we are annotating.
|
||||
* file_p partially may match that image.
|
||||
*/
|
||||
memset(&xpp, 0, sizeof(xpp));
|
||||
xpp.flags = xdl_opts;
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
xecfg.ctxlen = 1;
|
||||
memset(split, 0, sizeof(struct blame_entry [3]));
|
||||
plno = tlno = 0;
|
||||
for (i = 0; i < patch->num; i++) {
|
||||
struct chunk *chunk = &patch->chunks[i];
|
||||
|
||||
handle_split(sb, ent, tlno, plno, chunk->same, parent, split);
|
||||
plno = chunk->p_next;
|
||||
tlno = chunk->t_next;
|
||||
}
|
||||
xdi_diff_hunks(file_p, &file_o, handle_split_cb, &d, &xpp, &xecfg);
|
||||
/* remainder, if any, all match the preimage */
|
||||
handle_split(sb, ent, tlno, plno, ent->num_lines, parent, split);
|
||||
free_patch(patch);
|
||||
handle_split(sb, ent, d.tlno, d.plno, ent->num_lines, parent, split);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -97,7 +97,7 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix)
|
||||
else if (stdin_paths && doubledash < argc)
|
||||
errstr = "Can't specify files with --stdin";
|
||||
if (errstr) {
|
||||
error (errstr);
|
||||
error("%s", errstr);
|
||||
usage_with_options(check_attr_usage, check_attr_options);
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ static int post_checkout_hook(struct commit *old, struct commit *new,
|
||||
|
||||
memset(&proc, 0, sizeof(proc));
|
||||
argv[0] = name;
|
||||
argv[1] = xstrdup(sha1_to_hex(old->object.sha1));
|
||||
argv[1] = xstrdup(sha1_to_hex(old ? old->object.sha1 : null_sha1));
|
||||
argv[2] = xstrdup(sha1_to_hex(new->object.sha1));
|
||||
argv[3] = changed ? "1" : "0";
|
||||
argv[4] = NULL;
|
||||
@@ -397,8 +397,7 @@ static int merge_working_tree(struct checkout_opts *opts,
|
||||
}
|
||||
|
||||
/* 2-way merge to the new branch */
|
||||
topts.initial_checkout = (!active_nr &&
|
||||
(old->commit == new->commit));
|
||||
topts.initial_checkout = is_cache_unborn();
|
||||
topts.update = 1;
|
||||
topts.merge = 1;
|
||||
topts.gently = opts->merge;
|
||||
@@ -492,10 +491,10 @@ static void update_refs_for_switch(struct checkout_opts *opts,
|
||||
}
|
||||
|
||||
old_desc = old->name;
|
||||
if (!old_desc)
|
||||
if (!old_desc && old->commit)
|
||||
old_desc = sha1_to_hex(old->commit->object.sha1);
|
||||
strbuf_addf(&msg, "checkout: moving from %s to %s",
|
||||
old_desc, new->name);
|
||||
old_desc ? old_desc : "(invalid)", new->name);
|
||||
|
||||
if (new->path) {
|
||||
create_symref("HEAD", new->path, msg.buf);
|
||||
@@ -551,7 +550,7 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
|
||||
* a new commit, we want to mention the old commit once more
|
||||
* to remind the user that it might be lost.
|
||||
*/
|
||||
if (!opts->quiet && !old.path && new->commit != old.commit)
|
||||
if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
|
||||
describe_detached_head("Previous HEAD position was", old.commit);
|
||||
|
||||
if (!old.commit) {
|
||||
|
||||
@@ -1015,9 +1015,11 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
|
||||
/* Truncate the message just before the diff, if any. */
|
||||
p = strstr(sb.buf, "\ndiff --git a/");
|
||||
if (p != NULL)
|
||||
strbuf_setlen(&sb, p - sb.buf + 1);
|
||||
if (verbose) {
|
||||
p = strstr(sb.buf, "\ndiff --git ");
|
||||
if (p != NULL)
|
||||
strbuf_setlen(&sb, p - sb.buf + 1);
|
||||
}
|
||||
|
||||
if (cleanup_mode != CLEANUP_NONE)
|
||||
stripspace(&sb, cleanup_mode == CLEANUP_ALL);
|
||||
|
||||
@@ -118,7 +118,7 @@ static int builtin_diff_index(struct rev_info *revs,
|
||||
int cached = 0;
|
||||
while (1 < argc) {
|
||||
const char *arg = argv[1];
|
||||
if (!strcmp(arg, "--cached"))
|
||||
if (!strcmp(arg, "--cached") || !strcmp(arg, "--staged"))
|
||||
cached = 1;
|
||||
else
|
||||
usage(builtin_diff_usage);
|
||||
@@ -300,6 +300,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL);
|
||||
DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
|
||||
DIFF_OPT_SET(&rev.diffopt, ALLOW_TEXTCONV);
|
||||
|
||||
/*
|
||||
* If the user asked for our exit code then don't start a
|
||||
@@ -319,7 +320,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
|
||||
const char *arg = argv[i];
|
||||
if (!strcmp(arg, "--"))
|
||||
break;
|
||||
else if (!strcmp(arg, "--cached")) {
|
||||
else if (!strcmp(arg, "--cached") ||
|
||||
!strcmp(arg, "--staged")) {
|
||||
add_head_to_pending(&rev);
|
||||
if (!rev.pending.nr)
|
||||
die("No HEAD commit to compare with (yet)");
|
||||
|
||||
12
builtin-gc.c
12
builtin-gc.c
@@ -131,19 +131,9 @@ static int too_many_packs(void)
|
||||
|
||||
prepare_packed_git();
|
||||
for (cnt = 0, p = packed_git; p; p = p->next) {
|
||||
char path[PATH_MAX];
|
||||
size_t len;
|
||||
int keep;
|
||||
|
||||
if (!p->pack_local)
|
||||
continue;
|
||||
len = strlen(p->pack_name);
|
||||
if (PATH_MAX <= len + 1)
|
||||
continue; /* oops, give up */
|
||||
memcpy(path, p->pack_name, len-5);
|
||||
memcpy(path + len - 5, ".keep", 6);
|
||||
keep = access(p->pack_name, F_OK) && (errno == ENOENT);
|
||||
if (keep)
|
||||
if (p->pack_keep)
|
||||
continue;
|
||||
/*
|
||||
* Perhaps check the size of the pack and count only
|
||||
|
||||
@@ -28,7 +28,6 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
|
||||
struct rev_info *rev)
|
||||
{
|
||||
int i;
|
||||
int decorate = 0;
|
||||
|
||||
rev->abbrev = DEFAULT_ABBREV;
|
||||
rev->commit_format = CMIT_FMT_DEFAULT;
|
||||
@@ -55,10 +54,13 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
|
||||
const char *arg = argv[i];
|
||||
if (!strcmp(arg, "--decorate")) {
|
||||
load_ref_decorations();
|
||||
decorate = 1;
|
||||
rev->show_decorations = 1;
|
||||
} else if (!strcmp(arg, "--source")) {
|
||||
rev->show_source = 1;
|
||||
} else
|
||||
die("unrecognized argument: %s", arg);
|
||||
}
|
||||
DIFF_OPT_SET(&rev->diffopt, ALLOW_TEXTCONV);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -227,6 +227,8 @@ static void show_files(struct dir_struct *dir, const char *prefix)
|
||||
int dtype = ce_to_dtype(ce);
|
||||
if (excluded(dir, ce->name, &dtype) != dir->show_ignored)
|
||||
continue;
|
||||
if (ce->ce_flags & CE_UPDATE)
|
||||
continue;
|
||||
err = lstat(ce->name, &st);
|
||||
if (show_deleted && err)
|
||||
show_ce_entry(tag_removed, ce);
|
||||
@@ -329,7 +331,7 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix)
|
||||
if (prefix) {
|
||||
static const char *(matchbuf[2]);
|
||||
matchbuf[0] = prefix;
|
||||
matchbuf [1] = NULL;
|
||||
matchbuf[1] = NULL;
|
||||
match = matchbuf;
|
||||
} else
|
||||
match = NULL;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "remote.h"
|
||||
|
||||
static const char ls_remote_usage[] =
|
||||
"git ls-remote [--upload-pack=<git-upload-pack>] [<host>:]<directory>";
|
||||
"git ls-remote [--heads] [--tags] [-u <exec> | --upload-pack <exec>] <repository> <refs>...";
|
||||
|
||||
/*
|
||||
* Is there one among the list of patterns that match the tail part
|
||||
|
||||
@@ -71,6 +71,7 @@ static int reuse_delta = 1, reuse_object = 1;
|
||||
static int keep_unreachable, unpack_unreachable, include_tag;
|
||||
static int local;
|
||||
static int incremental;
|
||||
static int ignore_packed_keep;
|
||||
static int allow_ofs_delta;
|
||||
static const char *base_name;
|
||||
static int progress = 1;
|
||||
@@ -245,8 +246,16 @@ static unsigned long write_object(struct sha1file *f,
|
||||
type = entry->type;
|
||||
|
||||
/* write limit if limited packsize and not first object */
|
||||
limit = pack_size_limit && nr_written ?
|
||||
pack_size_limit - write_offset : 0;
|
||||
if (!pack_size_limit || !nr_written)
|
||||
limit = 0;
|
||||
else if (pack_size_limit <= write_offset)
|
||||
/*
|
||||
* the earlier object did not fit the limit; avoid
|
||||
* mistaking this with unlimited (i.e. limit = 0).
|
||||
*/
|
||||
limit = 1;
|
||||
else
|
||||
limit = pack_size_limit - write_offset;
|
||||
|
||||
if (!entry->delta)
|
||||
usable_delta = 0; /* no delta */
|
||||
@@ -277,6 +286,7 @@ static unsigned long write_object(struct sha1file *f,
|
||||
*/
|
||||
|
||||
if (!to_reuse) {
|
||||
no_reuse:
|
||||
if (!usable_delta) {
|
||||
buf = read_sha1_file(entry->idx.sha1, &type, &size);
|
||||
if (!buf)
|
||||
@@ -358,46 +368,60 @@ static unsigned long write_object(struct sha1file *f,
|
||||
struct revindex_entry *revidx;
|
||||
off_t offset;
|
||||
|
||||
if (entry->delta) {
|
||||
if (entry->delta)
|
||||
type = (allow_ofs_delta && entry->delta->idx.offset) ?
|
||||
OBJ_OFS_DELTA : OBJ_REF_DELTA;
|
||||
reused_delta++;
|
||||
}
|
||||
hdrlen = encode_header(type, entry->size, header);
|
||||
|
||||
offset = entry->in_pack_offset;
|
||||
revidx = find_pack_revindex(p, offset);
|
||||
datalen = revidx[1].offset - offset;
|
||||
if (!pack_to_stdout && p->index_version > 1 &&
|
||||
check_pack_crc(p, &w_curs, offset, datalen, revidx->nr))
|
||||
die("bad packed object CRC for %s", sha1_to_hex(entry->idx.sha1));
|
||||
check_pack_crc(p, &w_curs, offset, datalen, revidx->nr)) {
|
||||
error("bad packed object CRC for %s", sha1_to_hex(entry->idx.sha1));
|
||||
unuse_pack(&w_curs);
|
||||
goto no_reuse;
|
||||
}
|
||||
|
||||
offset += entry->in_pack_header_size;
|
||||
datalen -= entry->in_pack_header_size;
|
||||
if (!pack_to_stdout && p->index_version == 1 &&
|
||||
check_pack_inflate(p, &w_curs, offset, datalen, entry->size)) {
|
||||
error("corrupt packed object for %s", sha1_to_hex(entry->idx.sha1));
|
||||
unuse_pack(&w_curs);
|
||||
goto no_reuse;
|
||||
}
|
||||
|
||||
if (type == OBJ_OFS_DELTA) {
|
||||
off_t ofs = entry->idx.offset - entry->delta->idx.offset;
|
||||
unsigned pos = sizeof(dheader) - 1;
|
||||
dheader[pos] = ofs & 127;
|
||||
while (ofs >>= 7)
|
||||
dheader[--pos] = 128 | (--ofs & 127);
|
||||
if (limit && hdrlen + sizeof(dheader) - pos + datalen + 20 >= limit)
|
||||
if (limit && hdrlen + sizeof(dheader) - pos + datalen + 20 >= limit) {
|
||||
unuse_pack(&w_curs);
|
||||
return 0;
|
||||
}
|
||||
sha1write(f, header, hdrlen);
|
||||
sha1write(f, dheader + pos, sizeof(dheader) - pos);
|
||||
hdrlen += sizeof(dheader) - pos;
|
||||
reused_delta++;
|
||||
} else if (type == OBJ_REF_DELTA) {
|
||||
if (limit && hdrlen + 20 + datalen + 20 >= limit)
|
||||
if (limit && hdrlen + 20 + datalen + 20 >= limit) {
|
||||
unuse_pack(&w_curs);
|
||||
return 0;
|
||||
}
|
||||
sha1write(f, header, hdrlen);
|
||||
sha1write(f, entry->delta->idx.sha1, 20);
|
||||
hdrlen += 20;
|
||||
reused_delta++;
|
||||
} else {
|
||||
if (limit && hdrlen + datalen + 20 >= limit)
|
||||
if (limit && hdrlen + datalen + 20 >= limit) {
|
||||
unuse_pack(&w_curs);
|
||||
return 0;
|
||||
}
|
||||
sha1write(f, header, hdrlen);
|
||||
}
|
||||
|
||||
if (!pack_to_stdout && p->index_version == 1 &&
|
||||
check_pack_inflate(p, &w_curs, offset, datalen, entry->size))
|
||||
die("corrupt packed object for %s", sha1_to_hex(entry->idx.sha1));
|
||||
copy_pack_data(f, p, &w_curs, offset, datalen);
|
||||
unuse_pack(&w_curs);
|
||||
reused++;
|
||||
@@ -690,6 +714,9 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!exclude && local && has_loose_object_nonlocal(sha1))
|
||||
return 0;
|
||||
|
||||
for (p = packed_git; p; p = p->next) {
|
||||
off_t offset = find_pack_entry_one(sha1, p);
|
||||
if (offset) {
|
||||
@@ -703,6 +730,8 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type,
|
||||
return 0;
|
||||
if (local && !p->pack_local)
|
||||
return 0;
|
||||
if (ignore_packed_keep && p->pack_local && p->pack_keep)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1002,9 +1031,11 @@ static void check_object(struct object_entry *entry)
|
||||
* We want in_pack_type even if we do not reuse delta
|
||||
* since non-delta representations could still be reused.
|
||||
*/
|
||||
used = unpack_object_header_gently(buf, avail,
|
||||
used = unpack_object_header_buffer(buf, avail,
|
||||
&entry->in_pack_type,
|
||||
&entry->size);
|
||||
if (used == 0)
|
||||
goto give_up;
|
||||
|
||||
/*
|
||||
* Determine if this is a delta and if so whether we can
|
||||
@@ -1016,6 +1047,8 @@ static void check_object(struct object_entry *entry)
|
||||
/* Not a delta hence we've already got all we need. */
|
||||
entry->type = entry->in_pack_type;
|
||||
entry->in_pack_header_size = used;
|
||||
if (entry->type < OBJ_COMMIT || entry->type > OBJ_BLOB)
|
||||
goto give_up;
|
||||
unuse_pack(&w_curs);
|
||||
return;
|
||||
case OBJ_REF_DELTA:
|
||||
@@ -1032,19 +1065,25 @@ static void check_object(struct object_entry *entry)
|
||||
ofs = c & 127;
|
||||
while (c & 128) {
|
||||
ofs += 1;
|
||||
if (!ofs || MSB(ofs, 7))
|
||||
die("delta base offset overflow in pack for %s",
|
||||
sha1_to_hex(entry->idx.sha1));
|
||||
if (!ofs || MSB(ofs, 7)) {
|
||||
error("delta base offset overflow in pack for %s",
|
||||
sha1_to_hex(entry->idx.sha1));
|
||||
goto give_up;
|
||||
}
|
||||
c = buf[used_0++];
|
||||
ofs = (ofs << 7) + (c & 127);
|
||||
}
|
||||
if (ofs >= entry->in_pack_offset)
|
||||
die("delta base offset out of bound for %s",
|
||||
sha1_to_hex(entry->idx.sha1));
|
||||
ofs = entry->in_pack_offset - ofs;
|
||||
if (ofs <= 0 || ofs >= entry->in_pack_offset) {
|
||||
error("delta base offset out of bound for %s",
|
||||
sha1_to_hex(entry->idx.sha1));
|
||||
goto give_up;
|
||||
}
|
||||
if (reuse_delta && !entry->preferred_base) {
|
||||
struct revindex_entry *revidx;
|
||||
revidx = find_pack_revindex(p, ofs);
|
||||
if (!revidx)
|
||||
goto give_up;
|
||||
base_ref = nth_packed_object_sha1(p, revidx->nr);
|
||||
}
|
||||
entry->in_pack_header_size = used + used_0;
|
||||
@@ -1064,6 +1103,7 @@ static void check_object(struct object_entry *entry)
|
||||
*/
|
||||
entry->type = entry->in_pack_type;
|
||||
entry->delta = base_entry;
|
||||
entry->delta_size = entry->size;
|
||||
entry->delta_sibling = base_entry->delta_child;
|
||||
base_entry->delta_child = entry;
|
||||
unuse_pack(&w_curs);
|
||||
@@ -1078,6 +1118,8 @@ static void check_object(struct object_entry *entry)
|
||||
*/
|
||||
entry->size = get_size_from_delta(p, &w_curs,
|
||||
entry->in_pack_offset + entry->in_pack_header_size);
|
||||
if (entry->size == 0)
|
||||
goto give_up;
|
||||
unuse_pack(&w_curs);
|
||||
return;
|
||||
}
|
||||
@@ -1087,6 +1129,7 @@ static void check_object(struct object_entry *entry)
|
||||
* with sha1_object_info() to find about the object type
|
||||
* at this point...
|
||||
*/
|
||||
give_up:
|
||||
unuse_pack(&w_curs);
|
||||
}
|
||||
|
||||
@@ -1698,6 +1741,16 @@ static void prepare_pack(int window, int depth)
|
||||
|
||||
get_object_details();
|
||||
|
||||
/*
|
||||
* If we're locally repacking then we need to be doubly careful
|
||||
* from now on in order to make sure no stealth corruption gets
|
||||
* propagated to the new pack. Clients receiving streamed packs
|
||||
* should validate everything they get anyway so no need to incur
|
||||
* the additional cost here in that case.
|
||||
*/
|
||||
if (!pack_to_stdout)
|
||||
do_check_packed_object_crc = 1;
|
||||
|
||||
if (!nr_objects || !window || !depth)
|
||||
return;
|
||||
|
||||
@@ -2048,6 +2101,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
||||
incremental = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("--honor-pack-keep", arg)) {
|
||||
ignore_packed_keep = 1;
|
||||
continue;
|
||||
}
|
||||
if (!prefixcmp(arg, "--compression=")) {
|
||||
char *end;
|
||||
int level = strtoul(arg+14, &end, 0);
|
||||
|
||||
@@ -206,7 +206,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
|
||||
break;
|
||||
case 2:
|
||||
opts.fn = twoway_merge;
|
||||
opts.initial_checkout = !active_nr;
|
||||
opts.initial_checkout = is_cache_unborn();
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
|
||||
@@ -11,8 +11,15 @@
|
||||
|
||||
static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
|
||||
|
||||
enum deny_action {
|
||||
DENY_IGNORE,
|
||||
DENY_WARN,
|
||||
DENY_REFUSE,
|
||||
};
|
||||
|
||||
static int deny_deletes = 0;
|
||||
static int deny_non_fast_forwards = 0;
|
||||
static enum deny_action deny_current_branch = DENY_WARN;
|
||||
static int receive_fsck_objects;
|
||||
static int receive_unpack_limit = -1;
|
||||
static int transfer_unpack_limit = -1;
|
||||
@@ -22,6 +29,21 @@ static int report_status;
|
||||
static char capabilities[] = " report-status delete-refs ";
|
||||
static int capabilities_sent;
|
||||
|
||||
static enum deny_action parse_deny_action(const char *var, const char *value)
|
||||
{
|
||||
if (value) {
|
||||
if (!strcasecmp(value, "ignore"))
|
||||
return DENY_IGNORE;
|
||||
if (!strcasecmp(value, "warn"))
|
||||
return DENY_WARN;
|
||||
if (!strcasecmp(value, "refuse"))
|
||||
return DENY_REFUSE;
|
||||
}
|
||||
if (git_config_bool(var, value))
|
||||
return DENY_REFUSE;
|
||||
return DENY_IGNORE;
|
||||
}
|
||||
|
||||
static int receive_pack_config(const char *var, const char *value, void *cb)
|
||||
{
|
||||
if (strcmp(var, "receive.denydeletes") == 0) {
|
||||
@@ -49,6 +71,11 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "receive.denycurrentbranch")) {
|
||||
deny_current_branch = parse_deny_action(var, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return git_default_config(var, value, cb);
|
||||
}
|
||||
|
||||
@@ -173,6 +200,20 @@ static int run_update_hook(struct command *cmd)
|
||||
return hook_status(run_command(&proc), update_hook);
|
||||
}
|
||||
|
||||
static int is_ref_checked_out(const char *ref)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
const char *head;
|
||||
|
||||
if (is_bare_repository())
|
||||
return 0;
|
||||
|
||||
head = resolve_ref("HEAD", sha1, 0, NULL);
|
||||
if (!head)
|
||||
return 0;
|
||||
return !strcmp(head, ref);
|
||||
}
|
||||
|
||||
static const char *update(struct command *cmd)
|
||||
{
|
||||
const char *name = cmd->ref_name;
|
||||
@@ -186,6 +227,24 @@ static const char *update(struct command *cmd)
|
||||
return "funny refname";
|
||||
}
|
||||
|
||||
switch (deny_current_branch) {
|
||||
case DENY_IGNORE:
|
||||
break;
|
||||
case DENY_WARN:
|
||||
if (!is_ref_checked_out(name))
|
||||
break;
|
||||
warning("updating the currently checked out branch; this may"
|
||||
" cause confusion,\n"
|
||||
"as the index and working tree do not reflect changes"
|
||||
" that are now in HEAD.");
|
||||
break;
|
||||
case DENY_REFUSE:
|
||||
if (!is_ref_checked_out(name))
|
||||
break;
|
||||
error("refusing to update checked out branch: %s", name);
|
||||
return "branch is currently checked out";
|
||||
}
|
||||
|
||||
if (!is_null_sha1(new_sha1) && !has_sha1_file(new_sha1)) {
|
||||
error("unpack should have generated %s, "
|
||||
"but I can't find it!", sha1_to_hex(new_sha1));
|
||||
|
||||
190
builtin-remote.c
190
builtin-remote.c
@@ -10,6 +10,7 @@
|
||||
static const char * const builtin_remote_usage[] = {
|
||||
"git remote",
|
||||
"git remote add <name> <url>",
|
||||
"git remote rename <old> <new>",
|
||||
"git remote rm <name>",
|
||||
"git remote show <name>",
|
||||
"git remote prune <name>",
|
||||
@@ -320,7 +321,7 @@ static int add_branch_for_removal(const char *refname,
|
||||
|
||||
/* make sure that symrefs are deleted */
|
||||
if (flags & REF_ISSYMREF)
|
||||
return unlink(git_path(refname));
|
||||
return unlink(git_path("%s", refname));
|
||||
|
||||
item = string_list_append(refname, branches->branches);
|
||||
item->util = xmalloc(20);
|
||||
@@ -329,6 +330,191 @@ static int add_branch_for_removal(const char *refname,
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct rename_info {
|
||||
const char *old;
|
||||
const char *new;
|
||||
struct string_list *remote_branches;
|
||||
};
|
||||
|
||||
static int read_remote_branches(const char *refname,
|
||||
const unsigned char *sha1, int flags, void *cb_data)
|
||||
{
|
||||
struct rename_info *rename = cb_data;
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
struct string_list_item *item;
|
||||
int flag;
|
||||
unsigned char orig_sha1[20];
|
||||
const char *symref;
|
||||
|
||||
strbuf_addf(&buf, "refs/remotes/%s", rename->old);
|
||||
if(!prefixcmp(refname, buf.buf)) {
|
||||
item = string_list_append(xstrdup(refname), rename->remote_branches);
|
||||
symref = resolve_ref(refname, orig_sha1, 1, &flag);
|
||||
if (flag & REF_ISSYMREF)
|
||||
item->util = xstrdup(symref);
|
||||
else
|
||||
item->util = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int migrate_file(struct remote *remote)
|
||||
{
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
int i;
|
||||
char *path = NULL;
|
||||
|
||||
strbuf_addf(&buf, "remote.%s.url", remote->name);
|
||||
for (i = 0; i < remote->url_nr; i++)
|
||||
if (git_config_set_multivar(buf.buf, remote->url[i], "^$", 0))
|
||||
return error("Could not append '%s' to '%s'",
|
||||
remote->url[i], buf.buf);
|
||||
strbuf_reset(&buf);
|
||||
strbuf_addf(&buf, "remote.%s.push", remote->name);
|
||||
for (i = 0; i < remote->push_refspec_nr; i++)
|
||||
if (git_config_set_multivar(buf.buf, remote->push_refspec[i], "^$", 0))
|
||||
return error("Could not append '%s' to '%s'",
|
||||
remote->push_refspec[i], buf.buf);
|
||||
strbuf_reset(&buf);
|
||||
strbuf_addf(&buf, "remote.%s.fetch", remote->name);
|
||||
for (i = 0; i < remote->fetch_refspec_nr; i++)
|
||||
if (git_config_set_multivar(buf.buf, remote->fetch_refspec[i], "^$", 0))
|
||||
return error("Could not append '%s' to '%s'",
|
||||
remote->fetch_refspec[i], buf.buf);
|
||||
if (remote->origin == REMOTE_REMOTES)
|
||||
path = git_path("remotes/%s", remote->name);
|
||||
else if (remote->origin == REMOTE_BRANCHES)
|
||||
path = git_path("branches/%s", remote->name);
|
||||
if (path && unlink(path))
|
||||
warning("failed to remove '%s'", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mv(int argc, const char **argv)
|
||||
{
|
||||
struct option options[] = {
|
||||
OPT_END()
|
||||
};
|
||||
struct remote *oldremote, *newremote;
|
||||
struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT, buf3 = STRBUF_INIT;
|
||||
struct string_list remote_branches = { NULL, 0, 0, 0 };
|
||||
struct rename_info rename;
|
||||
int i;
|
||||
|
||||
if (argc != 3)
|
||||
usage_with_options(builtin_remote_usage, options);
|
||||
|
||||
rename.old = argv[1];
|
||||
rename.new = argv[2];
|
||||
rename.remote_branches = &remote_branches;
|
||||
|
||||
oldremote = remote_get(rename.old);
|
||||
if (!oldremote)
|
||||
die("No such remote: %s", rename.old);
|
||||
|
||||
if (!strcmp(rename.old, rename.new) && oldremote->origin != REMOTE_CONFIG)
|
||||
return migrate_file(oldremote);
|
||||
|
||||
newremote = remote_get(rename.new);
|
||||
if (newremote && (newremote->url_nr > 1 || newremote->fetch_refspec_nr))
|
||||
die("remote %s already exists.", rename.new);
|
||||
|
||||
strbuf_addf(&buf, "refs/heads/test:refs/remotes/%s/test", rename.new);
|
||||
if (!valid_fetch_refspec(buf.buf))
|
||||
die("'%s' is not a valid remote name", rename.new);
|
||||
|
||||
strbuf_reset(&buf);
|
||||
strbuf_addf(&buf, "remote.%s", rename.old);
|
||||
strbuf_addf(&buf2, "remote.%s", rename.new);
|
||||
if (git_config_rename_section(buf.buf, buf2.buf) < 1)
|
||||
return error("Could not rename config section '%s' to '%s'",
|
||||
buf.buf, buf2.buf);
|
||||
|
||||
strbuf_reset(&buf);
|
||||
strbuf_addf(&buf, "remote.%s.fetch", rename.new);
|
||||
if (git_config_set_multivar(buf.buf, NULL, NULL, 1))
|
||||
return error("Could not remove config section '%s'", buf.buf);
|
||||
for (i = 0; i < oldremote->fetch_refspec_nr; i++) {
|
||||
char *ptr;
|
||||
|
||||
strbuf_reset(&buf2);
|
||||
strbuf_addstr(&buf2, oldremote->fetch_refspec[i]);
|
||||
ptr = strstr(buf2.buf, rename.old);
|
||||
if (ptr)
|
||||
strbuf_splice(&buf2, ptr-buf2.buf, strlen(rename.old),
|
||||
rename.new, strlen(rename.new));
|
||||
if (git_config_set_multivar(buf.buf, buf2.buf, "^$", 0))
|
||||
return error("Could not append '%s'", buf.buf);
|
||||
}
|
||||
|
||||
read_branches();
|
||||
for (i = 0; i < branch_list.nr; i++) {
|
||||
struct string_list_item *item = branch_list.items + i;
|
||||
struct branch_info *info = item->util;
|
||||
if (info->remote && !strcmp(info->remote, rename.old)) {
|
||||
strbuf_reset(&buf);
|
||||
strbuf_addf(&buf, "branch.%s.remote", item->string);
|
||||
if (git_config_set(buf.buf, rename.new)) {
|
||||
return error("Could not set '%s'", buf.buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* First remove symrefs, then rename the rest, finally create
|
||||
* the new symrefs.
|
||||
*/
|
||||
for_each_ref(read_remote_branches, &rename);
|
||||
for (i = 0; i < remote_branches.nr; i++) {
|
||||
struct string_list_item *item = remote_branches.items + i;
|
||||
int flag = 0;
|
||||
unsigned char sha1[20];
|
||||
const char *symref;
|
||||
|
||||
symref = resolve_ref(item->string, sha1, 1, &flag);
|
||||
if (!(flag & REF_ISSYMREF))
|
||||
continue;
|
||||
if (delete_ref(item->string, NULL, REF_NODEREF))
|
||||
die("deleting '%s' failed", item->string);
|
||||
}
|
||||
for (i = 0; i < remote_branches.nr; i++) {
|
||||
struct string_list_item *item = remote_branches.items + i;
|
||||
|
||||
if (item->util)
|
||||
continue;
|
||||
strbuf_reset(&buf);
|
||||
strbuf_addstr(&buf, item->string);
|
||||
strbuf_splice(&buf, strlen("refs/remotes/"), strlen(rename.old),
|
||||
rename.new, strlen(rename.new));
|
||||
strbuf_reset(&buf2);
|
||||
strbuf_addf(&buf2, "remote: renamed %s to %s",
|
||||
item->string, buf.buf);
|
||||
if (rename_ref(item->string, buf.buf, buf2.buf))
|
||||
die("renaming '%s' failed", item->string);
|
||||
}
|
||||
for (i = 0; i < remote_branches.nr; i++) {
|
||||
struct string_list_item *item = remote_branches.items + i;
|
||||
|
||||
if (!item->util)
|
||||
continue;
|
||||
strbuf_reset(&buf);
|
||||
strbuf_addstr(&buf, item->string);
|
||||
strbuf_splice(&buf, strlen("refs/remotes/"), strlen(rename.old),
|
||||
rename.new, strlen(rename.new));
|
||||
strbuf_reset(&buf2);
|
||||
strbuf_addstr(&buf2, item->util);
|
||||
strbuf_splice(&buf2, strlen("refs/remotes/"), strlen(rename.old),
|
||||
rename.new, strlen(rename.new));
|
||||
strbuf_reset(&buf3);
|
||||
strbuf_addf(&buf3, "remote: renamed %s to %s",
|
||||
item->string, buf.buf);
|
||||
if (create_symref(buf.buf, buf2.buf, buf3.buf))
|
||||
die("creating '%s' failed", buf.buf);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int remove_branches(struct string_list *branches)
|
||||
{
|
||||
int i, result = 0;
|
||||
@@ -695,6 +881,8 @@ int cmd_remote(int argc, const char **argv, const char *prefix)
|
||||
result = show_all();
|
||||
else if (!strcmp(argv[0], "add"))
|
||||
result = add(argc, argv);
|
||||
else if (!strcmp(argv[0], "rename"))
|
||||
result = mv(argc, argv);
|
||||
else if (!strcmp(argv[0], "rm"))
|
||||
result = rm(argc, argv);
|
||||
else if (!strcmp(argv[0], "show"))
|
||||
|
||||
@@ -98,6 +98,7 @@ static int diff_two(const char *file1, const char *label1,
|
||||
|
||||
printf("--- a/%s\n+++ b/%s\n", label1, label2);
|
||||
fflush(stdout);
|
||||
memset(&xpp, 0, sizeof(xpp));
|
||||
xpp.flags = XDF_NEED_MINIMAL;
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
xecfg.ctxlen = 3;
|
||||
|
||||
@@ -100,7 +100,7 @@ static void show_commit(struct commit *commit)
|
||||
children = children->next;
|
||||
}
|
||||
}
|
||||
show_decorations(commit);
|
||||
show_decorations(&revs, commit);
|
||||
if (revs.commit_format == CMIT_FMT_ONELINE)
|
||||
putchar(' ');
|
||||
else
|
||||
|
||||
@@ -230,7 +230,7 @@ static void update_tracking_ref(struct remote *remote, struct ref *ref)
|
||||
{
|
||||
struct refspec rs;
|
||||
|
||||
if (ref->status != REF_STATUS_OK)
|
||||
if (ref->status != REF_STATUS_OK && ref->status != REF_STATUS_UPTODATE)
|
||||
return;
|
||||
|
||||
rs.src = ref->name;
|
||||
@@ -435,24 +435,19 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
|
||||
*/
|
||||
new_refs = 0;
|
||||
for (ref = remote_refs; ref; ref = ref->next) {
|
||||
const unsigned char *new_sha1;
|
||||
|
||||
if (!ref->peer_ref) {
|
||||
if (!args.send_mirror)
|
||||
continue;
|
||||
new_sha1 = null_sha1;
|
||||
}
|
||||
else
|
||||
new_sha1 = ref->peer_ref->new_sha1;
|
||||
if (ref->peer_ref)
|
||||
hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
|
||||
else if (!args.send_mirror)
|
||||
continue;
|
||||
|
||||
|
||||
ref->deletion = is_null_sha1(new_sha1);
|
||||
ref->deletion = is_null_sha1(ref->new_sha1);
|
||||
if (ref->deletion && !allow_deleting_refs) {
|
||||
ref->status = REF_STATUS_REJECT_NODELETE;
|
||||
continue;
|
||||
}
|
||||
if (!ref->deletion &&
|
||||
!hashcmp(ref->old_sha1, new_sha1)) {
|
||||
!hashcmp(ref->old_sha1, ref->new_sha1)) {
|
||||
ref->status = REF_STATUS_UPTODATE;
|
||||
continue;
|
||||
}
|
||||
@@ -480,14 +475,13 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
|
||||
!ref->deletion &&
|
||||
!is_null_sha1(ref->old_sha1) &&
|
||||
(!has_sha1_file(ref->old_sha1)
|
||||
|| !ref_newer(new_sha1, ref->old_sha1));
|
||||
|| !ref_newer(ref->new_sha1, ref->old_sha1));
|
||||
|
||||
if (ref->nonfastforward && !ref->force && !args.force_update) {
|
||||
ref->status = REF_STATUS_REJECT_NONFASTFORWARD;
|
||||
continue;
|
||||
}
|
||||
|
||||
hashcpy(ref->new_sha1, new_sha1);
|
||||
if (!ref->deletion)
|
||||
new_refs++;
|
||||
|
||||
|
||||
@@ -344,7 +344,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
|
||||
const char *object_ref, *tag;
|
||||
struct ref_lock *lock;
|
||||
|
||||
int annotate = 0, sign = 0, force = 0, lines = 0,
|
||||
int annotate = 0, sign = 0, force = 0, lines = -1,
|
||||
list = 0, delete = 0, verify = 0;
|
||||
const char *msgfile = NULL, *keyid = NULL;
|
||||
struct msg_arg msg = { 0, STRBUF_INIT };
|
||||
@@ -380,9 +380,19 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
if (sign)
|
||||
annotate = 1;
|
||||
if (argc == 0 && !(delete || verify))
|
||||
list = 1;
|
||||
|
||||
if ((annotate || msg.given || msgfile || force) &&
|
||||
(list || delete || verify))
|
||||
usage_with_options(git_tag_usage, options);
|
||||
|
||||
if (list + delete + verify > 1)
|
||||
usage_with_options(git_tag_usage, options);
|
||||
if (list)
|
||||
return list_tags(argv[0], lines);
|
||||
return list_tags(argv[0], lines == -1 ? 0 : lines);
|
||||
if (lines != -1)
|
||||
die("-n option is only allowed with -l.");
|
||||
if (delete)
|
||||
return for_each_tag_name(argv, delete_tag);
|
||||
if (verify)
|
||||
@@ -406,11 +416,6 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
}
|
||||
|
||||
if (argc == 0) {
|
||||
if (annotate)
|
||||
usage_with_options(git_tag_usage, options);
|
||||
return list_tags(NULL, lines);
|
||||
}
|
||||
tag = argv[0];
|
||||
|
||||
object_ref = argc == 2 ? argv[1] : "HEAD";
|
||||
|
||||
@@ -370,6 +370,8 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
|
||||
base_offset = (base_offset << 7) + (c & 127);
|
||||
}
|
||||
base_offset = obj_list[nr].offset - base_offset;
|
||||
if (base_offset <= 0 || base_offset >= obj_list[nr].offset)
|
||||
die("offset value out of bound for delta base object");
|
||||
|
||||
delta_data = get_data(delta_size);
|
||||
if (dry_run || !delta_data) {
|
||||
|
||||
4
bundle.c
4
bundle.c
@@ -114,7 +114,7 @@ int verify_bundle(struct bundle_header *header, int verbose)
|
||||
continue;
|
||||
}
|
||||
if (++ret == 1)
|
||||
error(message);
|
||||
error("%s", message);
|
||||
error("%s %s", sha1_to_hex(e->sha1), e->name);
|
||||
}
|
||||
if (revs.pending.nr != p->nr)
|
||||
@@ -139,7 +139,7 @@ int verify_bundle(struct bundle_header *header, int verbose)
|
||||
for (i = 0; i < req_nr; i++)
|
||||
if (!(refs.objects[i].item->flags & SHOWN)) {
|
||||
if (++ret == 1)
|
||||
error(message);
|
||||
error("%s", message);
|
||||
error("%s %s", sha1_to_hex(refs.objects[i].item->sha1),
|
||||
refs.objects[i].name);
|
||||
}
|
||||
|
||||
17
cache.h
17
cache.h
@@ -262,6 +262,7 @@ static inline void remove_name_hash(struct cache_entry *ce)
|
||||
|
||||
#define read_cache() read_index(&the_index)
|
||||
#define read_cache_from(path) read_index_from(&the_index, (path))
|
||||
#define is_cache_unborn() is_index_unborn(&the_index)
|
||||
#define read_cache_unmerged() read_index_unmerged(&the_index)
|
||||
#define write_cache(newfd, cache, entries) write_index(&the_index, (newfd))
|
||||
#define discard_cache() discard_index(&the_index)
|
||||
@@ -368,6 +369,7 @@ extern int init_db(const char *template_dir, unsigned int flags);
|
||||
/* Initialize and use the cache information */
|
||||
extern int read_index(struct index_state *);
|
||||
extern int read_index_from(struct index_state *, const char *path);
|
||||
extern int is_index_unborn(struct index_state *);
|
||||
extern int read_index_unmerged(struct index_state *);
|
||||
extern int write_index(const struct index_state *, int newfd);
|
||||
extern int discard_index(struct index_state *);
|
||||
@@ -528,6 +530,12 @@ static inline void hashclr(unsigned char *hash)
|
||||
}
|
||||
extern int is_empty_blob_sha1(const unsigned char *sha1);
|
||||
|
||||
#define EMPTY_TREE_SHA1_HEX \
|
||||
"4b825dc642cb6eb9a060e54bf8d69288fbee4904"
|
||||
#define EMPTY_TREE_SHA1_BIN \
|
||||
"\x4b\x82\x5d\xc6\x42\xcb\x6e\xb9\xa0\x60" \
|
||||
"\xe5\x4b\xf8\xd6\x92\x88\xfb\xee\x49\x04"
|
||||
|
||||
int git_mkstemp(char *path, size_t n, const char *template);
|
||||
|
||||
/*
|
||||
@@ -572,12 +580,16 @@ extern int force_object_loose(const unsigned char *sha1, time_t mtime);
|
||||
/* just like read_sha1_file(), but non fatal in presence of bad objects */
|
||||
extern void *read_object(const unsigned char *sha1, enum object_type *type, unsigned long *size);
|
||||
|
||||
/* global flag to enable extra checks when accessing packed objects */
|
||||
extern int do_check_packed_object_crc;
|
||||
|
||||
extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned long size, const char *type);
|
||||
|
||||
extern int move_temp_to_file(const char *tmpfile, const char *filename);
|
||||
|
||||
extern int has_sha1_pack(const unsigned char *sha1, const char **ignore);
|
||||
extern int has_sha1_file(const unsigned char *sha1);
|
||||
extern int has_loose_object_nonlocal(const unsigned char *sha1);
|
||||
|
||||
extern int has_pack_file(const unsigned char *sha1);
|
||||
extern int has_pack_index(const unsigned char *sha1);
|
||||
@@ -686,7 +698,8 @@ extern struct packed_git {
|
||||
int index_version;
|
||||
time_t mtime;
|
||||
int pack_fd;
|
||||
int pack_local;
|
||||
unsigned pack_local:1,
|
||||
pack_keep:1;
|
||||
unsigned char sha1[20];
|
||||
/* something like ".git/objects/pack/xxxxx.pack" */
|
||||
char pack_name[FLEX_ARRAY]; /* more */
|
||||
@@ -758,7 +771,7 @@ extern const unsigned char *nth_packed_object_sha1(struct packed_git *, uint32_t
|
||||
extern off_t nth_packed_object_offset(const struct packed_git *, uint32_t);
|
||||
extern off_t find_pack_entry_one(const unsigned char *, struct packed_git *);
|
||||
extern void *unpack_entry(struct packed_git *, off_t, enum object_type *, unsigned long *);
|
||||
extern unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep);
|
||||
extern unsigned long unpack_object_header_buffer(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep);
|
||||
extern unsigned long get_size_from_delta(struct packed_git *, struct pack_window **, off_t);
|
||||
extern const char *packed_object_info_detail(struct packed_git *, off_t, unsigned long *, unsigned long *, unsigned int *, unsigned char *);
|
||||
extern int matches_pack_name(struct packed_git *p, const char *name);
|
||||
|
||||
@@ -213,6 +213,7 @@ static void combine_diff(const unsigned char *parent, mmfile_t *result_file,
|
||||
|
||||
parent_file.ptr = grab_blob(parent, &sz);
|
||||
parent_file.size = sz;
|
||||
memset(&xpp, 0, sizeof(xpp));
|
||||
xpp.flags = XDF_NEED_MINIMAL;
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
memset(&state, 0, sizeof(state));
|
||||
|
||||
@@ -536,12 +536,16 @@ static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
|
||||
* would normally create a console window. But
|
||||
* since we'll be redirecting std streams, we do
|
||||
* not need the console.
|
||||
* It is necessary to use DETACHED_PROCESS
|
||||
* instead of CREATE_NO_WINDOW to make ssh
|
||||
* recognize that it has no console.
|
||||
*/
|
||||
flags = CREATE_NO_WINDOW;
|
||||
flags = DETACHED_PROCESS;
|
||||
} else {
|
||||
/* There is already a console. If we specified
|
||||
* CREATE_NO_WINDOW here, too, Windows would
|
||||
* DETACHED_PROCESS here, too, Windows would
|
||||
* disassociate the child from the console.
|
||||
* The same is true for CREATE_NO_WINDOW.
|
||||
* Go figure!
|
||||
*/
|
||||
flags = 0;
|
||||
|
||||
@@ -41,6 +41,7 @@ NO_C99_FORMAT=@NO_C99_FORMAT@
|
||||
NO_STRCASESTR=@NO_STRCASESTR@
|
||||
NO_MEMMEM=@NO_MEMMEM@
|
||||
NO_STRLCPY=@NO_STRLCPY@
|
||||
NO_UINTMAX_T=@NO_UINTMAX_T@
|
||||
NO_STRTOUMAX=@NO_STRTOUMAX@
|
||||
NO_SETENV=@NO_SETENV@
|
||||
NO_UNSETENV=@NO_UNSETENV@
|
||||
@@ -50,3 +51,4 @@ OLD_ICONV=@OLD_ICONV@
|
||||
NO_DEFLATE_BOUND=@NO_DEFLATE_BOUND@
|
||||
FREAD_READS_DIRECTORIES=@FREAD_READS_DIRECTORIES@
|
||||
SNPRINTF_RETURNS_BOGUS=@SNPRINTF_RETURNS_BOGUS@
|
||||
PTHREAD_LIBS=@PTHREAD_LIBS@
|
||||
|
||||
52
configure.ac
52
configure.ac
@@ -65,7 +65,17 @@ else \
|
||||
fi \
|
||||
])# GIT_PARSE_WITH
|
||||
|
||||
|
||||
dnl
|
||||
dnl GIT_CHECK_FUNC(FUNCTION, IFTRUE, IFFALSE)
|
||||
dnl -----------------------------------------
|
||||
dnl Similar to AC_CHECK_FUNC, but on systems that do not generate
|
||||
dnl warnings for missing prototypes (e.g. FreeBSD when compiling without
|
||||
dnl -Wall), it does not work. By looking for function definition in
|
||||
dnl libraries, this problem can be worked around.
|
||||
AC_DEFUN([GIT_CHECK_FUNC],[AC_CHECK_FUNC([$1],[
|
||||
AC_SEARCH_LIBS([$1],,
|
||||
[$2],[$3])
|
||||
],[$3])])
|
||||
## Site configuration related to programs (before tests)
|
||||
## --with-PACKAGE[=ARG] and --without-PACKAGE
|
||||
#
|
||||
@@ -325,7 +335,7 @@ AC_SUBST(NO_SOCKADDR_STORAGE)
|
||||
#
|
||||
# Define NO_IPV6 if you lack IPv6 support and getaddrinfo().
|
||||
AC_CHECK_TYPE([struct addrinfo],[
|
||||
AC_CHECK_FUNC([getaddrinfo],
|
||||
GIT_CHECK_FUNC([getaddrinfo],
|
||||
[NO_IPV6=],
|
||||
[NO_IPV6=YesPlease])
|
||||
],[NO_IPV6=YesPlease],[
|
||||
@@ -419,43 +429,51 @@ AC_SUBST(SNPRINTF_RETURNS_BOGUS)
|
||||
AC_MSG_NOTICE([CHECKS for library functions])
|
||||
#
|
||||
# Define NO_STRCASESTR if you don't have strcasestr.
|
||||
AC_CHECK_FUNC(strcasestr,
|
||||
GIT_CHECK_FUNC(strcasestr,
|
||||
[NO_STRCASESTR=],
|
||||
[NO_STRCASESTR=YesPlease])
|
||||
AC_SUBST(NO_STRCASESTR)
|
||||
#
|
||||
# Define NO_MEMMEM if you don't have memmem.
|
||||
AC_CHECK_FUNC(memmem,
|
||||
GIT_CHECK_FUNC(memmem,
|
||||
[NO_MEMMEM=],
|
||||
[NO_MEMMEM=YesPlease])
|
||||
AC_SUBST(NO_MEMMEM)
|
||||
#
|
||||
# Define NO_STRLCPY if you don't have strlcpy.
|
||||
AC_CHECK_FUNC(strlcpy,
|
||||
GIT_CHECK_FUNC(strlcpy,
|
||||
[NO_STRLCPY=],
|
||||
[NO_STRLCPY=YesPlease])
|
||||
AC_SUBST(NO_STRLCPY)
|
||||
#
|
||||
# Define NO_UINTMAX_T if your platform does not have uintmax_t
|
||||
AC_CHECK_TYPE(uintmax_t,
|
||||
[NO_UINTMAX_T=],
|
||||
[NO_UINTMAX_T=YesPlease],[
|
||||
#include <inttypes.h>
|
||||
])
|
||||
AC_SUBST(NO_UINTMAX_T)
|
||||
#
|
||||
# Define NO_STRTOUMAX if you don't have strtoumax in the C library.
|
||||
AC_CHECK_FUNC(strtoumax,
|
||||
GIT_CHECK_FUNC(strtoumax,
|
||||
[NO_STRTOUMAX=],
|
||||
[NO_STRTOUMAX=YesPlease])
|
||||
AC_SUBST(NO_STRTOUMAX)
|
||||
#
|
||||
# Define NO_SETENV if you don't have setenv in the C library.
|
||||
AC_CHECK_FUNC(setenv,
|
||||
GIT_CHECK_FUNC(setenv,
|
||||
[NO_SETENV=],
|
||||
[NO_SETENV=YesPlease])
|
||||
AC_SUBST(NO_SETENV)
|
||||
#
|
||||
# Define NO_UNSETENV if you don't have unsetenv in the C library.
|
||||
AC_CHECK_FUNC(unsetenv,
|
||||
GIT_CHECK_FUNC(unsetenv,
|
||||
[NO_UNSETENV=],
|
||||
[NO_UNSETENV=YesPlease])
|
||||
AC_SUBST(NO_UNSETENV)
|
||||
#
|
||||
# Define NO_MKDTEMP if you don't have mkdtemp in the C library.
|
||||
AC_CHECK_FUNC(mkdtemp,
|
||||
GIT_CHECK_FUNC(mkdtemp,
|
||||
[NO_MKDTEMP=],
|
||||
[NO_MKDTEMP=YesPlease])
|
||||
AC_SUBST(NO_MKDTEMP)
|
||||
@@ -471,6 +489,22 @@ AC_SUBST(NO_MKDTEMP)
|
||||
#
|
||||
# Define NO_SYMLINK_HEAD if you never want .git/HEAD to be a symbolic link.
|
||||
# Enable it on Windows. By default, symrefs are still used.
|
||||
#
|
||||
# Define PTHREAD_LIBS to the linker flag used for Pthread support.
|
||||
AC_LANG_CONFTEST([AC_LANG_PROGRAM(
|
||||
[[#include <pthread.h>]],
|
||||
[[pthread_mutex_t test_mutex;]]
|
||||
)])
|
||||
${CC} -pthread conftest.c -o conftest.o > /dev/null 2>&1
|
||||
if test $? -eq 0;then
|
||||
PTHREAD_LIBS="-pthread"
|
||||
else
|
||||
${CC} -lpthread conftest.c -o conftest.o > /dev/null 2>&1
|
||||
if test $? -eq 0;then
|
||||
PTHREAD_LIBS="-lpthread"
|
||||
fi
|
||||
fi
|
||||
AC_SUBST(PTHREAD_LIBS)
|
||||
|
||||
## Site configuration (override autodetection)
|
||||
## --with-PACKAGE[=ARG] and --without-PACKAGE
|
||||
|
||||
@@ -316,8 +316,11 @@ def gitBranchExists(branch):
|
||||
stderr=subprocess.PIPE, stdout=subprocess.PIPE);
|
||||
return proc.wait() == 0;
|
||||
|
||||
_gitConfig = {}
|
||||
def gitConfig(key):
|
||||
return read_pipe("git config %s" % key, ignore_error=True).strip()
|
||||
if not _gitConfig.has_key(key):
|
||||
_gitConfig[key] = read_pipe("git config %s" % key, ignore_error=True).strip()
|
||||
return _gitConfig[key]
|
||||
|
||||
def p4BranchesInGit(branchesAreInRemotes = True):
|
||||
branches = {}
|
||||
@@ -946,7 +949,7 @@ class P4Sync(Command):
|
||||
|
||||
if includeFile:
|
||||
filesForCommit.append(f)
|
||||
if f['action'] != 'delete':
|
||||
if f['action'] not in ('delete', 'purge'):
|
||||
filesToRead.append(f)
|
||||
|
||||
filedata = []
|
||||
@@ -965,11 +968,11 @@ class P4Sync(Command):
|
||||
while j < len(filedata):
|
||||
stat = filedata[j]
|
||||
j += 1
|
||||
text = [];
|
||||
text = ''
|
||||
while j < len(filedata) and filedata[j]['code'] in ('text', 'unicode', 'binary'):
|
||||
text.append(filedata[j]['data'])
|
||||
text += filedata[j]['data']
|
||||
del filedata[j]['data']
|
||||
j += 1
|
||||
text = ''.join(text)
|
||||
|
||||
if not stat.has_key('depotFile'):
|
||||
sys.stderr.write("p4 print fails with: %s\n" % repr(stat))
|
||||
@@ -1038,7 +1041,7 @@ class P4Sync(Command):
|
||||
continue
|
||||
|
||||
relPath = self.stripRepoPath(file['path'], branchPrefixes)
|
||||
if file["action"] == "delete":
|
||||
if file["action"] in ("delete", "purge"):
|
||||
self.gitStream.write("D %s\n" % relPath)
|
||||
else:
|
||||
data = file['data']
|
||||
@@ -1077,7 +1080,7 @@ class P4Sync(Command):
|
||||
|
||||
cleanedFiles = {}
|
||||
for info in files:
|
||||
if info["action"] == "delete":
|
||||
if info["action"] in ("delete", "purge"):
|
||||
continue
|
||||
cleanedFiles[info["depotFile"]] = info["rev"]
|
||||
|
||||
@@ -1400,7 +1403,7 @@ class P4Sync(Command):
|
||||
if change > newestRevision:
|
||||
newestRevision = change
|
||||
|
||||
if info["action"] == "delete":
|
||||
if info["action"] in ("delete", "purge"):
|
||||
# don't increase the file cnt, otherwise details["depotFile123"] will have gaps!
|
||||
#fileCnt = fileCnt + 1
|
||||
continue
|
||||
|
||||
77
diff.c
77
diff.c
@@ -93,12 +93,6 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
|
||||
if (!strcmp(var, "diff.external"))
|
||||
return git_config_string(&external_diff_cmd_cfg, var, value);
|
||||
|
||||
switch (userdiff_config_porcelain(var, value)) {
|
||||
case 0: break;
|
||||
case -1: return -1;
|
||||
default: return 0;
|
||||
}
|
||||
|
||||
return git_diff_basic_config(var, value, cb);
|
||||
}
|
||||
|
||||
@@ -109,6 +103,12 @@ int git_diff_basic_config(const char *var, const char *value, void *cb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (userdiff_config(var, value)) {
|
||||
case 0: break;
|
||||
case -1: return -1;
|
||||
default: return 0;
|
||||
}
|
||||
|
||||
if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) {
|
||||
int slot = parse_diff_color_slot(var, 11);
|
||||
if (!value)
|
||||
@@ -123,12 +123,6 @@ int git_diff_basic_config(const char *var, const char *value, void *cb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (userdiff_config_basic(var, value)) {
|
||||
case 0: break;
|
||||
case -1: return -1;
|
||||
default: return 0;
|
||||
}
|
||||
|
||||
return git_color_default_config(var, value, cb);
|
||||
}
|
||||
|
||||
@@ -294,18 +288,8 @@ static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one)
|
||||
else if (diff_populate_filespec(one, 0))
|
||||
return -1;
|
||||
|
||||
diff_filespec_load_driver(one);
|
||||
if (one->driver->textconv) {
|
||||
size_t size;
|
||||
mf->ptr = run_textconv(one->driver->textconv, one, &size);
|
||||
if (!mf->ptr)
|
||||
return -1;
|
||||
mf->size = size;
|
||||
}
|
||||
else {
|
||||
mf->ptr = one->data;
|
||||
mf->size = one->size;
|
||||
}
|
||||
mf->ptr = one->data;
|
||||
mf->size = one->size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -400,6 +384,7 @@ static void diff_words_show(struct diff_words_data *diff_words)
|
||||
mmfile_t minus, plus;
|
||||
int i;
|
||||
|
||||
memset(&xpp, 0, sizeof(xpp));
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
minus.size = diff_words->minus.text.size;
|
||||
minus.ptr = xmalloc(minus.size);
|
||||
@@ -1282,7 +1267,7 @@ static void emit_binary_diff(FILE *file, mmfile_t *one, mmfile_t *two)
|
||||
emit_binary_diff_body(file, two, one);
|
||||
}
|
||||
|
||||
void diff_filespec_load_driver(struct diff_filespec *one)
|
||||
static void diff_filespec_load_driver(struct diff_filespec *one)
|
||||
{
|
||||
if (!one->driver)
|
||||
one->driver = userdiff_find_by_path(one->path);
|
||||
@@ -1323,6 +1308,16 @@ void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const
|
||||
options->b_prefix = b;
|
||||
}
|
||||
|
||||
static const char *get_textconv(struct diff_filespec *one)
|
||||
{
|
||||
if (!DIFF_FILE_VALID(one))
|
||||
return NULL;
|
||||
if (!S_ISREG(one->mode))
|
||||
return NULL;
|
||||
diff_filespec_load_driver(one);
|
||||
return one->driver->textconv;
|
||||
}
|
||||
|
||||
static void builtin_diff(const char *name_a,
|
||||
const char *name_b,
|
||||
struct diff_filespec *one,
|
||||
@@ -1337,6 +1332,7 @@ static void builtin_diff(const char *name_a,
|
||||
const char *set = diff_get_color_opt(o, DIFF_METAINFO);
|
||||
const char *reset = diff_get_color_opt(o, DIFF_RESET);
|
||||
const char *a_prefix, *b_prefix;
|
||||
const char *textconv_one = NULL, *textconv_two = NULL;
|
||||
|
||||
diff_set_mnemonic_prefix(o, "a/", "b/");
|
||||
if (DIFF_OPT_TST(o, REVERSE_DIFF)) {
|
||||
@@ -1390,8 +1386,14 @@ static void builtin_diff(const char *name_a,
|
||||
if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
|
||||
die("unable to read files to diff");
|
||||
|
||||
if (DIFF_OPT_TST(o, ALLOW_TEXTCONV)) {
|
||||
textconv_one = get_textconv(one);
|
||||
textconv_two = get_textconv(two);
|
||||
}
|
||||
|
||||
if (!DIFF_OPT_TST(o, TEXT) &&
|
||||
(diff_filespec_is_binary(one) || diff_filespec_is_binary(two))) {
|
||||
( (diff_filespec_is_binary(one) && !textconv_one) ||
|
||||
(diff_filespec_is_binary(two) && !textconv_two) )) {
|
||||
/* Quite common confusing case */
|
||||
if (mf1.size == mf2.size &&
|
||||
!memcmp(mf1.ptr, mf2.ptr, mf1.size))
|
||||
@@ -1412,10 +1414,26 @@ static void builtin_diff(const char *name_a,
|
||||
struct emit_callback ecbdata;
|
||||
const struct userdiff_funcname *pe;
|
||||
|
||||
if (textconv_one) {
|
||||
size_t size;
|
||||
mf1.ptr = run_textconv(textconv_one, one, &size);
|
||||
if (!mf1.ptr)
|
||||
die("unable to read files to diff");
|
||||
mf1.size = size;
|
||||
}
|
||||
if (textconv_two) {
|
||||
size_t size;
|
||||
mf2.ptr = run_textconv(textconv_two, two, &size);
|
||||
if (!mf2.ptr)
|
||||
die("unable to read files to diff");
|
||||
mf2.size = size;
|
||||
}
|
||||
|
||||
pe = diff_funcname_pattern(one);
|
||||
if (!pe)
|
||||
pe = diff_funcname_pattern(two);
|
||||
|
||||
memset(&xpp, 0, sizeof(xpp));
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
memset(&ecbdata, 0, sizeof(ecbdata));
|
||||
ecbdata.label_path = lbl;
|
||||
@@ -1443,6 +1461,10 @@ static void builtin_diff(const char *name_a,
|
||||
&xpp, &xecfg, &ecb);
|
||||
if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS))
|
||||
free_diff_words_data(&ecbdata);
|
||||
if (textconv_one)
|
||||
free(mf1.ptr);
|
||||
if (textconv_two)
|
||||
free(mf2.ptr);
|
||||
}
|
||||
|
||||
free_ab_and_return:
|
||||
@@ -1489,6 +1511,7 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
|
||||
xdemitconf_t xecfg;
|
||||
xdemitcb_t ecb;
|
||||
|
||||
memset(&xpp, 0, sizeof(xpp));
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
|
||||
xdi_diff_outf(&mf1, &mf2, diffstat_consume, diffstat,
|
||||
@@ -1535,6 +1558,7 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
|
||||
xdemitconf_t xecfg;
|
||||
xdemitcb_t ecb;
|
||||
|
||||
memset(&xpp, 0, sizeof(xpp));
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
xecfg.ctxlen = 1; /* at least one context line */
|
||||
xpp.flags = XDF_NEED_MINIMAL;
|
||||
@@ -2958,6 +2982,7 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
|
||||
struct diff_filepair *p = q->queue[i];
|
||||
int len1, len2;
|
||||
|
||||
memset(&xpp, 0, sizeof(xpp));
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
if (p->status == 0)
|
||||
return error("internal diff status error");
|
||||
|
||||
1
diff.h
1
diff.h
@@ -65,6 +65,7 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,
|
||||
#define DIFF_OPT_IGNORE_SUBMODULES (1 << 18)
|
||||
#define DIFF_OPT_DIRSTAT_CUMULATIVE (1 << 19)
|
||||
#define DIFF_OPT_DIRSTAT_BY_FILE (1 << 20)
|
||||
#define DIFF_OPT_ALLOW_TEXTCONV (1 << 21)
|
||||
#define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag)
|
||||
#define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag)
|
||||
#define DIFF_OPT_CLR(opts, flag) ((opts)->flags &= ~DIFF_OPT_##flag)
|
||||
|
||||
@@ -118,7 +118,7 @@ const char *get_git_work_tree(void)
|
||||
work_tree = git_work_tree_cfg;
|
||||
/* make_absolute_path also normalizes the path */
|
||||
if (work_tree && !is_absolute_path(work_tree))
|
||||
work_tree = xstrdup(make_absolute_path(git_path(work_tree)));
|
||||
work_tree = xstrdup(make_absolute_path(git_path("%s", work_tree)));
|
||||
} else if (work_tree)
|
||||
work_tree = xstrdup(make_absolute_path(work_tree));
|
||||
git_work_tree_initialized = 1;
|
||||
|
||||
2
fsck.c
2
fsck.c
@@ -326,7 +326,7 @@ int fsck_error_function(struct object *obj, int type, const char *fmt, ...)
|
||||
die("this should not happen, your snprintf is broken");
|
||||
}
|
||||
|
||||
error(sb.buf);
|
||||
error("%s", sb.buf);
|
||||
strbuf_release(&sb);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -455,7 +455,7 @@ bisect_next() {
|
||||
good=$(git for-each-ref --format='^%(objectname)' \
|
||||
"refs/bisect/good-*" | tr '\012' ' ') &&
|
||||
skip=$(git for-each-ref --format='%(objectname)' \
|
||||
"refs/bisect/skip-*" | tr '\012' ' ') &&
|
||||
"refs/bisect/skip-*" | tr '\012' ' ') || exit
|
||||
|
||||
# Maybe some merge bases must be tested first
|
||||
check_good_are_ancestors_of_bad "$bad" "$good" "$skip"
|
||||
|
||||
@@ -597,6 +597,28 @@ if {[is_Windows]} {
|
||||
if {![info exists env(DISPLAY)]} {
|
||||
set env(DISPLAY) :9999
|
||||
}
|
||||
} else {
|
||||
catch {
|
||||
image create photo gitlogo -width 16 -height 16
|
||||
|
||||
gitlogo put #33CC33 -to 7 0 9 2
|
||||
gitlogo put #33CC33 -to 4 2 12 4
|
||||
gitlogo put #33CC33 -to 7 4 9 6
|
||||
gitlogo put #CC3333 -to 4 6 12 8
|
||||
gitlogo put gray26 -to 4 9 6 10
|
||||
gitlogo put gray26 -to 3 10 6 12
|
||||
gitlogo put gray26 -to 8 9 13 11
|
||||
gitlogo put gray26 -to 8 11 10 12
|
||||
gitlogo put gray26 -to 11 11 13 14
|
||||
gitlogo put gray26 -to 3 12 5 14
|
||||
gitlogo put gray26 -to 5 13
|
||||
gitlogo put gray26 -to 10 13
|
||||
gitlogo put gray26 -to 4 14 12 15
|
||||
gitlogo put gray26 -to 5 15 11 16
|
||||
gitlogo redither
|
||||
|
||||
wm iconphoto . -default gitlogo
|
||||
}
|
||||
}
|
||||
|
||||
######################################################################
|
||||
@@ -918,19 +940,25 @@ git-version proc _parse_config {arr_name args} {
|
||||
}
|
||||
|
||||
proc load_config {include_global} {
|
||||
global repo_config global_config default_config
|
||||
global repo_config global_config system_config default_config
|
||||
|
||||
if {$include_global} {
|
||||
_parse_config system_config --system
|
||||
_parse_config global_config --global
|
||||
}
|
||||
_parse_config repo_config
|
||||
|
||||
foreach name [array names default_config] {
|
||||
if {[catch {set v $system_config($name)}]} {
|
||||
set system_config($name) $default_config($name)
|
||||
}
|
||||
}
|
||||
foreach name [array names system_config] {
|
||||
if {[catch {set v $global_config($name)}]} {
|
||||
set global_config($name) $default_config($name)
|
||||
set global_config($name) $system_config($name)
|
||||
}
|
||||
if {[catch {set v $repo_config($name)}]} {
|
||||
set repo_config($name) $default_config($name)
|
||||
set repo_config($name) $system_config($name)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -997,6 +1025,17 @@ citool {
|
||||
}
|
||||
}
|
||||
|
||||
######################################################################
|
||||
##
|
||||
## execution environment
|
||||
|
||||
set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
|
||||
|
||||
# Suggest our implementation of askpass, if none is set
|
||||
if {![info exists env(SSH_ASKPASS)]} {
|
||||
set env(SSH_ASKPASS) [gitexec git-gui--askpass]
|
||||
}
|
||||
|
||||
######################################################################
|
||||
##
|
||||
## repository setup
|
||||
@@ -1073,15 +1112,6 @@ set selected_commit_type new
|
||||
set nullid "0000000000000000000000000000000000000000"
|
||||
set nullid2 "0000000000000000000000000000000000000001"
|
||||
|
||||
set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
|
||||
|
||||
######################################################################
|
||||
|
||||
# Suggest our implementation of askpass, if none is set
|
||||
if {![info exists env(SSH_ASKPASS)]} {
|
||||
set env(SSH_ASKPASS) [gitexec git-gui--askpass]
|
||||
}
|
||||
|
||||
######################################################################
|
||||
##
|
||||
## task management
|
||||
@@ -1461,10 +1491,8 @@ proc rescan_done {fd buf after} {
|
||||
prune_selection
|
||||
unlock_index
|
||||
display_all_files
|
||||
if {$current_diff_path ne {}} reshow_diff
|
||||
if {$current_diff_path eq {}} select_first_diff
|
||||
|
||||
uplevel #0 $after
|
||||
if {$current_diff_path ne {}} { reshow_diff $after }
|
||||
if {$current_diff_path eq {}} { select_first_diff $after }
|
||||
}
|
||||
|
||||
proc prune_selection {} {
|
||||
@@ -1976,16 +2004,16 @@ proc do_rescan {} {
|
||||
}
|
||||
|
||||
proc ui_do_rescan {} {
|
||||
rescan {force_first_diff; ui_ready}
|
||||
rescan {force_first_diff ui_ready}
|
||||
}
|
||||
|
||||
proc do_commit {} {
|
||||
commit_tree
|
||||
}
|
||||
|
||||
proc next_diff {} {
|
||||
proc next_diff {{after {}}} {
|
||||
global next_diff_p next_diff_w next_diff_i
|
||||
show_diff $next_diff_p $next_diff_w {}
|
||||
show_diff $next_diff_p $next_diff_w {} {} $after
|
||||
}
|
||||
|
||||
proc find_anchor_pos {lst name} {
|
||||
@@ -2070,25 +2098,42 @@ proc next_diff_after_action {w path {lno {}} {mmask {}}} {
|
||||
}
|
||||
}
|
||||
|
||||
proc select_first_diff {} {
|
||||
proc select_first_diff {after} {
|
||||
global ui_workdir
|
||||
|
||||
if {[find_next_diff $ui_workdir {} 1 {^_?U}] ||
|
||||
[find_next_diff $ui_workdir {} 1 {[^O]$}]} {
|
||||
next_diff
|
||||
next_diff $after
|
||||
} else {
|
||||
uplevel #0 $after
|
||||
}
|
||||
}
|
||||
|
||||
proc force_first_diff {} {
|
||||
global current_diff_path
|
||||
proc force_first_diff {after} {
|
||||
global ui_workdir current_diff_path file_states
|
||||
|
||||
if {[info exists file_states($current_diff_path)]} {
|
||||
set state [lindex $file_states($current_diff_path) 0]
|
||||
|
||||
if {[string index $state 1] ne {O}} return
|
||||
} else {
|
||||
set state {OO}
|
||||
}
|
||||
|
||||
select_first_diff
|
||||
set reselect 0
|
||||
if {[string first {U} $state] >= 0} {
|
||||
# Already a conflict, do nothing
|
||||
} elseif {[find_next_diff $ui_workdir $current_diff_path {} {^_?U}]} {
|
||||
set reselect 1
|
||||
} elseif {[string index $state 1] ne {O}} {
|
||||
# Already a diff & no conflicts, do nothing
|
||||
} elseif {[find_next_diff $ui_workdir $current_diff_path {} {[^O]$}]} {
|
||||
set reselect 1
|
||||
}
|
||||
|
||||
if {$reselect} {
|
||||
next_diff $after
|
||||
} else {
|
||||
uplevel #0 $after
|
||||
}
|
||||
}
|
||||
|
||||
proc toggle_or_diff {w x y} {
|
||||
@@ -2244,6 +2289,9 @@ if {[is_enabled transport]} {
|
||||
.mbar add cascade -label [mc Merge] -menu .mbar.merge
|
||||
.mbar add cascade -label [mc Remote] -menu .mbar.remote
|
||||
}
|
||||
if {[is_enabled multicommit] || [is_enabled singlecommit]} {
|
||||
.mbar add cascade -label [mc Tools] -menu .mbar.tools
|
||||
}
|
||||
. configure -menu .mbar
|
||||
|
||||
# -- Repository Menu
|
||||
@@ -2518,6 +2566,20 @@ if {[is_MacOSX]} {
|
||||
-command do_options
|
||||
}
|
||||
|
||||
# -- Tools Menu
|
||||
#
|
||||
if {[is_enabled multicommit] || [is_enabled singlecommit]} {
|
||||
set tools_menubar .mbar.tools
|
||||
menu $tools_menubar
|
||||
$tools_menubar add separator
|
||||
$tools_menubar add command -label [mc "Add..."] -command tools_add::dialog
|
||||
$tools_menubar add command -label [mc "Remove..."] -command tools_remove::dialog
|
||||
set tools_tailcnt 3
|
||||
if {[array names repo_config guitool.*.cmd] ne {}} {
|
||||
tools_populate_all
|
||||
}
|
||||
}
|
||||
|
||||
# -- Help Menu
|
||||
#
|
||||
.mbar add cascade -label [mc Help] -menu .mbar.help
|
||||
|
||||
@@ -321,7 +321,7 @@ constructor new {i_commit i_path i_jump} {
|
||||
tk_popup $w.ctxm %X %Y
|
||||
"
|
||||
bind $i <Shift-Tab> "[list focus $w_cviewer];break"
|
||||
bind $i <Tab> "[list focus $w_cviewer];break"
|
||||
bind $i <Tab> "[cb _focus_search $w_cviewer];break"
|
||||
}
|
||||
|
||||
foreach i [concat $w_columns $w_cviewer] {
|
||||
@@ -337,10 +337,10 @@ constructor new {i_commit i_path i_jump} {
|
||||
bind $i <Control-Key-f> {catch {%W yview scroll 1 pages};break}
|
||||
}
|
||||
|
||||
bind $w_cviewer <Shift-Tab> "[list focus $w_file];break"
|
||||
bind $w_cviewer <Shift-Tab> "[cb _focus_search $w_file];break"
|
||||
bind $w_cviewer <Tab> "[list focus $w_file];break"
|
||||
bind $w_cviewer <Button-1> [list focus $w_cviewer]
|
||||
bind $w_file <Visibility> [list focus $w_file]
|
||||
bind $w_cviewer <Button-1> [list focus $w_cviewer]
|
||||
bind $w_file <Visibility> [cb _focus_search $w_file]
|
||||
bind $top <F7> [list searchbar::show $finder]
|
||||
bind $top <Escape> [list searchbar::hide $finder]
|
||||
bind $top <F3> [list searchbar::find_next $finder]
|
||||
@@ -382,6 +382,14 @@ constructor new {i_commit i_path i_jump} {
|
||||
_load $this $i_jump
|
||||
}
|
||||
|
||||
method _focus_search {win} {
|
||||
if {[searchbar::visible $finder]} {
|
||||
focus [searchbar::editor $finder]
|
||||
} else {
|
||||
focus $win
|
||||
}
|
||||
}
|
||||
|
||||
method _handle_destroy {win} {
|
||||
if {$win eq $w} {
|
||||
_kill $this
|
||||
@@ -551,7 +559,7 @@ method _read_file {fd jump} {
|
||||
} ifdeleted { catch {close $fd} }
|
||||
|
||||
method _exec_blame {cur_w cur_d options cur_s} {
|
||||
lappend options --incremental
|
||||
lappend options --incremental --encoding=utf-8
|
||||
if {$commit eq {}} {
|
||||
lappend options --contents $path
|
||||
} else {
|
||||
|
||||
@@ -43,12 +43,18 @@ constructor pick {} {
|
||||
$w.mbar.apple add command \
|
||||
-label [mc "About %s" [appname]] \
|
||||
-command do_about
|
||||
$w.mbar.apple add command \
|
||||
-label [mc "Show SSH Key"] \
|
||||
-command do_ssh_key
|
||||
} else {
|
||||
$w.mbar add cascade -label [mc Help] -menu $w.mbar.help
|
||||
menu $w.mbar.help
|
||||
$w.mbar.help add command \
|
||||
-label [mc "About %s" [appname]] \
|
||||
-command do_about
|
||||
$w.mbar.help add command \
|
||||
-label [mc "Show SSH Key"] \
|
||||
-command do_ssh_key
|
||||
}
|
||||
|
||||
wm protocol $top WM_DELETE_WINDOW exit
|
||||
|
||||
@@ -16,7 +16,7 @@ proc clear_diff {} {
|
||||
$ui_workdir tag remove in_diff 0.0 end
|
||||
}
|
||||
|
||||
proc reshow_diff {} {
|
||||
proc reshow_diff {{after {}}} {
|
||||
global file_states file_lists
|
||||
global current_diff_path current_diff_side
|
||||
global ui_diff
|
||||
@@ -30,13 +30,13 @@ proc reshow_diff {} {
|
||||
|| [lsearch -sorted -exact $file_lists($current_diff_side) $p] == -1} {
|
||||
|
||||
if {[find_next_diff $current_diff_side $p {} {[^O]}]} {
|
||||
next_diff
|
||||
next_diff $after
|
||||
} else {
|
||||
clear_diff
|
||||
}
|
||||
} else {
|
||||
set save_pos [lindex [$ui_diff yview] 0]
|
||||
show_diff $p $current_diff_side {} $save_pos
|
||||
show_diff $p $current_diff_side {} $save_pos $after
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ proc config_check_encodings {} {
|
||||
|
||||
proc save_config {} {
|
||||
global default_config font_descs
|
||||
global repo_config global_config
|
||||
global repo_config global_config system_config
|
||||
global repo_config_new global_config_new
|
||||
global ui_comm_spell
|
||||
|
||||
@@ -49,7 +49,7 @@ proc save_config {} {
|
||||
foreach name [array names default_config] {
|
||||
set value $global_config_new($name)
|
||||
if {$value ne $global_config($name)} {
|
||||
if {$value eq $default_config($name)} {
|
||||
if {$value eq $system_config($name)} {
|
||||
catch {git config --global --unset $name}
|
||||
} else {
|
||||
regsub -all "\[{}\]" $value {"} value
|
||||
@@ -284,17 +284,17 @@ proc do_options {} {
|
||||
}
|
||||
|
||||
proc do_restore_defaults {} {
|
||||
global font_descs default_config repo_config
|
||||
global font_descs default_config repo_config system_config
|
||||
global repo_config_new global_config_new
|
||||
|
||||
foreach name [array names default_config] {
|
||||
set repo_config_new($name) $default_config($name)
|
||||
set global_config_new($name) $default_config($name)
|
||||
set repo_config_new($name) $system_config($name)
|
||||
set global_config_new($name) $system_config($name)
|
||||
}
|
||||
|
||||
foreach option $font_descs {
|
||||
set name [lindex $option 0]
|
||||
set repo_config(gui.$name) $default_config(gui.$name)
|
||||
set repo_config(gui.$name) $system_config(gui.$name)
|
||||
}
|
||||
apply_config
|
||||
|
||||
|
||||
@@ -19,11 +19,11 @@ constructor new {i_w i_text args} {
|
||||
|
||||
frame $w
|
||||
label $w.l -text [mc Find:]
|
||||
entry $w.ent -textvariable ${__this}::searchstring -background lightgreen
|
||||
button $w.bn -text [mc Next] -command [cb find_next]
|
||||
button $w.bp -text [mc Prev] -command [cb find_prev]
|
||||
checkbutton $w.cs -text [mc Case-Sensitive] \
|
||||
-variable ${__this}::casesensitive -command [cb _incrsearch]
|
||||
entry $w.ent -textvariable ${__this}::searchstring -background lightgreen
|
||||
pack $w.l -side left
|
||||
pack $w.cs -side right
|
||||
pack $w.bp -side right
|
||||
@@ -35,24 +35,32 @@ constructor new {i_w i_text args} {
|
||||
|
||||
trace add variable searchstring write [cb _incrsearch_cb]
|
||||
|
||||
bind $w <Destroy> [cb delete_this]
|
||||
bind $w <Destroy> [list delete_this $this]
|
||||
return $this
|
||||
}
|
||||
|
||||
method show {} {
|
||||
if {![winfo ismapped $w]} {
|
||||
if {![visible $this]} {
|
||||
grid $w
|
||||
}
|
||||
focus -force $w.ent
|
||||
}
|
||||
|
||||
method hide {} {
|
||||
if {[winfo ismapped $w]} {
|
||||
if {[visible $this]} {
|
||||
focus $ctext
|
||||
grid remove $w
|
||||
}
|
||||
}
|
||||
|
||||
method visible {} {
|
||||
return [winfo ismapped $w]
|
||||
}
|
||||
|
||||
method editor {} {
|
||||
return $w.ent
|
||||
}
|
||||
|
||||
method _get_new_anchor {} {
|
||||
# use start of selection if it is visible,
|
||||
# or the bounds of the visible area
|
||||
|
||||
159
git-gui/lib/tools.tcl
Normal file
159
git-gui/lib/tools.tcl
Normal file
@@ -0,0 +1,159 @@
|
||||
# git-gui Tools menu implementation
|
||||
|
||||
proc tools_list {} {
|
||||
global repo_config
|
||||
|
||||
set names {}
|
||||
foreach item [array names repo_config guitool.*.cmd] {
|
||||
lappend names [string range $item 8 end-4]
|
||||
}
|
||||
return [lsort $names]
|
||||
}
|
||||
|
||||
proc tools_populate_all {} {
|
||||
global tools_menubar tools_menutbl
|
||||
global tools_tailcnt
|
||||
|
||||
set mbar_end [$tools_menubar index end]
|
||||
set mbar_base [expr {$mbar_end - $tools_tailcnt}]
|
||||
if {$mbar_base >= 0} {
|
||||
$tools_menubar delete 0 $mbar_base
|
||||
}
|
||||
|
||||
array unset tools_menutbl
|
||||
|
||||
foreach fullname [tools_list] {
|
||||
tools_populate_one $fullname
|
||||
}
|
||||
}
|
||||
|
||||
proc tools_create_item {parent args} {
|
||||
global tools_menubar tools_tailcnt
|
||||
if {$parent eq $tools_menubar} {
|
||||
set pos [expr {[$parent index end]-$tools_tailcnt+1}]
|
||||
eval [list $parent insert $pos] $args
|
||||
} else {
|
||||
eval [list $parent add] $args
|
||||
}
|
||||
}
|
||||
|
||||
proc tools_populate_one {fullname} {
|
||||
global tools_menubar tools_menutbl tools_id
|
||||
|
||||
if {![info exists tools_id]} {
|
||||
set tools_id 0
|
||||
}
|
||||
|
||||
set names [split $fullname '/']
|
||||
set parent $tools_menubar
|
||||
for {set i 0} {$i < [llength $names]-1} {incr i} {
|
||||
set subname [join [lrange $names 0 $i] '/']
|
||||
if {[info exists tools_menutbl($subname)]} {
|
||||
set parent $tools_menutbl($subname)
|
||||
} else {
|
||||
set subid $parent.t$tools_id
|
||||
tools_create_item $parent cascade \
|
||||
-label [lindex $names $i] -menu $subid
|
||||
menu $subid
|
||||
set tools_menutbl($subname) $subid
|
||||
set parent $subid
|
||||
incr tools_id
|
||||
}
|
||||
}
|
||||
|
||||
tools_create_item $parent command \
|
||||
-label [lindex $names end] \
|
||||
-command [list tools_exec $fullname]
|
||||
}
|
||||
|
||||
proc tools_exec {fullname} {
|
||||
global repo_config env current_diff_path
|
||||
global current_branch is_detached
|
||||
|
||||
if {[is_config_true "guitool.$fullname.needsfile"]} {
|
||||
if {$current_diff_path eq {}} {
|
||||
error_popup [mc "Running %s requires a selected file." $fullname]
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
catch { unset env(ARGS) }
|
||||
catch { unset env(REVISION) }
|
||||
|
||||
if {[get_config "guitool.$fullname.revprompt"] ne {} ||
|
||||
[get_config "guitool.$fullname.argprompt"] ne {}} {
|
||||
set dlg [tools_askdlg::dialog $fullname]
|
||||
if {![tools_askdlg::execute $dlg]} {
|
||||
return
|
||||
}
|
||||
} elseif {[is_config_true "guitool.$fullname.confirm"]} {
|
||||
if {[ask_popup [mc "Are you sure you want to run %s?" $fullname]] ne {yes}} {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
set env(GIT_GUITOOL) $fullname
|
||||
set env(FILENAME) $current_diff_path
|
||||
if {$is_detached} {
|
||||
set env(CUR_BRANCH) ""
|
||||
} else {
|
||||
set env(CUR_BRANCH) $current_branch
|
||||
}
|
||||
|
||||
set cmdline $repo_config(guitool.$fullname.cmd)
|
||||
if {[is_config_true "guitool.$fullname.noconsole"]} {
|
||||
tools_run_silent [list sh -c $cmdline] \
|
||||
[list tools_complete $fullname {}]
|
||||
} else {
|
||||
regsub {/} $fullname { / } title
|
||||
set w [console::new \
|
||||
[mc "Tool: %s" $title] \
|
||||
[mc "Running: %s" $cmdline]]
|
||||
console::exec $w [list sh -c $cmdline] \
|
||||
[list tools_complete $fullname $w]
|
||||
}
|
||||
|
||||
unset env(GIT_GUITOOL)
|
||||
unset env(FILENAME)
|
||||
unset env(CUR_BRANCH)
|
||||
catch { unset env(ARGS) }
|
||||
catch { unset env(REVISION) }
|
||||
}
|
||||
|
||||
proc tools_run_silent {cmd after} {
|
||||
lappend cmd 2>@1
|
||||
set fd [_open_stdout_stderr $cmd]
|
||||
|
||||
fconfigure $fd -blocking 0 -translation binary
|
||||
fileevent $fd readable [list tools_consume_input $fd $after]
|
||||
}
|
||||
|
||||
proc tools_consume_input {fd after} {
|
||||
read $fd
|
||||
if {[eof $fd]} {
|
||||
fconfigure $fd -blocking 1
|
||||
if {[catch {close $fd}]} {
|
||||
uplevel #0 $after 0
|
||||
} else {
|
||||
uplevel #0 $after 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc tools_complete {fullname w {ok 1}} {
|
||||
if {$w ne {}} {
|
||||
console::done $w $ok
|
||||
}
|
||||
|
||||
if {$ok} {
|
||||
set msg [mc "Tool completed succesfully: %s" $fullname]
|
||||
} else {
|
||||
set msg [mc "Tool failed: %s" $fullname]
|
||||
}
|
||||
|
||||
if {[is_config_true "guitool.$fullname.norescan"]} {
|
||||
ui_status $msg
|
||||
} else {
|
||||
rescan [list ui_status $msg]
|
||||
}
|
||||
}
|
||||
421
git-gui/lib/tools_dlg.tcl
Normal file
421
git-gui/lib/tools_dlg.tcl
Normal file
@@ -0,0 +1,421 @@
|
||||
# git-gui Tools menu dialogs
|
||||
|
||||
class tools_add {
|
||||
|
||||
field w ; # widget path
|
||||
field w_name ; # new remote name widget
|
||||
field w_cmd ; # new remote location widget
|
||||
|
||||
field name {}; # name of the tool
|
||||
field command {}; # command to execute
|
||||
field add_global 0; # add to the --global config
|
||||
field no_console 0; # disable using the console
|
||||
field needs_file 0; # ensure filename is set
|
||||
field confirm 0; # ask for confirmation
|
||||
field ask_branch 0; # ask for a revision
|
||||
field ask_args 0; # ask for additional args
|
||||
|
||||
constructor dialog {} {
|
||||
global repo_config
|
||||
|
||||
make_toplevel top w
|
||||
wm title $top [append "[appname] ([reponame]): " [mc "Add Tool"]]
|
||||
if {$top ne {.}} {
|
||||
wm geometry $top "+[winfo rootx .]+[winfo rooty .]"
|
||||
wm transient $top .
|
||||
}
|
||||
|
||||
label $w.header -text [mc "Add New Tool Command"] -font font_uibold
|
||||
pack $w.header -side top -fill x
|
||||
|
||||
frame $w.buttons
|
||||
checkbutton $w.buttons.global \
|
||||
-text [mc "Add globally"] \
|
||||
-variable @add_global
|
||||
pack $w.buttons.global -side left -padx 5
|
||||
button $w.buttons.create -text [mc Add] \
|
||||
-default active \
|
||||
-command [cb _add]
|
||||
pack $w.buttons.create -side right
|
||||
button $w.buttons.cancel -text [mc Cancel] \
|
||||
-command [list destroy $w]
|
||||
pack $w.buttons.cancel -side right -padx 5
|
||||
pack $w.buttons -side bottom -fill x -pady 10 -padx 10
|
||||
|
||||
labelframe $w.desc -text [mc "Tool Details"]
|
||||
|
||||
label $w.desc.name_cmnt -anchor w\
|
||||
-text [mc "Use '/' separators to create a submenu tree:"]
|
||||
grid x $w.desc.name_cmnt -sticky we -padx {0 5} -pady {0 2}
|
||||
label $w.desc.name_l -text [mc "Name:"]
|
||||
set w_name $w.desc.name_t
|
||||
entry $w_name \
|
||||
-borderwidth 1 \
|
||||
-relief sunken \
|
||||
-width 40 \
|
||||
-textvariable @name \
|
||||
-validate key \
|
||||
-validatecommand [cb _validate_name %d %S]
|
||||
grid $w.desc.name_l $w_name -sticky we -padx {0 5}
|
||||
|
||||
label $w.desc.cmd_l -text [mc "Command:"]
|
||||
set w_cmd $w.desc.cmd_t
|
||||
entry $w_cmd \
|
||||
-borderwidth 1 \
|
||||
-relief sunken \
|
||||
-width 40 \
|
||||
-textvariable @command
|
||||
grid $w.desc.cmd_l $w_cmd -sticky we -padx {0 5} -pady {0 3}
|
||||
|
||||
grid columnconfigure $w.desc 1 -weight 1
|
||||
pack $w.desc -anchor nw -fill x -pady 5 -padx 5
|
||||
|
||||
checkbutton $w.confirm \
|
||||
-text [mc "Show a dialog before running"] \
|
||||
-variable @confirm -command [cb _check_enable_dlg]
|
||||
|
||||
labelframe $w.dlg -labelwidget $w.confirm
|
||||
|
||||
checkbutton $w.dlg.askbranch \
|
||||
-text [mc "Ask the user to select a revision (sets \$REVISION)"] \
|
||||
-variable @ask_branch -state disabled
|
||||
pack $w.dlg.askbranch -anchor w -padx 15
|
||||
|
||||
checkbutton $w.dlg.askargs \
|
||||
-text [mc "Ask the user for additional arguments (sets \$ARGS)"] \
|
||||
-variable @ask_args -state disabled
|
||||
pack $w.dlg.askargs -anchor w -padx 15
|
||||
|
||||
pack $w.dlg -anchor nw -fill x -pady {0 8} -padx 5
|
||||
|
||||
checkbutton $w.noconsole \
|
||||
-text [mc "Don't show the command output window"] \
|
||||
-variable @no_console
|
||||
pack $w.noconsole -anchor w -padx 5
|
||||
|
||||
checkbutton $w.needsfile \
|
||||
-text [mc "Run only if a diff is selected (\$FILENAME not empty)"] \
|
||||
-variable @needs_file
|
||||
pack $w.needsfile -anchor w -padx 5
|
||||
|
||||
bind $w <Visibility> [cb _visible]
|
||||
bind $w <Key-Escape> [list destroy $w]
|
||||
bind $w <Key-Return> [cb _add]\;break
|
||||
tkwait window $w
|
||||
}
|
||||
|
||||
method _check_enable_dlg {} {
|
||||
if {$confirm} {
|
||||
$w.dlg.askbranch configure -state normal
|
||||
$w.dlg.askargs configure -state normal
|
||||
} else {
|
||||
$w.dlg.askbranch configure -state disabled
|
||||
$w.dlg.askargs configure -state disabled
|
||||
}
|
||||
}
|
||||
|
||||
method _add {} {
|
||||
global repo_config
|
||||
|
||||
if {$name eq {}} {
|
||||
error_popup [mc "Please supply a name for the tool."]
|
||||
focus $w_name
|
||||
return
|
||||
}
|
||||
|
||||
set item "guitool.$name.cmd"
|
||||
|
||||
if {[info exists repo_config($item)]} {
|
||||
error_popup [mc "Tool '%s' already exists." $name]
|
||||
focus $w_name
|
||||
return
|
||||
}
|
||||
|
||||
set cmd [list git config]
|
||||
if {$add_global} { lappend cmd --global }
|
||||
set items {}
|
||||
if {$no_console} { lappend items "guitool.$name.noconsole" }
|
||||
if {$needs_file} { lappend items "guitool.$name.needsfile" }
|
||||
if {$confirm} {
|
||||
if {$ask_args} { lappend items "guitool.$name.argprompt" }
|
||||
if {$ask_branch} { lappend items "guitool.$name.revprompt" }
|
||||
if {!$ask_args && !$ask_branch} {
|
||||
lappend items "guitool.$name.confirm"
|
||||
}
|
||||
}
|
||||
|
||||
if {[catch {
|
||||
eval $cmd [list $item $command]
|
||||
foreach citem $items { eval $cmd [list $citem yes] }
|
||||
} err]} {
|
||||
error_popup [mc "Could not add tool:\n%s" $err]
|
||||
} else {
|
||||
set repo_config($item) $command
|
||||
foreach citem $items { set repo_config($citem) yes }
|
||||
|
||||
tools_populate_all
|
||||
}
|
||||
|
||||
destroy $w
|
||||
}
|
||||
|
||||
method _validate_name {d S} {
|
||||
if {$d == 1} {
|
||||
if {[regexp {[~?*&\[\0\"\\\{]} $S]} {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
method _visible {} {
|
||||
grab $w
|
||||
$w_name icursor end
|
||||
focus $w_name
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class tools_remove {
|
||||
|
||||
field w ; # widget path
|
||||
field w_names ; # name list
|
||||
|
||||
constructor dialog {} {
|
||||
global repo_config global_config system_config
|
||||
|
||||
load_config 1
|
||||
|
||||
make_toplevel top w
|
||||
wm title $top [append "[appname] ([reponame]): " [mc "Remove Tool"]]
|
||||
if {$top ne {.}} {
|
||||
wm geometry $top "+[winfo rootx .]+[winfo rooty .]"
|
||||
wm transient $top .
|
||||
}
|
||||
|
||||
label $w.header -text [mc "Remove Tool Commands"] -font font_uibold
|
||||
pack $w.header -side top -fill x
|
||||
|
||||
frame $w.buttons
|
||||
button $w.buttons.create -text [mc Remove] \
|
||||
-default active \
|
||||
-command [cb _remove]
|
||||
pack $w.buttons.create -side right
|
||||
button $w.buttons.cancel -text [mc Cancel] \
|
||||
-command [list destroy $w]
|
||||
pack $w.buttons.cancel -side right -padx 5
|
||||
pack $w.buttons -side bottom -fill x -pady 10 -padx 10
|
||||
|
||||
frame $w.list
|
||||
set w_names $w.list.l
|
||||
listbox $w_names \
|
||||
-height 10 \
|
||||
-width 30 \
|
||||
-selectmode extended \
|
||||
-exportselection false \
|
||||
-yscrollcommand [list $w.list.sby set]
|
||||
scrollbar $w.list.sby -command [list $w.list.l yview]
|
||||
pack $w.list.sby -side right -fill y
|
||||
pack $w.list.l -side left -fill both -expand 1
|
||||
pack $w.list -fill both -expand 1 -pady 5 -padx 5
|
||||
|
||||
set local_cnt 0
|
||||
foreach fullname [tools_list] {
|
||||
# Cannot delete system tools
|
||||
if {[info exists system_config(guitool.$fullname.cmd)]} continue
|
||||
|
||||
$w_names insert end $fullname
|
||||
if {![info exists global_config(guitool.$fullname.cmd)]} {
|
||||
$w_names itemconfigure end -foreground blue
|
||||
incr local_cnt
|
||||
}
|
||||
}
|
||||
|
||||
if {$local_cnt > 0} {
|
||||
label $w.colorlbl -foreground blue \
|
||||
-text [mc "(Blue denotes repository-local tools)"]
|
||||
pack $w.colorlbl -fill x -pady 5 -padx 5
|
||||
}
|
||||
|
||||
bind $w <Visibility> [cb _visible]
|
||||
bind $w <Key-Escape> [list destroy $w]
|
||||
bind $w <Key-Return> [cb _remove]\;break
|
||||
tkwait window $w
|
||||
}
|
||||
|
||||
method _remove {} {
|
||||
foreach i [$w_names curselection] {
|
||||
set name [$w_names get $i]
|
||||
|
||||
catch { git config --remove-section guitool.$name }
|
||||
catch { git config --global --remove-section guitool.$name }
|
||||
}
|
||||
|
||||
load_config 0
|
||||
tools_populate_all
|
||||
|
||||
destroy $w
|
||||
}
|
||||
|
||||
method _visible {} {
|
||||
grab $w
|
||||
focus $w_names
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class tools_askdlg {
|
||||
|
||||
field w ; # widget path
|
||||
field w_rev {}; # revision browser
|
||||
field w_args {}; # arguments
|
||||
|
||||
field is_ask_args 0; # has arguments field
|
||||
field is_ask_revs 0; # has revision browser
|
||||
|
||||
field is_ok 0; # ok to start
|
||||
field argstr {}; # arguments
|
||||
|
||||
constructor dialog {fullname} {
|
||||
global M1B
|
||||
|
||||
set title [get_config "guitool.$fullname.title"]
|
||||
if {$title eq {}} {
|
||||
regsub {/} $fullname { / } title
|
||||
}
|
||||
|
||||
make_toplevel top w -autodelete 0
|
||||
wm title $top [append "[appname] ([reponame]): " $title]
|
||||
if {$top ne {.}} {
|
||||
wm geometry $top "+[winfo rootx .]+[winfo rooty .]"
|
||||
wm transient $top .
|
||||
}
|
||||
|
||||
set prompt [get_config "guitool.$fullname.prompt"]
|
||||
if {$prompt eq {}} {
|
||||
set command [get_config "guitool.$fullname.cmd"]
|
||||
set prompt [mc "Run Command: %s" $command]
|
||||
}
|
||||
|
||||
label $w.header -text $prompt -font font_uibold
|
||||
pack $w.header -side top -fill x
|
||||
|
||||
set argprompt [get_config "guitool.$fullname.argprompt"]
|
||||
set revprompt [get_config "guitool.$fullname.revprompt"]
|
||||
|
||||
set is_ask_args [expr {$argprompt ne {}}]
|
||||
set is_ask_revs [expr {$revprompt ne {}}]
|
||||
|
||||
if {$is_ask_args} {
|
||||
if {$argprompt eq {yes} || $argprompt eq {true} || $argprompt eq {1}} {
|
||||
set argprompt [mc "Arguments"]
|
||||
}
|
||||
|
||||
labelframe $w.arg -text $argprompt
|
||||
|
||||
set w_args $w.arg.txt
|
||||
entry $w_args \
|
||||
-borderwidth 1 \
|
||||
-relief sunken \
|
||||
-width 40 \
|
||||
-textvariable @argstr
|
||||
pack $w_args -padx 5 -pady 5 -fill both
|
||||
pack $w.arg -anchor nw -fill both -pady 5 -padx 5
|
||||
}
|
||||
|
||||
if {$is_ask_revs} {
|
||||
if {$revprompt eq {yes} || $revprompt eq {true} || $revprompt eq {1}} {
|
||||
set revprompt [mc "Revision"]
|
||||
}
|
||||
|
||||
if {[is_config_true "guitool.$fullname.revunmerged"]} {
|
||||
set w_rev [::choose_rev::new_unmerged $w.rev $revprompt]
|
||||
} else {
|
||||
set w_rev [::choose_rev::new $w.rev $revprompt]
|
||||
}
|
||||
|
||||
pack $w.rev -anchor nw -fill both -expand 1 -pady 5 -padx 5
|
||||
}
|
||||
|
||||
frame $w.buttons
|
||||
if {$is_ask_revs} {
|
||||
button $w.buttons.visualize \
|
||||
-text [mc Visualize] \
|
||||
-command [cb _visualize]
|
||||
pack $w.buttons.visualize -side left
|
||||
}
|
||||
button $w.buttons.ok \
|
||||
-text [mc OK] \
|
||||
-command [cb _start]
|
||||
pack $w.buttons.ok -side right
|
||||
button $w.buttons.cancel \
|
||||
-text [mc "Cancel"] \
|
||||
-command [cb _cancel]
|
||||
pack $w.buttons.cancel -side right -padx 5
|
||||
pack $w.buttons -side bottom -fill x -pady 10 -padx 10
|
||||
|
||||
bind $w <$M1B-Key-Return> [cb _start]
|
||||
bind $w <Key-Return> [cb _start]
|
||||
bind $w <Key-Escape> [cb _cancel]
|
||||
wm protocol $w WM_DELETE_WINDOW [cb _cancel]
|
||||
|
||||
bind $w <Visibility> [cb _visible]
|
||||
return $this
|
||||
}
|
||||
|
||||
method execute {} {
|
||||
tkwait window $w
|
||||
set rv $is_ok
|
||||
delete_this
|
||||
return $rv
|
||||
}
|
||||
|
||||
method _visible {} {
|
||||
grab $w
|
||||
if {$is_ask_args} {
|
||||
focus $w_args
|
||||
} elseif {$is_ask_revs} {
|
||||
$w_rev focus_filter
|
||||
}
|
||||
}
|
||||
|
||||
method _cancel {} {
|
||||
wm protocol $w WM_DELETE_WINDOW {}
|
||||
destroy $w
|
||||
}
|
||||
|
||||
method _rev {} {
|
||||
if {[catch {$w_rev commit_or_die}]} {
|
||||
return {}
|
||||
}
|
||||
return [$w_rev get]
|
||||
}
|
||||
|
||||
method _visualize {} {
|
||||
global current_branch
|
||||
set rev [_rev $this]
|
||||
if {$rev ne {}} {
|
||||
do_gitk [list --left-right "$current_branch...$rev"]
|
||||
}
|
||||
}
|
||||
|
||||
method _start {} {
|
||||
global env
|
||||
|
||||
if {$is_ask_revs} {
|
||||
set name [_rev $this]
|
||||
if {$name eq {}} {
|
||||
return
|
||||
}
|
||||
set env(REVISION) $name
|
||||
}
|
||||
|
||||
if {$is_ask_args} {
|
||||
set env(ARGS) $argstr
|
||||
}
|
||||
|
||||
set is_ok 1
|
||||
_cancel $this
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -71,19 +71,17 @@ case ",$all_into_one," in
|
||||
existing="$existing $e"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if test -z "$args"
|
||||
then
|
||||
args='--unpacked --incremental'
|
||||
elif test -n "$unpack_unreachable"
|
||||
then
|
||||
args="$args $unpack_unreachable"
|
||||
if test -n "$args" -a -n "$unpack_unreachable" -a \
|
||||
-n "$remove_redundant"
|
||||
then
|
||||
args="$args $unpack_unreachable"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
args="$args $local $quiet $no_reuse$extra"
|
||||
names=$(git pack-objects --non-empty --all --reflog $args </dev/null "$PACKTMP") ||
|
||||
names=$(git pack-objects --honor-pack-keep --non-empty --all --reflog $args </dev/null "$PACKTMP") ||
|
||||
exit 1
|
||||
if [ -z "$names" ]; then
|
||||
if test -z "$quiet"; then
|
||||
|
||||
@@ -323,7 +323,7 @@ cmd_update()
|
||||
# Only mention uninitialized submodules when its
|
||||
# path have been specified
|
||||
test "$#" != "0" &&
|
||||
say "Submodule path '$path' not initialized"
|
||||
say "Submodule path '$path' not initialized" &&
|
||||
say "Maybe you want to use 'update --init'?"
|
||||
continue
|
||||
fi
|
||||
|
||||
51
git-svn.perl
51
git-svn.perl
@@ -223,11 +223,13 @@ unless ($cmd && $cmd =~ /(?:clone|init|multi-init)$/) {
|
||||
"but it is not a directory\n";
|
||||
}
|
||||
my $git_dir = delete $ENV{GIT_DIR};
|
||||
chomp(my $cdup = command_oneline(qw/rev-parse --show-cdup/));
|
||||
unless (length $cdup) {
|
||||
die "Already at toplevel, but $git_dir ",
|
||||
"not found '$cdup'\n";
|
||||
}
|
||||
my $cdup = undef;
|
||||
git_cmd_try {
|
||||
$cdup = command_oneline(qw/rev-parse --show-cdup/);
|
||||
$git_dir = '.' unless ($cdup);
|
||||
chomp $cdup if ($cdup);
|
||||
$cdup = "." unless ($cdup && length $cdup);
|
||||
} "Already at toplevel, but $git_dir not found\n";
|
||||
chdir $cdup or die "Unable to chdir up to '$cdup'\n";
|
||||
unless (-d $git_dir) {
|
||||
die "$git_dir still not found after going to ",
|
||||
@@ -852,7 +854,7 @@ sub escape_uri_only {
|
||||
my ($uri) = @_;
|
||||
my @tmp;
|
||||
foreach (split m{/}, $uri) {
|
||||
s/([^\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg;
|
||||
s/([^~\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg;
|
||||
push @tmp, $_;
|
||||
}
|
||||
join('/', @tmp);
|
||||
@@ -1136,9 +1138,19 @@ sub get_commit_entry {
|
||||
system($editor, $commit_editmsg);
|
||||
}
|
||||
rename $commit_editmsg, $commit_msg or croak $!;
|
||||
open $log_fh, '<', $commit_msg or croak $!;
|
||||
{ local $/; chomp($log_entry{log} = <$log_fh>); }
|
||||
close $log_fh or croak $!;
|
||||
{
|
||||
# SVN requires messages to be UTF-8 when entering the repo
|
||||
local $/;
|
||||
open $log_fh, '<', $commit_msg or croak $!;
|
||||
binmode $log_fh;
|
||||
chomp($log_entry{log} = <$log_fh>);
|
||||
|
||||
if (my $enc = Git::config('i18n.commitencoding')) {
|
||||
require Encode;
|
||||
Encode::from_to($log_entry{log}, $enc, 'UTF-8');
|
||||
}
|
||||
close $log_fh or croak $!;
|
||||
}
|
||||
unlink $commit_msg;
|
||||
\%log_entry;
|
||||
}
|
||||
@@ -2273,6 +2285,14 @@ sub do_git_commit {
|
||||
}
|
||||
defined(my $pid = open3(my $msg_fh, my $out_fh, '>&STDERR', @exec))
|
||||
or croak $!;
|
||||
binmode $msg_fh;
|
||||
|
||||
# we always get UTF-8 from SVN, but we may want our commits in
|
||||
# a different encoding.
|
||||
if (my $enc = Git::config('i18n.commitencoding')) {
|
||||
require Encode;
|
||||
Encode::from_to($log_entry->{log}, 'UTF-8', $enc);
|
||||
}
|
||||
print $msg_fh $log_entry->{log} or croak $!;
|
||||
restore_commit_header_env($old_env);
|
||||
unless ($self->no_metadata) {
|
||||
@@ -3312,11 +3332,11 @@ sub change_file_prop {
|
||||
|
||||
sub apply_textdelta {
|
||||
my ($self, $fb, $exp) = @_;
|
||||
my $fh = Git::temp_acquire('svn_delta');
|
||||
my $fh = $::_repository->temp_acquire('svn_delta');
|
||||
# $fh gets auto-closed() by SVN::TxDelta::apply(),
|
||||
# (but $base does not,) so dup() it for reading in close_file
|
||||
open my $dup, '<&', $fh or croak $!;
|
||||
my $base = Git::temp_acquire('git_blob');
|
||||
my $base = $::_repository->temp_acquire('git_blob');
|
||||
if ($fb->{blob}) {
|
||||
print $base 'link ' if ($fb->{mode_a} == 120000);
|
||||
my $size = $::_repository->cat_blob($fb->{blob}, $base);
|
||||
@@ -3357,7 +3377,8 @@ sub close_file {
|
||||
warn "$path has mode 120000",
|
||||
" but is not a link\n";
|
||||
} else {
|
||||
my $tmp_fh = Git::temp_acquire('svn_hash');
|
||||
my $tmp_fh = $::_repository->temp_acquire(
|
||||
'svn_hash');
|
||||
my $res;
|
||||
while ($res = sysread($fh, my $str, 1024)) {
|
||||
my $out = syswrite($tmp_fh, $str, $res);
|
||||
@@ -3537,7 +3558,7 @@ sub repo_path {
|
||||
sub url_path {
|
||||
my ($self, $path) = @_;
|
||||
if ($self->{url} =~ m#^https?://#) {
|
||||
$path =~ s/([^a-zA-Z0-9_.-])/uc sprintf("%%%02x",ord($1))/eg;
|
||||
$path =~ s/([^~a-zA-Z0-9_.-])/uc sprintf("%%%02x",ord($1))/eg;
|
||||
}
|
||||
$self->{url} . '/' . $self->repo_path($path);
|
||||
}
|
||||
@@ -3745,7 +3766,7 @@ sub change_file_prop {
|
||||
|
||||
sub _chg_file_get_blob ($$$$) {
|
||||
my ($self, $fbat, $m, $which) = @_;
|
||||
my $fh = Git::temp_acquire("git_blob_$which");
|
||||
my $fh = $::_repository->temp_acquire("git_blob_$which");
|
||||
if ($m->{"mode_$which"} =~ /^120/) {
|
||||
print $fh 'link ' or croak $!;
|
||||
$self->change_file_prop($fbat,'svn:special','*');
|
||||
@@ -3890,7 +3911,7 @@ sub escape_uri_only {
|
||||
my ($uri) = @_;
|
||||
my @tmp;
|
||||
foreach (split m{/}, $uri) {
|
||||
s/([^\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg;
|
||||
s/([^~\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg;
|
||||
push @tmp, $_;
|
||||
}
|
||||
join('/', @tmp);
|
||||
|
||||
1037
gitk-git/gitk
1037
gitk-git/gitk
File diff suppressed because it is too large
Load Diff
@@ -166,6 +166,27 @@ Gitweb repositories
|
||||
shows repositories only if this file exists in its object database
|
||||
(if directory has the magic file named $export_ok).
|
||||
|
||||
- Finally, it is possible to specify an arbitrary perl subroutine that
|
||||
will be called for each project to determine if it can be exported.
|
||||
The subroutine receives an absolute path to the project as its only
|
||||
parameter.
|
||||
|
||||
For example, if you use mod_perl to run the script, and have dumb
|
||||
http protocol authentication configured for your repositories, you
|
||||
can use the following hook to allow access only if the user is
|
||||
authorized to read the files:
|
||||
|
||||
$export_auth_hook = sub {
|
||||
use Apache2::SubRequest ();
|
||||
use Apache2::Const -compile => qw(HTTP_OK);
|
||||
my $path = "$_[0]/HEAD";
|
||||
my $r = Apache2::RequestUtil->request;
|
||||
my $sub = $r->lookup_file($path);
|
||||
return $sub->filename eq $path
|
||||
&& $sub->status == Apache2::Const::HTTP_OK;
|
||||
};
|
||||
|
||||
|
||||
Generating projects list using gitweb
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ our $my_uri = $cgi->url(-absolute => 1);
|
||||
# if we're called with PATH_INFO, we have to strip that
|
||||
# from the URL to find our real URL
|
||||
# we make $path_info global because it's also used later on
|
||||
my $path_info = $ENV{"PATH_INFO"};
|
||||
our $path_info = $ENV{"PATH_INFO"};
|
||||
if ($path_info) {
|
||||
$my_url =~ s,\Q$path_info\E$,,;
|
||||
$my_uri =~ s,\Q$path_info\E$,,;
|
||||
@@ -95,6 +95,11 @@ our $default_projects_order = "project";
|
||||
# (only effective if this variable evaluates to true)
|
||||
our $export_ok = "++GITWEB_EXPORT_OK++";
|
||||
|
||||
# show repository only if this subroutine returns true
|
||||
# when given the path to the project, for example:
|
||||
# sub { return -e "$_[0]/git-daemon-export-ok"; }
|
||||
our $export_auth_hook = undef;
|
||||
|
||||
# only allow viewing of repositories also shown on the overview page
|
||||
our $strict_export = "++GITWEB_STRICT_EXPORT++";
|
||||
|
||||
@@ -292,10 +297,10 @@ our %feature = (
|
||||
|
||||
# The 'default' value consists of a list of triplets in the form
|
||||
# (label, link, position) where position is the label after which
|
||||
# to inster the link and link is a format string where %n expands
|
||||
# to insert the link and link is a format string where %n expands
|
||||
# to the project name, %f to the project path within the filesystem,
|
||||
# %h to the current hash (h gitweb parameter) and %b to the current
|
||||
# hash base (hb gitweb parameter).
|
||||
# hash base (hb gitweb parameter); %% expands to %.
|
||||
|
||||
# To enable system wide have in $GITWEB_CONFIG e.g.
|
||||
# $feature{'actions'}{'default'} = [('graphiclog',
|
||||
@@ -400,7 +405,8 @@ sub check_head_link {
|
||||
sub check_export_ok {
|
||||
my ($dir) = @_;
|
||||
return (check_head_link($dir) &&
|
||||
(!$export_ok || -e "$dir/$export_ok"));
|
||||
(!$export_ok || -e "$dir/$export_ok") &&
|
||||
(!$export_auth_hook || $export_auth_hook->($dir)));
|
||||
}
|
||||
|
||||
# process alternate names for backward compatibility
|
||||
@@ -436,7 +442,7 @@ $projects_list ||= $projectroot;
|
||||
# together during validation: this allows subsequent uses (e.g. href()) to be
|
||||
# agnostic of the parameter origin
|
||||
|
||||
my %input_params = ();
|
||||
our %input_params = ();
|
||||
|
||||
# input parameters are stored with the long parameter name as key. This will
|
||||
# also be used in the href subroutine to convert parameters to their CGI
|
||||
@@ -446,7 +452,7 @@ my %input_params = ();
|
||||
# XXX: Warning: If you touch this, check the search form for updating,
|
||||
# too.
|
||||
|
||||
my @cgi_param_mapping = (
|
||||
our @cgi_param_mapping = (
|
||||
project => "p",
|
||||
action => "a",
|
||||
file_name => "f",
|
||||
@@ -463,10 +469,10 @@ my @cgi_param_mapping = (
|
||||
extra_options => "opt",
|
||||
search_use_regexp => "sr",
|
||||
);
|
||||
my %cgi_param_mapping = @cgi_param_mapping;
|
||||
our %cgi_param_mapping = @cgi_param_mapping;
|
||||
|
||||
# we will also need to know the possible actions, for validation
|
||||
my %actions = (
|
||||
our %actions = (
|
||||
"blame" => \&git_blame,
|
||||
"blobdiff" => \&git_blobdiff,
|
||||
"blobdiff_plain" => \&git_blobdiff_plain,
|
||||
@@ -498,7 +504,7 @@ my %actions = (
|
||||
|
||||
# finally, we have the hash of allowed extra_options for the commands that
|
||||
# allow them
|
||||
my %allowed_options = (
|
||||
our %allowed_options = (
|
||||
"--no-merges" => [ qw(rss atom log shortlog history) ],
|
||||
);
|
||||
|
||||
@@ -616,6 +622,45 @@ sub evaluate_path_info {
|
||||
$input_params{'hash_parent'} ||= $parentrefname;
|
||||
}
|
||||
}
|
||||
|
||||
# for the snapshot action, we allow URLs in the form
|
||||
# $project/snapshot/$hash.ext
|
||||
# where .ext determines the snapshot and gets removed from the
|
||||
# passed $refname to provide the $hash.
|
||||
#
|
||||
# To be able to tell that $refname includes the format extension, we
|
||||
# require the following two conditions to be satisfied:
|
||||
# - the hash input parameter MUST have been set from the $refname part
|
||||
# of the URL (i.e. they must be equal)
|
||||
# - the snapshot format MUST NOT have been defined already (e.g. from
|
||||
# CGI parameter sf)
|
||||
# It's also useless to try any matching unless $refname has a dot,
|
||||
# so we check for that too
|
||||
if (defined $input_params{'action'} &&
|
||||
$input_params{'action'} eq 'snapshot' &&
|
||||
defined $refname && index($refname, '.') != -1 &&
|
||||
$refname eq $input_params{'hash'} &&
|
||||
!defined $input_params{'snapshot_format'}) {
|
||||
# We loop over the known snapshot formats, checking for
|
||||
# extensions. Allowed extensions are both the defined suffix
|
||||
# (which includes the initial dot already) and the snapshot
|
||||
# format key itself, with a prepended dot
|
||||
while (my ($fmt, %opt) = each %known_snapshot_formats) {
|
||||
my $hash = $refname;
|
||||
my $sfx;
|
||||
$hash =~ s/(\Q$opt{'suffix'}\E|\Q.$fmt\E)$//;
|
||||
next unless $sfx = $1;
|
||||
# a valid suffix was found, so set the snapshot format
|
||||
# and reset the hash parameter
|
||||
$input_params{'snapshot_format'} = $fmt;
|
||||
$input_params{'hash'} = $hash;
|
||||
# we also set the format suffix to the one requested
|
||||
# in the URL: this way a request for e.g. .tgz returns
|
||||
# a .tgz instead of a .tar.gz
|
||||
$known_snapshot_formats{$fmt}{'suffix'} = $sfx;
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
evaluate_path_info();
|
||||
|
||||
@@ -721,6 +766,10 @@ if (defined $searchtext) {
|
||||
our $git_dir;
|
||||
$git_dir = "$projectroot/$project" if $project;
|
||||
|
||||
# list of supported snapshot formats
|
||||
our @snapshot_fmts = gitweb_check_feature('snapshot');
|
||||
@snapshot_fmts = filter_snapshot_fmts(@snapshot_fmts);
|
||||
|
||||
# dispatch
|
||||
if (!defined $action) {
|
||||
if (defined $hash) {
|
||||
@@ -768,6 +817,7 @@ sub href (%) {
|
||||
# - action
|
||||
# - hash_parent or hash_parent_base:/file_parent
|
||||
# - hash or hash_base:/filename
|
||||
# - the snapshot_format as an appropriate suffix
|
||||
|
||||
# When the script is the root DirectoryIndex for the domain,
|
||||
# $href here would be something like http://gitweb.example.com/
|
||||
@@ -779,6 +829,10 @@ sub href (%) {
|
||||
$href .= "/".esc_url($params{'project'}) if defined $params{'project'};
|
||||
delete $params{'project'};
|
||||
|
||||
# since we destructively absorb parameters, we keep this
|
||||
# boolean that remembers if we're handling a snapshot
|
||||
my $is_snapshot = $params{'action'} eq 'snapshot';
|
||||
|
||||
# Summary just uses the project path URL, any other action is
|
||||
# added to the URL
|
||||
if (defined $params{'action'}) {
|
||||
@@ -818,6 +872,18 @@ sub href (%) {
|
||||
$href .= esc_url($params{'hash'});
|
||||
delete $params{'hash'};
|
||||
}
|
||||
|
||||
# If the action was a snapshot, we can absorb the
|
||||
# snapshot_format parameter too
|
||||
if ($is_snapshot) {
|
||||
my $fmt = $params{'snapshot_format'};
|
||||
# snapshot_format should always be defined when href()
|
||||
# is called, but just in case some code forgets, we
|
||||
# fall back to the default
|
||||
$fmt ||= $snapshot_fmts[0];
|
||||
$href .= $known_snapshot_formats{$fmt}{'suffix'};
|
||||
delete $params{'snapshot_format'};
|
||||
}
|
||||
}
|
||||
|
||||
# now encode the parameters explicitly
|
||||
@@ -853,8 +919,7 @@ sub validate_project {
|
||||
my $input = shift || return undef;
|
||||
if (!validate_pathname($input) ||
|
||||
!(-d "$projectroot/$input") ||
|
||||
!check_head_link("$projectroot/$input") ||
|
||||
($export_ok && !(-e "$projectroot/$input/$export_ok")) ||
|
||||
!check_export_ok("$projectroot/$input") ||
|
||||
($strict_export && !project_in_list($input))) {
|
||||
return undef;
|
||||
} else {
|
||||
@@ -1647,8 +1712,6 @@ sub format_diff_line {
|
||||
# linked. Pass the hash of the tree/commit to snapshot.
|
||||
sub format_snapshot_links {
|
||||
my ($hash) = @_;
|
||||
my @snapshot_fmts = gitweb_check_feature('snapshot');
|
||||
@snapshot_fmts = filter_snapshot_fmts(@snapshot_fmts);
|
||||
my $num_fmts = @snapshot_fmts;
|
||||
if ($num_fmts > 1) {
|
||||
# A parenthesized list of links bearing format names.
|
||||
@@ -3022,14 +3085,19 @@ sub git_print_page_nav {
|
||||
$arg{'tree'}{'hash_base'} = $treebase if defined $treebase;
|
||||
|
||||
my @actions = gitweb_check_feature('actions');
|
||||
my %repl = (
|
||||
'%' => '%',
|
||||
'n' => $project, # project name
|
||||
'f' => $git_dir, # project path within filesystem
|
||||
'h' => $treehead || '', # current hash ('h' parameter)
|
||||
'b' => $treebase || '', # hash base ('hb' parameter)
|
||||
);
|
||||
while (@actions) {
|
||||
my ($label, $link, $pos) = (shift(@actions), shift(@actions), shift(@actions));
|
||||
my ($label, $link, $pos) = splice(@actions,0,3);
|
||||
# insert
|
||||
@navs = map { $_ eq $pos ? ($_, $label) : $_ } @navs;
|
||||
# munch munch
|
||||
$link =~ s#%n#$project#g;
|
||||
$link =~ s#%f#$git_dir#g;
|
||||
$treehead ? $link =~ s#%h#$treehead#g : $link =~ s#%h##g;
|
||||
$treebase ? $link =~ s#%b#$treebase#g : $link =~ s#%b##g;
|
||||
$link =~ s/%([%nfhb])/$repl{$1}/g;
|
||||
$arg{$label}{'_href'} = $link;
|
||||
}
|
||||
|
||||
@@ -4850,20 +4918,17 @@ sub git_tree {
|
||||
}
|
||||
|
||||
sub git_snapshot {
|
||||
my @supported_fmts = gitweb_check_feature('snapshot');
|
||||
@supported_fmts = filter_snapshot_fmts(@supported_fmts);
|
||||
|
||||
my $format = $input_params{'snapshot_format'};
|
||||
if (!@supported_fmts) {
|
||||
if (!@snapshot_fmts) {
|
||||
die_error(403, "Snapshots not allowed");
|
||||
}
|
||||
# default to first supported snapshot format
|
||||
$format ||= $supported_fmts[0];
|
||||
$format ||= $snapshot_fmts[0];
|
||||
if ($format !~ m/^[a-z0-9]+$/) {
|
||||
die_error(400, "Invalid snapshot format parameter");
|
||||
} elsif (!exists($known_snapshot_formats{$format})) {
|
||||
die_error(400, "Unknown snapshot format");
|
||||
} elsif (!grep($_ eq $format, @supported_fmts)) {
|
||||
} elsif (!grep($_ eq $format, @snapshot_fmts)) {
|
||||
die_error(403, "Unsupported snapshot format");
|
||||
}
|
||||
|
||||
|
||||
6
grep.c
6
grep.c
@@ -514,7 +514,7 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
|
||||
if (from <= last_shown)
|
||||
from = last_shown + 1;
|
||||
if (last_shown && from != last_shown + 1)
|
||||
printf(hunk_mark);
|
||||
fputs(hunk_mark, stdout);
|
||||
while (from < lno) {
|
||||
pcl = &prev[lno-from-1];
|
||||
show_line(opt, pcl->bol, pcl->eol,
|
||||
@@ -524,7 +524,7 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
|
||||
last_shown = lno-1;
|
||||
}
|
||||
if (last_shown && lno != last_shown + 1)
|
||||
printf(hunk_mark);
|
||||
fputs(hunk_mark, stdout);
|
||||
if (!opt->count)
|
||||
show_line(opt, bol, eol, name, lno, ':');
|
||||
last_shown = last_hit = lno;
|
||||
@@ -535,7 +535,7 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
|
||||
* we need to show this line.
|
||||
*/
|
||||
if (last_shown && lno != last_shown + 1)
|
||||
printf(hunk_mark);
|
||||
fputs(hunk_mark, stdout);
|
||||
show_line(opt, bol, eol, name, lno, '-');
|
||||
last_shown = lno;
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ int main(int argc, const char **argv)
|
||||
}
|
||||
|
||||
if (errstr) {
|
||||
error (errstr);
|
||||
error("%s", errstr);
|
||||
usage_with_options(hash_object_usage, hash_object_options);
|
||||
}
|
||||
|
||||
|
||||
@@ -338,7 +338,7 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_
|
||||
base_offset = (base_offset << 7) + (c & 127);
|
||||
}
|
||||
delta_base->offset = obj->idx.offset - base_offset;
|
||||
if (delta_base->offset >= obj->idx.offset)
|
||||
if (delta_base->offset <= 0 || delta_base->offset >= obj->idx.offset)
|
||||
bad_object(obj->idx.offset, "delta base offset is out of bound");
|
||||
break;
|
||||
case OBJ_COMMIT:
|
||||
|
||||
10
log-tree.c
10
log-tree.c
@@ -52,11 +52,15 @@ static void show_parents(struct commit *commit, int abbrev)
|
||||
}
|
||||
}
|
||||
|
||||
void show_decorations(struct commit *commit)
|
||||
void show_decorations(struct rev_info *opt, struct commit *commit)
|
||||
{
|
||||
const char *prefix;
|
||||
struct name_decoration *decoration;
|
||||
|
||||
if (opt->show_source && commit->util)
|
||||
printf("\t%s", (char *) commit->util);
|
||||
if (!opt->show_decorations)
|
||||
return;
|
||||
decoration = lookup_decoration(&name_decoration, &commit->object);
|
||||
if (!decoration)
|
||||
return;
|
||||
@@ -279,7 +283,7 @@ void show_log(struct rev_info *opt)
|
||||
fputs(diff_unique_abbrev(commit->object.sha1, abbrev_commit), stdout);
|
||||
if (opt->print_parents)
|
||||
show_parents(commit, abbrev_commit);
|
||||
show_decorations(commit);
|
||||
show_decorations(opt, commit);
|
||||
if (opt->graph && !graph_is_commit_finished(opt->graph)) {
|
||||
putchar('\n');
|
||||
graph_show_remainder(opt->graph);
|
||||
@@ -352,7 +356,7 @@ void show_log(struct rev_info *opt)
|
||||
printf(" (from %s)",
|
||||
diff_unique_abbrev(parent->object.sha1,
|
||||
abbrev_commit));
|
||||
show_decorations(commit);
|
||||
show_decorations(opt, commit);
|
||||
printf("%s", diff_get_color_opt(&opt->diffopt, DIFF_RESET));
|
||||
if (opt->commit_format == CMIT_FMT_ONELINE) {
|
||||
putchar(' ');
|
||||
|
||||
@@ -12,7 +12,7 @@ int log_tree_diff_flush(struct rev_info *);
|
||||
int log_tree_commit(struct rev_info *, struct commit *);
|
||||
int log_tree_opt_parse(struct rev_info *, const char **, int);
|
||||
void show_log(struct rev_info *opt);
|
||||
void show_decorations(struct commit *commit);
|
||||
void show_decorations(struct rev_info *opt, struct commit *commit);
|
||||
void log_write_email_headers(struct rev_info *opt, const char *name,
|
||||
const char **subject_p,
|
||||
const char **extra_headers_p,
|
||||
|
||||
@@ -61,6 +61,7 @@ static int generate_common_file(mmfile_t *res, mmfile_t *f1, mmfile_t *f2)
|
||||
xdemitconf_t xecfg;
|
||||
xdemitcb_t ecb;
|
||||
|
||||
memset(&xpp, 0, sizeof(xpp));
|
||||
xpp.flags = XDF_NEED_MINIMAL;
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
xecfg.ctxlen = 3;
|
||||
|
||||
@@ -140,7 +140,8 @@ struct revindex_entry *find_pack_revindex(struct packed_git *p, off_t ofs)
|
||||
else
|
||||
lo = mi + 1;
|
||||
} while (lo < hi);
|
||||
die("internal error: pack revindex corrupt");
|
||||
error("bad offset for revindex");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void discard_revindex(void)
|
||||
|
||||
4
path.c
4
path.c
@@ -41,7 +41,7 @@ char *mksnpath(char *buf, size_t n, const char *fmt, ...)
|
||||
len = vsnprintf(buf, n, fmt, args);
|
||||
va_end(args);
|
||||
if (len >= n) {
|
||||
snprintf(buf, n, bad_path);
|
||||
strlcpy(buf, bad_path, n);
|
||||
return buf;
|
||||
}
|
||||
return cleanup_path(buf);
|
||||
@@ -63,7 +63,7 @@ static char *git_vsnpath(char *buf, size_t n, const char *fmt, va_list args)
|
||||
goto bad;
|
||||
return cleanup_path(buf);
|
||||
bad:
|
||||
snprintf(buf, n, bad_path);
|
||||
strlcpy(buf, bad_path, n);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
15
perl/Git.pm
15
perl/Git.pm
@@ -961,9 +961,7 @@ issue.
|
||||
=cut
|
||||
|
||||
sub temp_acquire {
|
||||
my ($self, $name) = _maybe_self(@_);
|
||||
|
||||
my $temp_fd = _temp_cache($name);
|
||||
my $temp_fd = _temp_cache(@_);
|
||||
|
||||
$TEMP_FILES{$temp_fd}{locked} = 1;
|
||||
$temp_fd;
|
||||
@@ -1005,7 +1003,7 @@ sub temp_release {
|
||||
}
|
||||
|
||||
sub _temp_cache {
|
||||
my ($name) = @_;
|
||||
my ($self, $name) = _maybe_self(@_);
|
||||
|
||||
_verify_require();
|
||||
|
||||
@@ -1022,9 +1020,16 @@ sub _temp_cache {
|
||||
"' was closed. Opening replacement.";
|
||||
}
|
||||
my $fname;
|
||||
|
||||
my $tmpdir;
|
||||
if (defined $self) {
|
||||
$tmpdir = $self->repo_path();
|
||||
}
|
||||
|
||||
($$temp_fd, $fname) = File::Temp->tempfile(
|
||||
'Git_XXXXXX', UNLINK => 1
|
||||
'Git_XXXXXX', UNLINK => 1, DIR => $tmpdir,
|
||||
) or throw Error::Simple("couldn't open new temp file");
|
||||
|
||||
$$temp_fd->autoflush;
|
||||
binmode $$temp_fd;
|
||||
$TEMP_FILES{$$temp_fd}{fname} = $fname;
|
||||
|
||||
@@ -1269,6 +1269,11 @@ unmap:
|
||||
die("index file corrupt");
|
||||
}
|
||||
|
||||
int is_index_unborn(struct index_state *istate)
|
||||
{
|
||||
return (!istate->cache_nr && !istate->alloc && !istate->timestamp);
|
||||
}
|
||||
|
||||
int discard_index(struct index_state *istate)
|
||||
{
|
||||
istate->cache_nr = 0;
|
||||
|
||||
9
refs.c
9
refs.c
@@ -795,10 +795,10 @@ static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char
|
||||
char *ref_file;
|
||||
const char *orig_ref = ref;
|
||||
struct ref_lock *lock;
|
||||
struct stat st;
|
||||
int last_errno = 0;
|
||||
int type, lflags;
|
||||
int mustexist = (old_sha1 && !is_null_sha1(old_sha1));
|
||||
int missing = 0;
|
||||
|
||||
lock = xcalloc(1, sizeof(struct ref_lock));
|
||||
lock->lock_fd = -1;
|
||||
@@ -826,12 +826,13 @@ static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char
|
||||
orig_ref, strerror(errno));
|
||||
goto error_return;
|
||||
}
|
||||
missing = is_null_sha1(lock->old_sha1);
|
||||
/* When the ref did not exist and we are creating it,
|
||||
* make sure there is no existing ref that is packed
|
||||
* whose name begins with our refname, nor a ref whose
|
||||
* name is a proper prefix of our refname.
|
||||
*/
|
||||
if (is_null_sha1(lock->old_sha1) &&
|
||||
if (missing &&
|
||||
!is_refname_available(ref, NULL, get_packed_refs(), 0))
|
||||
goto error_return;
|
||||
|
||||
@@ -845,7 +846,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char
|
||||
lock->ref_name = xstrdup(ref);
|
||||
lock->orig_ref_name = xstrdup(orig_ref);
|
||||
ref_file = git_path("%s", ref);
|
||||
if (lstat(ref_file, &st) && errno == ENOENT)
|
||||
if (missing)
|
||||
lock->force_write = 1;
|
||||
if ((flags & REF_NODEREF) && (type & REF_ISSYMREF))
|
||||
lock->force_write = 1;
|
||||
@@ -939,7 +940,7 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
|
||||
lock->lk->filename[i] = 0;
|
||||
path = lock->lk->filename;
|
||||
} else {
|
||||
path = git_path(refname);
|
||||
path = git_path("%s", refname);
|
||||
}
|
||||
err = unlink(path);
|
||||
if (err && errno != ENOENT) {
|
||||
|
||||
14
remote.c
14
remote.c
@@ -201,6 +201,7 @@ static void read_remotes_file(struct remote *remote)
|
||||
|
||||
if (!f)
|
||||
return;
|
||||
remote->origin = REMOTE_REMOTES;
|
||||
while (fgets(buffer, BUF_SIZE, f)) {
|
||||
int value_list;
|
||||
char *s, *p;
|
||||
@@ -261,6 +262,7 @@ static void read_branches_file(struct remote *remote)
|
||||
s++;
|
||||
if (!*s)
|
||||
return;
|
||||
remote->origin = REMOTE_BRANCHES;
|
||||
p = s + strlen(s);
|
||||
while (isspace(p[-1]))
|
||||
*--p = 0;
|
||||
@@ -297,6 +299,17 @@ static void read_branches_file(struct remote *remote)
|
||||
}
|
||||
add_url_alias(remote, p);
|
||||
add_fetch_refspec(remote, strbuf_detach(&branch, 0));
|
||||
/*
|
||||
* Cogito compatible push: push current HEAD to remote #branch
|
||||
* (master if missing)
|
||||
*/
|
||||
strbuf_init(&branch, 0);
|
||||
strbuf_addstr(&branch, "HEAD");
|
||||
if (frag)
|
||||
strbuf_addf(&branch, ":refs/heads/%s", frag);
|
||||
else
|
||||
strbuf_addstr(&branch, ":refs/heads/master");
|
||||
add_push_refspec(remote, strbuf_detach(&branch, 0));
|
||||
remote->fetch_tags = 1; /* always auto-follow */
|
||||
}
|
||||
|
||||
@@ -350,6 +363,7 @@ static int handle_config(const char *key, const char *value, void *cb)
|
||||
if (!subkey)
|
||||
return error("Config with no key for remote %s", name);
|
||||
remote = make_remote(name, subkey - name);
|
||||
remote->origin = REMOTE_CONFIG;
|
||||
if (!strcmp(subkey, ".mirror"))
|
||||
remote->mirror = git_config_bool(key, value);
|
||||
else if (!strcmp(subkey, ".skipdefaultupdate"))
|
||||
|
||||
7
remote.h
7
remote.h
@@ -1,8 +1,15 @@
|
||||
#ifndef REMOTE_H
|
||||
#define REMOTE_H
|
||||
|
||||
enum {
|
||||
REMOTE_CONFIG,
|
||||
REMOTE_REMOTES,
|
||||
REMOTE_BRANCHES
|
||||
};
|
||||
|
||||
struct remote {
|
||||
const char *name;
|
||||
int origin;
|
||||
|
||||
const char **url;
|
||||
int url_nr;
|
||||
|
||||
47
revision.c
47
revision.c
@@ -11,6 +11,7 @@
|
||||
#include "reflog-walk.h"
|
||||
#include "patch-ids.h"
|
||||
#include "decorate.h"
|
||||
#include "log-tree.h"
|
||||
|
||||
volatile show_early_output_fn_t show_early_output;
|
||||
|
||||
@@ -199,6 +200,8 @@ static struct commit *handle_commit(struct rev_info *revs, struct object *object
|
||||
mark_parents_uninteresting(commit);
|
||||
revs->limited = 1;
|
||||
}
|
||||
if (revs->show_source && !commit->util)
|
||||
commit->util = (void *) name;
|
||||
return commit;
|
||||
}
|
||||
|
||||
@@ -292,10 +295,31 @@ static void file_change(struct diff_options *options,
|
||||
DIFF_OPT_SET(options, HAS_CHANGES);
|
||||
}
|
||||
|
||||
static int rev_compare_tree(struct rev_info *revs, struct tree *t1, struct tree *t2)
|
||||
static int rev_compare_tree(struct rev_info *revs, struct commit *parent, struct commit *commit)
|
||||
{
|
||||
struct tree *t1 = parent->tree;
|
||||
struct tree *t2 = commit->tree;
|
||||
|
||||
if (!t1)
|
||||
return REV_TREE_NEW;
|
||||
|
||||
if (revs->simplify_by_decoration) {
|
||||
/*
|
||||
* If we are simplifying by decoration, then the commit
|
||||
* is worth showing if it has a tag pointing at it.
|
||||
*/
|
||||
if (lookup_decoration(&name_decoration, &commit->object))
|
||||
return REV_TREE_DIFFERENT;
|
||||
/*
|
||||
* A commit that is not pointed by a tag is uninteresting
|
||||
* if we are not limited by path. This means that you will
|
||||
* see the usual "commits that touch the paths" plus any
|
||||
* tagged commit by specifying both --simplify-by-decoration
|
||||
* and pathspec.
|
||||
*/
|
||||
if (!revs->prune_data)
|
||||
return REV_TREE_SAME;
|
||||
}
|
||||
if (!t2)
|
||||
return REV_TREE_DIFFERENT;
|
||||
tree_difference = REV_TREE_SAME;
|
||||
@@ -306,12 +330,13 @@ static int rev_compare_tree(struct rev_info *revs, struct tree *t1, struct tree
|
||||
return tree_difference;
|
||||
}
|
||||
|
||||
static int rev_same_tree_as_empty(struct rev_info *revs, struct tree *t1)
|
||||
static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit)
|
||||
{
|
||||
int retval;
|
||||
void *tree;
|
||||
unsigned long size;
|
||||
struct tree_desc empty, real;
|
||||
struct tree *t1 = commit->tree;
|
||||
|
||||
if (!t1)
|
||||
return 0;
|
||||
@@ -345,7 +370,7 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
|
||||
return;
|
||||
|
||||
if (!commit->parents) {
|
||||
if (rev_same_tree_as_empty(revs, commit->tree))
|
||||
if (rev_same_tree_as_empty(revs, commit))
|
||||
commit->object.flags |= TREESAME;
|
||||
return;
|
||||
}
|
||||
@@ -365,7 +390,7 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
|
||||
die("cannot simplify commit %s (because of %s)",
|
||||
sha1_to_hex(commit->object.sha1),
|
||||
sha1_to_hex(p->object.sha1));
|
||||
switch (rev_compare_tree(revs, p->tree, commit->tree)) {
|
||||
switch (rev_compare_tree(revs, p, commit)) {
|
||||
case REV_TREE_SAME:
|
||||
tree_same = 1;
|
||||
if (!revs->simplify_history || (p->object.flags & UNINTERESTING)) {
|
||||
@@ -385,7 +410,7 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
|
||||
|
||||
case REV_TREE_NEW:
|
||||
if (revs->remove_empty_trees &&
|
||||
rev_same_tree_as_empty(revs, p->tree)) {
|
||||
rev_same_tree_as_empty(revs, p)) {
|
||||
/* We are adding all the specified
|
||||
* paths from this parent, so the
|
||||
* history beyond this parent is not
|
||||
@@ -484,6 +509,8 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit,
|
||||
|
||||
if (parse_commit(p) < 0)
|
||||
return -1;
|
||||
if (revs->show_source && !p->util)
|
||||
p->util = commit->util;
|
||||
p->object.flags |= left_flag;
|
||||
if (!(p->object.flags & SEEN)) {
|
||||
p->object.flags |= SEEN;
|
||||
@@ -968,7 +995,7 @@ static void add_ignore_packed(struct rev_info *revs, const char *name)
|
||||
int num = ++revs->num_ignore_packed;
|
||||
|
||||
revs->ignore_packed = xrealloc(revs->ignore_packed,
|
||||
sizeof(const char **) * (num + 1));
|
||||
sizeof(const char *) * (num + 1));
|
||||
revs->ignore_packed[num-1] = name;
|
||||
revs->ignore_packed[num] = NULL;
|
||||
}
|
||||
@@ -1033,6 +1060,14 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
|
||||
revs->rewrite_parents = 1;
|
||||
revs->simplify_history = 0;
|
||||
revs->limited = 1;
|
||||
} else if (!strcmp(arg, "--simplify-by-decoration")) {
|
||||
revs->simplify_merges = 1;
|
||||
revs->rewrite_parents = 1;
|
||||
revs->simplify_history = 0;
|
||||
revs->simplify_by_decoration = 1;
|
||||
revs->limited = 1;
|
||||
revs->prune = 1;
|
||||
load_ref_decorations();
|
||||
} else if (!strcmp(arg, "--date-order")) {
|
||||
revs->lifo = 0;
|
||||
revs->topo_order = 1;
|
||||
|
||||
@@ -43,6 +43,7 @@ struct rev_info {
|
||||
lifo:1,
|
||||
topo_order:1,
|
||||
simplify_merges:1,
|
||||
simplify_by_decoration:1,
|
||||
tag_objects:1,
|
||||
tree_objects:1,
|
||||
blob_objects:1,
|
||||
@@ -53,6 +54,8 @@ struct rev_info {
|
||||
left_right:1,
|
||||
rewrite_parents:1,
|
||||
print_parents:1,
|
||||
show_source:1,
|
||||
show_decorations:1,
|
||||
reverse:1,
|
||||
reverse_output_stage:1,
|
||||
cherry_pick:1,
|
||||
|
||||
113
sha1_file.c
113
sha1_file.c
@@ -423,23 +423,30 @@ void prepare_alt_odb(void)
|
||||
read_info_alternates(get_object_directory(), 0);
|
||||
}
|
||||
|
||||
static int has_loose_object(const unsigned char *sha1)
|
||||
static int has_loose_object_local(const unsigned char *sha1)
|
||||
{
|
||||
char *name = sha1_file_name(sha1);
|
||||
struct alternate_object_database *alt;
|
||||
return !access(name, F_OK);
|
||||
}
|
||||
|
||||
if (!access(name, F_OK))
|
||||
return 1;
|
||||
int has_loose_object_nonlocal(const unsigned char *sha1)
|
||||
{
|
||||
struct alternate_object_database *alt;
|
||||
prepare_alt_odb();
|
||||
for (alt = alt_odb_list; alt; alt = alt->next) {
|
||||
name = alt->name;
|
||||
fill_sha1_path(name, sha1);
|
||||
fill_sha1_path(alt->name, sha1);
|
||||
if (!access(alt->base, F_OK))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int has_loose_object(const unsigned char *sha1)
|
||||
{
|
||||
return has_loose_object_local(sha1) ||
|
||||
has_loose_object_nonlocal(sha1);
|
||||
}
|
||||
|
||||
static unsigned int pack_used_ctr;
|
||||
static unsigned int pack_mmap_calls;
|
||||
static unsigned int peak_pack_open_windows;
|
||||
@@ -841,6 +848,11 @@ struct packed_git *add_packed_git(const char *path, int path_len, int local)
|
||||
return NULL;
|
||||
}
|
||||
memcpy(p->pack_name, path, path_len);
|
||||
|
||||
strcpy(p->pack_name + path_len, ".keep");
|
||||
if (!access(p->pack_name, F_OK))
|
||||
p->pack_keep = 1;
|
||||
|
||||
strcpy(p->pack_name + path_len, ".pack");
|
||||
if (stat(p->pack_name, &st) || !S_ISREG(st.st_mode)) {
|
||||
free(p);
|
||||
@@ -1110,7 +1122,8 @@ static int legacy_loose_object(unsigned char *map)
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep)
|
||||
unsigned long unpack_object_header_buffer(const unsigned char *buf,
|
||||
unsigned long len, enum object_type *type, unsigned long *sizep)
|
||||
{
|
||||
unsigned shift;
|
||||
unsigned char c;
|
||||
@@ -1122,10 +1135,10 @@ unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned lon
|
||||
size = c & 15;
|
||||
shift = 4;
|
||||
while (c & 0x80) {
|
||||
if (len <= used)
|
||||
return 0;
|
||||
if (sizeof(long) * 8 <= shift)
|
||||
if (len <= used || sizeof(long) * 8 <= shift) {
|
||||
error("bad object header");
|
||||
return 0;
|
||||
}
|
||||
c = buf[used++];
|
||||
size += (c & 0x7f) << shift;
|
||||
shift += 7;
|
||||
@@ -1164,7 +1177,7 @@ static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned lon
|
||||
* really worth it and we don't write it any longer. But we
|
||||
* can still read it.
|
||||
*/
|
||||
used = unpack_object_header_gently(map, mapsize, &type, &size);
|
||||
used = unpack_object_header_buffer(map, mapsize, &type, &size);
|
||||
if (!used || !valid_loose_object_type[type])
|
||||
return -1;
|
||||
map += used;
|
||||
@@ -1313,8 +1326,10 @@ unsigned long get_size_from_delta(struct packed_git *p,
|
||||
} while ((st == Z_OK || st == Z_BUF_ERROR) &&
|
||||
stream.total_out < sizeof(delta_head));
|
||||
inflateEnd(&stream);
|
||||
if ((st != Z_STREAM_END) && stream.total_out != sizeof(delta_head))
|
||||
die("delta data unpack-initial failed");
|
||||
if ((st != Z_STREAM_END) && stream.total_out != sizeof(delta_head)) {
|
||||
error("delta data unpack-initial failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Examine the initial part of the delta to figure out
|
||||
* the result size.
|
||||
@@ -1355,7 +1370,7 @@ static off_t get_delta_base(struct packed_git *p,
|
||||
base_offset = (base_offset << 7) + (c & 127);
|
||||
}
|
||||
base_offset = delta_obj_offset - base_offset;
|
||||
if (base_offset >= delta_obj_offset)
|
||||
if (base_offset <= 0 || base_offset >= delta_obj_offset)
|
||||
return 0; /* out of bound */
|
||||
*curpos += used;
|
||||
} else if (type == OBJ_REF_DELTA) {
|
||||
@@ -1381,15 +1396,32 @@ static int packed_delta_info(struct packed_git *p,
|
||||
off_t base_offset;
|
||||
|
||||
base_offset = get_delta_base(p, w_curs, &curpos, type, obj_offset);
|
||||
if (!base_offset)
|
||||
return OBJ_BAD;
|
||||
type = packed_object_info(p, base_offset, NULL);
|
||||
if (type <= OBJ_NONE) {
|
||||
struct revindex_entry *revidx;
|
||||
const unsigned char *base_sha1;
|
||||
revidx = find_pack_revindex(p, base_offset);
|
||||
if (!revidx)
|
||||
return OBJ_BAD;
|
||||
base_sha1 = nth_packed_object_sha1(p, revidx->nr);
|
||||
mark_bad_packed_object(p, base_sha1);
|
||||
type = sha1_object_info(base_sha1, NULL);
|
||||
if (type <= OBJ_NONE)
|
||||
return OBJ_BAD;
|
||||
}
|
||||
|
||||
/* We choose to only get the type of the base object and
|
||||
* ignore potentially corrupt pack file that expects the delta
|
||||
* based on a base with a wrong size. This saves tons of
|
||||
* inflate() calls.
|
||||
*/
|
||||
if (sizep)
|
||||
if (sizep) {
|
||||
*sizep = get_size_from_delta(p, w_curs, curpos);
|
||||
if (*sizep == 0)
|
||||
type = OBJ_BAD;
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
@@ -1411,10 +1443,11 @@ static int unpack_object_header(struct packed_git *p,
|
||||
* insane, so we know won't exceed what we have been given.
|
||||
*/
|
||||
base = use_pack(p, w_curs, *curpos, &left);
|
||||
used = unpack_object_header_gently(base, left, &type, sizep);
|
||||
if (!used)
|
||||
die("object offset outside of pack file");
|
||||
*curpos += used;
|
||||
used = unpack_object_header_buffer(base, left, &type, sizep);
|
||||
if (!used) {
|
||||
type = OBJ_BAD;
|
||||
} else
|
||||
*curpos += used;
|
||||
|
||||
return type;
|
||||
}
|
||||
@@ -1498,8 +1531,9 @@ static int packed_object_info(struct packed_git *p, off_t obj_offset,
|
||||
*sizep = size;
|
||||
break;
|
||||
default:
|
||||
die("pack %s contains unknown object type %d",
|
||||
p->pack_name, type);
|
||||
error("unknown object type %i at offset %"PRIuMAX" in %s",
|
||||
type, (uintmax_t)obj_offset, p->pack_name);
|
||||
type = OBJ_BAD;
|
||||
}
|
||||
unuse_pack(&w_curs);
|
||||
return type;
|
||||
@@ -1663,9 +1697,12 @@ static void *unpack_delta_entry(struct packed_git *p,
|
||||
* This is costly but should happen only in the presence
|
||||
* of a corrupted pack, and is better than failing outright.
|
||||
*/
|
||||
struct revindex_entry *revidx = find_pack_revindex(p, base_offset);
|
||||
const unsigned char *base_sha1 =
|
||||
nth_packed_object_sha1(p, revidx->nr);
|
||||
struct revindex_entry *revidx;
|
||||
const unsigned char *base_sha1;
|
||||
revidx = find_pack_revindex(p, base_offset);
|
||||
if (!revidx)
|
||||
return NULL;
|
||||
base_sha1 = nth_packed_object_sha1(p, revidx->nr);
|
||||
error("failed to read delta base object %s"
|
||||
" at offset %"PRIuMAX" from %s",
|
||||
sha1_to_hex(base_sha1), (uintmax_t)base_offset,
|
||||
@@ -1694,6 +1731,8 @@ static void *unpack_delta_entry(struct packed_git *p,
|
||||
return result;
|
||||
}
|
||||
|
||||
int do_check_packed_object_crc;
|
||||
|
||||
void *unpack_entry(struct packed_git *p, off_t obj_offset,
|
||||
enum object_type *type, unsigned long *sizep)
|
||||
{
|
||||
@@ -1701,6 +1740,19 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset,
|
||||
off_t curpos = obj_offset;
|
||||
void *data;
|
||||
|
||||
if (do_check_packed_object_crc && p->index_version > 1) {
|
||||
struct revindex_entry *revidx = find_pack_revindex(p, obj_offset);
|
||||
unsigned long len = revidx[1].offset - obj_offset;
|
||||
if (check_pack_crc(p, &w_curs, obj_offset, len, revidx->nr)) {
|
||||
const unsigned char *sha1 =
|
||||
nth_packed_object_sha1(p, revidx->nr);
|
||||
error("bad packed object CRC for %s",
|
||||
sha1_to_hex(sha1));
|
||||
mark_bad_packed_object(p, sha1);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
*type = unpack_object_header(p, &w_curs, &curpos, sizep);
|
||||
switch (*type) {
|
||||
case OBJ_OFS_DELTA:
|
||||
@@ -1954,7 +2006,14 @@ int sha1_object_info(const unsigned char *sha1, unsigned long *sizep)
|
||||
if (!find_pack_entry(sha1, &e, NULL))
|
||||
return status;
|
||||
}
|
||||
return packed_object_info(e.p, e.offset, sizep);
|
||||
|
||||
status = packed_object_info(e.p, e.offset, sizep);
|
||||
if (status < 0) {
|
||||
mark_bad_packed_object(e.p, sha1);
|
||||
status = sha1_object_info(sha1, sizep);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void *read_packed_sha1(const unsigned char *sha1,
|
||||
@@ -1996,9 +2055,7 @@ static struct cached_object {
|
||||
static int cached_object_nr, cached_object_alloc;
|
||||
|
||||
static struct cached_object empty_tree = {
|
||||
/* empty tree sha1: 4b825dc642cb6eb9a060e54bf8d69288fbee4904 */
|
||||
"\x4b\x82\x5d\xc6\x42\xcb\x6e\xb9\xa0\x60"
|
||||
"\xe5\x4b\xf8\xd6\x92\x88\xfb\xee\x49\x04",
|
||||
EMPTY_TREE_SHA1_BIN,
|
||||
OBJ_TREE,
|
||||
"",
|
||||
0
|
||||
|
||||
@@ -13,7 +13,7 @@ file if core.symlinks is false.'
|
||||
test_expect_success \
|
||||
'preparation' '
|
||||
git config core.symlinks false &&
|
||||
l=$(echo -n file | git hash-object -t blob -w --stdin) &&
|
||||
l=$(printf file | git hash-object -t blob -w --stdin) &&
|
||||
echo "120000 $l symlink" | git update-index --index-info'
|
||||
|
||||
test_expect_success \
|
||||
|
||||
18
t/t2011-checkout-invalid-head.sh
Executable file
18
t/t2011-checkout-invalid-head.sh
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='checkout switching away from an invalid branch'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success 'setup' '
|
||||
echo hello >world &&
|
||||
git add world &&
|
||||
git commit -m initial
|
||||
'
|
||||
|
||||
test_expect_success 'checkout master from invalid HEAD' '
|
||||
echo 0000000000000000000000000000000000000000 >.git/HEAD &&
|
||||
git checkout master --
|
||||
'
|
||||
|
||||
test_done
|
||||
@@ -13,12 +13,12 @@ even if a plain file is in the working tree if core.symlinks is false.'
|
||||
test_expect_success \
|
||||
'preparation' '
|
||||
git config core.symlinks false &&
|
||||
l=$(echo -n file | git hash-object -t blob -w --stdin) &&
|
||||
l=$(printf file | git hash-object -t blob -w --stdin) &&
|
||||
echo "120000 $l symlink" | git update-index --index-info'
|
||||
|
||||
test_expect_success \
|
||||
'modify the symbolic link' '
|
||||
echo -n new-file > symlink &&
|
||||
printf new-file > symlink &&
|
||||
git update-index symlink'
|
||||
|
||||
test_expect_success \
|
||||
|
||||
@@ -96,6 +96,13 @@ test_expect_success \
|
||||
git branch -d n/o/p &&
|
||||
git branch n'
|
||||
|
||||
test_expect_success \
|
||||
'see if up-to-date packed refs are preserved' \
|
||||
'git branch q &&
|
||||
git pack-refs --all --prune &&
|
||||
git update-ref refs/heads/q refs/heads/q &&
|
||||
! test -f .git/refs/heads/q'
|
||||
|
||||
test_expect_success 'pack, prune and repack' '
|
||||
git tag foo &&
|
||||
git pack-refs --all --prune &&
|
||||
|
||||
126
t/t4030-diff-textconv.sh
Executable file
126
t/t4030-diff-textconv.sh
Executable file
@@ -0,0 +1,126 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='diff.*.textconv tests'
|
||||
. ./test-lib.sh
|
||||
|
||||
find_diff() {
|
||||
sed '1,/^index /d' | sed '/^-- $/,$d'
|
||||
}
|
||||
|
||||
cat >expect.binary <<'EOF'
|
||||
Binary files a/file and b/file differ
|
||||
EOF
|
||||
|
||||
cat >expect.text <<'EOF'
|
||||
--- a/file
|
||||
+++ b/file
|
||||
@@ -1 +1,2 @@
|
||||
0
|
||||
+1
|
||||
EOF
|
||||
|
||||
cat >hexdump <<'EOF'
|
||||
#!/bin/sh
|
||||
perl -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' "$1"
|
||||
EOF
|
||||
chmod +x hexdump
|
||||
|
||||
test_expect_success 'setup binary file with history' '
|
||||
printf "\\0\\n" >file &&
|
||||
git add file &&
|
||||
git commit -m one &&
|
||||
printf "\\1\\n" >>file &&
|
||||
git add file &&
|
||||
git commit -m two
|
||||
'
|
||||
|
||||
test_expect_success 'file is considered binary by porcelain' '
|
||||
git diff HEAD^ HEAD >diff &&
|
||||
find_diff <diff >actual &&
|
||||
test_cmp expect.binary actual
|
||||
'
|
||||
|
||||
test_expect_success 'file is considered binary by plumbing' '
|
||||
git diff-tree -p HEAD^ HEAD >diff &&
|
||||
find_diff <diff >actual &&
|
||||
test_cmp expect.binary actual
|
||||
'
|
||||
|
||||
test_expect_success 'setup textconv filters' '
|
||||
echo file diff=foo >.gitattributes &&
|
||||
git config diff.foo.textconv "$PWD"/hexdump &&
|
||||
git config diff.fail.textconv false
|
||||
'
|
||||
|
||||
test_expect_success 'diff produces text' '
|
||||
git diff HEAD^ HEAD >diff &&
|
||||
find_diff <diff >actual &&
|
||||
test_cmp expect.text actual
|
||||
'
|
||||
|
||||
test_expect_success 'diff-tree produces binary' '
|
||||
git diff-tree -p HEAD^ HEAD >diff &&
|
||||
find_diff <diff >actual &&
|
||||
test_cmp expect.binary actual
|
||||
'
|
||||
|
||||
test_expect_success 'log produces text' '
|
||||
git log -1 -p >log &&
|
||||
find_diff <log >actual &&
|
||||
test_cmp expect.text actual
|
||||
'
|
||||
|
||||
test_expect_success 'format-patch produces binary' '
|
||||
git format-patch --no-binary --stdout HEAD^ >patch &&
|
||||
find_diff <patch >actual &&
|
||||
test_cmp expect.binary actual
|
||||
'
|
||||
|
||||
test_expect_success 'status -v produces text' '
|
||||
git reset --soft HEAD^ &&
|
||||
git status -v >diff &&
|
||||
find_diff <diff >actual &&
|
||||
test_cmp expect.text actual &&
|
||||
git reset --soft HEAD@{1}
|
||||
'
|
||||
|
||||
cat >expect.stat <<'EOF'
|
||||
file | Bin 2 -> 4 bytes
|
||||
1 files changed, 0 insertions(+), 0 deletions(-)
|
||||
EOF
|
||||
test_expect_success 'diffstat does not run textconv' '
|
||||
echo file diff=fail >.gitattributes &&
|
||||
git diff --stat HEAD^ HEAD >actual &&
|
||||
test_cmp expect.stat actual
|
||||
'
|
||||
# restore working setup
|
||||
echo file diff=foo >.gitattributes
|
||||
|
||||
cat >expect.typechange <<'EOF'
|
||||
--- a/file
|
||||
+++ /dev/null
|
||||
@@ -1,2 +0,0 @@
|
||||
-0
|
||||
-1
|
||||
diff --git a/file b/file
|
||||
new file mode 120000
|
||||
index ad8b3d2..67be421
|
||||
--- /dev/null
|
||||
+++ b/file
|
||||
@@ -0,0 +1 @@
|
||||
+frotz
|
||||
\ No newline at end of file
|
||||
EOF
|
||||
# make a symlink the hard way that works on symlink-challenged file systems
|
||||
test_expect_success 'textconv does not act on symlinks' '
|
||||
printf frotz > file &&
|
||||
git add file &&
|
||||
git ls-files -s | sed -e s/100644/120000/ |
|
||||
git update-index --index-info &&
|
||||
git commit -m typechange &&
|
||||
git show >diff &&
|
||||
find_diff <diff >actual &&
|
||||
test_cmp expect.typechange actual
|
||||
'
|
||||
|
||||
test_done
|
||||
@@ -368,4 +368,10 @@ test_expect_success 'index-pack with --strict' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'tolerate absurdly small packsizelimit' '
|
||||
git config pack.packSizeLimit 2 &&
|
||||
packname_9=$(git pack-objects test-9 <obj-list) &&
|
||||
test $(wc -l <obj-list) = $(ls test-9-*.pack | wc -l)
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -202,7 +202,8 @@ test_expect_success \
|
||||
|
||||
test_expect_success \
|
||||
'[index v2] 5) pack-objects refuses to reuse corrupted data' \
|
||||
'test_must_fail git pack-objects test-5 <obj-list'
|
||||
'test_must_fail git pack-objects test-5 <obj-list &&
|
||||
test_must_fail git pack-objects --no-reuse-object test-6 <obj-list'
|
||||
|
||||
test_expect_success \
|
||||
'[index v2] 6) verify-pack detects CRC mismatch' \
|
||||
|
||||
@@ -47,11 +47,17 @@ zeros () {
|
||||
done | tr x '\0'
|
||||
}
|
||||
|
||||
do_repack() {
|
||||
pack=`printf "$blob_1\n$blob_2\n$blob_3\n" |
|
||||
git pack-objects $@ .git/objects/pack/pack` &&
|
||||
pack=".git/objects/pack/pack-${pack}"
|
||||
}
|
||||
|
||||
do_corrupt_object() {
|
||||
ofs=`git show-index < ${pack}.idx | grep $1 | cut -f1 -d" "` &&
|
||||
ofs=$(($ofs + $2)) &&
|
||||
chmod +w ${pack}.pack &&
|
||||
zeros | dd of=${pack}.pack count=1 bs=1 conv=notrunc seek=$ofs &&
|
||||
dd of=${pack}.pack count=1 bs=1 conv=notrunc seek=$ofs &&
|
||||
test_must_fail git verify-pack ${pack}.pack
|
||||
}
|
||||
|
||||
@@ -66,7 +72,7 @@ test_expect_success \
|
||||
|
||||
test_expect_success \
|
||||
'create corruption in header of first object' \
|
||||
'do_corrupt_object $blob_1 0 &&
|
||||
'do_corrupt_object $blob_1 0 < /dev/zero &&
|
||||
test_must_fail git cat-file blob $blob_1 > /dev/null &&
|
||||
test_must_fail git cat-file blob $blob_2 > /dev/null &&
|
||||
test_must_fail git cat-file blob $blob_3 > /dev/null'
|
||||
@@ -125,7 +131,7 @@ test_expect_success \
|
||||
'create corruption in header of first delta' \
|
||||
'create_new_pack &&
|
||||
git prune-packed &&
|
||||
do_corrupt_object $blob_2 0 &&
|
||||
do_corrupt_object $blob_2 0 < /dev/zero &&
|
||||
git cat-file blob $blob_1 > /dev/null &&
|
||||
test_must_fail git cat-file blob $blob_2 > /dev/null &&
|
||||
test_must_fail git cat-file blob $blob_3 > /dev/null'
|
||||
@@ -139,6 +145,15 @@ test_expect_success \
|
||||
git cat-file blob $blob_2 > /dev/null &&
|
||||
git cat-file blob $blob_3 > /dev/null'
|
||||
|
||||
test_expect_success \
|
||||
'... and then a repack "clears" the corruption' \
|
||||
'do_repack &&
|
||||
git prune-packed &&
|
||||
git verify-pack ${pack}.pack &&
|
||||
git cat-file blob $blob_1 > /dev/null &&
|
||||
git cat-file blob $blob_2 > /dev/null &&
|
||||
git cat-file blob $blob_3 > /dev/null'
|
||||
|
||||
test_expect_success \
|
||||
'create corruption in data of first delta' \
|
||||
'create_new_pack &&
|
||||
@@ -158,11 +173,20 @@ test_expect_success \
|
||||
git cat-file blob $blob_2 > /dev/null &&
|
||||
git cat-file blob $blob_3 > /dev/null'
|
||||
|
||||
test_expect_success \
|
||||
'... and then a repack "clears" the corruption' \
|
||||
'do_repack &&
|
||||
git prune-packed &&
|
||||
git verify-pack ${pack}.pack &&
|
||||
git cat-file blob $blob_1 > /dev/null &&
|
||||
git cat-file blob $blob_2 > /dev/null &&
|
||||
git cat-file blob $blob_3 > /dev/null'
|
||||
|
||||
test_expect_success \
|
||||
'corruption in delta base reference of first delta (OBJ_REF_DELTA)' \
|
||||
'create_new_pack &&
|
||||
git prune-packed &&
|
||||
do_corrupt_object $blob_2 2 &&
|
||||
do_corrupt_object $blob_2 2 < /dev/zero &&
|
||||
git cat-file blob $blob_1 > /dev/null &&
|
||||
test_must_fail git cat-file blob $blob_2 > /dev/null &&
|
||||
test_must_fail git cat-file blob $blob_3 > /dev/null'
|
||||
@@ -177,17 +201,75 @@ test_expect_success \
|
||||
git cat-file blob $blob_3 > /dev/null'
|
||||
|
||||
test_expect_success \
|
||||
'corruption in delta base reference of first delta (OBJ_OFS_DELTA)' \
|
||||
'... and then a repack "clears" the corruption' \
|
||||
'do_repack &&
|
||||
git prune-packed &&
|
||||
git verify-pack ${pack}.pack &&
|
||||
git cat-file blob $blob_1 > /dev/null &&
|
||||
git cat-file blob $blob_2 > /dev/null &&
|
||||
git cat-file blob $blob_3 > /dev/null'
|
||||
|
||||
test_expect_success \
|
||||
'corruption #0 in delta base reference of first delta (OBJ_OFS_DELTA)' \
|
||||
'create_new_pack --delta-base-offset &&
|
||||
git prune-packed &&
|
||||
do_corrupt_object $blob_2 2 &&
|
||||
do_corrupt_object $blob_2 2 < /dev/zero &&
|
||||
git cat-file blob $blob_1 > /dev/null &&
|
||||
test_must_fail git cat-file blob $blob_2 > /dev/null &&
|
||||
test_must_fail git cat-file blob $blob_3 > /dev/null'
|
||||
|
||||
test_expect_success \
|
||||
'... and a redundant pack allows for full recovery too' \
|
||||
'... but having a loose copy allows for full recovery' \
|
||||
'mv ${pack}.idx tmp &&
|
||||
git hash-object -t blob -w file_2 &&
|
||||
mv tmp ${pack}.idx &&
|
||||
git cat-file blob $blob_1 > /dev/null &&
|
||||
git cat-file blob $blob_2 > /dev/null &&
|
||||
git cat-file blob $blob_3 > /dev/null'
|
||||
|
||||
test_expect_success \
|
||||
'... and then a repack "clears" the corruption' \
|
||||
'do_repack --delta-base-offset &&
|
||||
git prune-packed &&
|
||||
git verify-pack ${pack}.pack &&
|
||||
git cat-file blob $blob_1 > /dev/null &&
|
||||
git cat-file blob $blob_2 > /dev/null &&
|
||||
git cat-file blob $blob_3 > /dev/null'
|
||||
|
||||
test_expect_success \
|
||||
'corruption #1 in delta base reference of first delta (OBJ_OFS_DELTA)' \
|
||||
'create_new_pack --delta-base-offset &&
|
||||
git prune-packed &&
|
||||
printf "\001" | do_corrupt_object $blob_2 2 &&
|
||||
git cat-file blob $blob_1 > /dev/null &&
|
||||
test_must_fail git cat-file blob $blob_2 > /dev/null &&
|
||||
test_must_fail git cat-file blob $blob_3 > /dev/null'
|
||||
|
||||
test_expect_success \
|
||||
'... but having a loose copy allows for full recovery' \
|
||||
'mv ${pack}.idx tmp &&
|
||||
git hash-object -t blob -w file_2 &&
|
||||
mv tmp ${pack}.idx &&
|
||||
git cat-file blob $blob_1 > /dev/null &&
|
||||
git cat-file blob $blob_2 > /dev/null &&
|
||||
git cat-file blob $blob_3 > /dev/null'
|
||||
|
||||
test_expect_success \
|
||||
'... and then a repack "clears" the corruption' \
|
||||
'do_repack --delta-base-offset &&
|
||||
git prune-packed &&
|
||||
git verify-pack ${pack}.pack &&
|
||||
git cat-file blob $blob_1 > /dev/null &&
|
||||
git cat-file blob $blob_2 > /dev/null &&
|
||||
git cat-file blob $blob_3 > /dev/null'
|
||||
|
||||
test_expect_success \
|
||||
'... and a redundant pack allows for full recovery too' \
|
||||
'do_corrupt_object $blob_2 2 < /dev/zero &&
|
||||
git cat-file blob $blob_1 > /dev/null &&
|
||||
test_must_fail git cat-file blob $blob_2 > /dev/null &&
|
||||
test_must_fail git cat-file blob $blob_3 > /dev/null &&
|
||||
mv ${pack}.idx tmp &&
|
||||
git hash-object -t blob -w file_1 &&
|
||||
git hash-object -t blob -w file_2 &&
|
||||
printf "$blob_1\n$blob_2\n" | git pack-objects .git/objects/pack/pack &&
|
||||
|
||||
@@ -103,7 +103,7 @@ unset GIT_CONFIG GIT_CONFIG_LOCAL
|
||||
HOME=`pwd`/no-such-directory
|
||||
export HOME ;# this way we force the victim/.git/config to be used.
|
||||
|
||||
test_expect_failure \
|
||||
test_expect_success \
|
||||
'pushing a delete should be denied with denyDeletes' '
|
||||
cd victim &&
|
||||
git config receive.denyDeletes true &&
|
||||
|
||||
@@ -331,4 +331,52 @@ test_expect_success 'reject adding remote with an invalid name' '
|
||||
|
||||
'
|
||||
|
||||
# The first three test if the tracking branches are properly renamed,
|
||||
# the last two ones check if the config is updated.
|
||||
|
||||
test_expect_success 'rename a remote' '
|
||||
|
||||
git clone one four &&
|
||||
(cd four &&
|
||||
git remote rename origin upstream &&
|
||||
rmdir .git/refs/remotes/origin &&
|
||||
test "$(git symbolic-ref refs/remotes/upstream/HEAD)" = "refs/remotes/upstream/master" &&
|
||||
test "$(git rev-parse upstream/master)" = "$(git rev-parse master)" &&
|
||||
test "$(git config remote.upstream.fetch)" = "+refs/heads/*:refs/remotes/upstream/*" &&
|
||||
test "$(git config branch.master.remote)" = "upstream")
|
||||
|
||||
'
|
||||
|
||||
cat > remotes_origin << EOF
|
||||
URL: $(pwd)/one
|
||||
Push: refs/heads/master:refs/heads/upstream
|
||||
Pull: refs/heads/master:refs/heads/origin
|
||||
EOF
|
||||
|
||||
test_expect_success 'migrate a remote from named file in $GIT_DIR/remotes' '
|
||||
git clone one five &&
|
||||
origin_url=$(pwd)/one &&
|
||||
(cd five &&
|
||||
git remote rm origin &&
|
||||
mkdir -p .git/remotes &&
|
||||
cat ../remotes_origin > .git/remotes/origin &&
|
||||
git remote rename origin origin &&
|
||||
! test -f .git/remotes/origin &&
|
||||
test "$(git config remote.origin.url)" = "$origin_url" &&
|
||||
test "$(git config remote.origin.push)" = "refs/heads/master:refs/heads/upstream" &&
|
||||
test "$(git config remote.origin.fetch)" = "refs/heads/master:refs/heads/origin")
|
||||
'
|
||||
|
||||
test_expect_success 'migrate a remote from named file in $GIT_DIR/branches' '
|
||||
git clone one six &&
|
||||
origin_url=$(pwd)/one &&
|
||||
(cd six &&
|
||||
git remote rm origin &&
|
||||
echo "$origin_url" > .git/branches/origin &&
|
||||
git remote rename origin origin &&
|
||||
! test -f .git/branches/origin &&
|
||||
test "$(git config remote.origin.url)" = "$origin_url" &&
|
||||
test "$(git config remote.origin.fetch)" = "refs/heads/master:refs/heads/origin")
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -39,6 +39,11 @@ mk_test () {
|
||||
)
|
||||
}
|
||||
|
||||
mk_child() {
|
||||
rm -rf "$1" &&
|
||||
git clone testrepo "$1"
|
||||
}
|
||||
|
||||
check_push_result () {
|
||||
(
|
||||
cd testrepo &&
|
||||
@@ -425,29 +430,47 @@ test_expect_success 'push with dry-run' '
|
||||
|
||||
test_expect_success 'push updates local refs' '
|
||||
|
||||
rm -rf parent child &&
|
||||
mkdir parent &&
|
||||
(cd parent && git init &&
|
||||
echo one >foo && git add foo && git commit -m one) &&
|
||||
git clone parent child &&
|
||||
mk_test heads/master &&
|
||||
mk_child child &&
|
||||
(cd child &&
|
||||
echo two >foo && git commit -a -m two &&
|
||||
git pull .. master &&
|
||||
git push &&
|
||||
test $(git rev-parse master) = $(git rev-parse remotes/origin/master))
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'push updates up-to-date local refs' '
|
||||
|
||||
mk_test heads/master &&
|
||||
mk_child child1 &&
|
||||
mk_child child2 &&
|
||||
(cd child1 && git pull .. master && git push) &&
|
||||
(cd child2 &&
|
||||
git pull ../child1 master &&
|
||||
git push &&
|
||||
test $(git rev-parse master) = $(git rev-parse remotes/origin/master))
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'push preserves up-to-date packed refs' '
|
||||
|
||||
mk_test heads/master &&
|
||||
mk_child child &&
|
||||
(cd child &&
|
||||
git push &&
|
||||
! test -f .git/refs/remotes/origin/master)
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'push does not update local refs on failure' '
|
||||
|
||||
rm -rf parent child &&
|
||||
mkdir parent &&
|
||||
(cd parent && git init &&
|
||||
echo one >foo && git add foo && git commit -m one &&
|
||||
echo exit 1 >.git/hooks/pre-receive &&
|
||||
chmod +x .git/hooks/pre-receive) &&
|
||||
git clone parent child &&
|
||||
mk_test heads/master &&
|
||||
mk_child child &&
|
||||
mkdir testrepo/.git/hooks &&
|
||||
echo exit 1 >testrepo/.git/hooks/pre-receive &&
|
||||
chmod +x testrepo/.git/hooks/pre-receive &&
|
||||
(cd child &&
|
||||
echo two >foo && git commit -a -m two &&
|
||||
git pull .. master
|
||||
test_must_fail git push &&
|
||||
test $(git rev-parse master) != \
|
||||
$(git rev-parse remotes/origin/master))
|
||||
@@ -456,11 +479,98 @@ test_expect_success 'push does not update local refs on failure' '
|
||||
|
||||
test_expect_success 'allow deleting an invalid remote ref' '
|
||||
|
||||
pwd &&
|
||||
mk_test heads/master &&
|
||||
rm -f testrepo/.git/objects/??/* &&
|
||||
git push testrepo :refs/heads/master &&
|
||||
(cd testrepo && test_must_fail git rev-parse --verify refs/heads/master)
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'warn on push to HEAD of non-bare repository' '
|
||||
mk_test heads/master
|
||||
(cd testrepo &&
|
||||
git checkout master &&
|
||||
git config receive.denyCurrentBranch warn) &&
|
||||
git push testrepo master 2>stderr &&
|
||||
grep "warning.*this may cause confusion" stderr
|
||||
'
|
||||
|
||||
test_expect_success 'deny push to HEAD of non-bare repository' '
|
||||
mk_test heads/master
|
||||
(cd testrepo &&
|
||||
git checkout master &&
|
||||
git config receive.denyCurrentBranch true) &&
|
||||
test_must_fail git push testrepo master
|
||||
'
|
||||
|
||||
test_expect_success 'allow push to HEAD of bare repository (bare)' '
|
||||
mk_test heads/master
|
||||
(cd testrepo &&
|
||||
git checkout master &&
|
||||
git config receive.denyCurrentBranch true &&
|
||||
git config core.bare true) &&
|
||||
git push testrepo master 2>stderr &&
|
||||
! grep "warning.*this may cause confusion" stderr
|
||||
'
|
||||
|
||||
test_expect_success 'allow push to HEAD of non-bare repository (config)' '
|
||||
mk_test heads/master
|
||||
(cd testrepo &&
|
||||
git checkout master &&
|
||||
git config receive.denyCurrentBranch false
|
||||
) &&
|
||||
git push testrepo master 2>stderr &&
|
||||
! grep "warning.*this may cause confusion" stderr
|
||||
'
|
||||
|
||||
test_expect_success 'fetch with branches' '
|
||||
mk_empty &&
|
||||
git branch second $the_first_commit &&
|
||||
git checkout second &&
|
||||
echo ".." > testrepo/.git/branches/branch1 &&
|
||||
(cd testrepo &&
|
||||
git fetch branch1 &&
|
||||
r=$(git show-ref -s --verify refs/heads/branch1) &&
|
||||
test "z$r" = "z$the_commit" &&
|
||||
test 1 = $(git for-each-ref refs/heads | wc -l)
|
||||
) &&
|
||||
git checkout master
|
||||
'
|
||||
|
||||
test_expect_success 'fetch with branches containing #' '
|
||||
mk_empty &&
|
||||
echo "..#second" > testrepo/.git/branches/branch2 &&
|
||||
(cd testrepo &&
|
||||
git fetch branch2 &&
|
||||
r=$(git show-ref -s --verify refs/heads/branch2) &&
|
||||
test "z$r" = "z$the_first_commit" &&
|
||||
test 1 = $(git for-each-ref refs/heads | wc -l)
|
||||
) &&
|
||||
git checkout master
|
||||
'
|
||||
|
||||
test_expect_success 'push with branches' '
|
||||
mk_empty &&
|
||||
git checkout second &&
|
||||
echo "testrepo" > .git/branches/branch1 &&
|
||||
git push branch1 &&
|
||||
(cd testrepo &&
|
||||
r=$(git show-ref -s --verify refs/heads/master) &&
|
||||
test "z$r" = "z$the_first_commit" &&
|
||||
test 1 = $(git for-each-ref refs/heads | wc -l)
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'push with branches containing #' '
|
||||
mk_empty &&
|
||||
echo "testrepo#branch3" > .git/branches/branch2 &&
|
||||
git push branch2 &&
|
||||
(cd testrepo &&
|
||||
r=$(git show-ref -s --verify refs/heads/branch3) &&
|
||||
test "z$r" = "z$the_first_commit" &&
|
||||
test 1 = $(git for-each-ref refs/heads | wc -l)
|
||||
) &&
|
||||
git checkout master
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -18,11 +18,11 @@ git add file &&
|
||||
git commit -m initial &&
|
||||
git branch b-symlink &&
|
||||
git branch b-file &&
|
||||
l=$(echo -n file | git hash-object -t blob -w --stdin) &&
|
||||
l=$(printf file | git hash-object -t blob -w --stdin) &&
|
||||
echo "120000 $l symlink" | git update-index --index-info &&
|
||||
git commit -m master &&
|
||||
git checkout b-symlink &&
|
||||
l=$(echo -n file-different | git hash-object -t blob -w --stdin) &&
|
||||
l=$(printf file-different | git hash-object -t blob -w --stdin) &&
|
||||
echo "120000 $l symlink" | git update-index --index-info &&
|
||||
git commit -m b-symlink &&
|
||||
git checkout b-file &&
|
||||
|
||||
@@ -1091,4 +1091,15 @@ test_expect_success 'filename for the message is relative to cwd' '
|
||||
git cat-file tag tag-from-subdir-2 | grep "in sub directory"
|
||||
'
|
||||
|
||||
# mixing modes and options:
|
||||
|
||||
test_expect_success 'mixing incompatibles modes and options is forbidden' '
|
||||
test_must_fail git tag -a
|
||||
test_must_fail git tag -l -v
|
||||
test_must_fail git tag -n 100
|
||||
test_must_fail git tag -l -m msg
|
||||
test_must_fail git tag -l -F some file
|
||||
test_must_fail git tag -v -s
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -89,6 +89,14 @@ test_expect_success 'verbose' '
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'verbose respects diff config' '
|
||||
|
||||
git config color.diff always &&
|
||||
git status -v >actual &&
|
||||
grep "\[1mdiff --git" actual &&
|
||||
git config --unset color.diff
|
||||
'
|
||||
|
||||
test_expect_success 'cleanup commit messages (verbatim,-t)' '
|
||||
|
||||
echo >>negative &&
|
||||
|
||||
73
t/t7507-commit-verbose.sh
Executable file
73
t/t7507-commit-verbose.sh
Executable file
@@ -0,0 +1,73 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='verbose commit template'
|
||||
. ./test-lib.sh
|
||||
|
||||
cat >check-for-diff <<EOF
|
||||
#!$SHELL_PATH
|
||||
exec grep '^diff --git' "\$1"
|
||||
EOF
|
||||
chmod +x check-for-diff
|
||||
test_set_editor "$PWD/check-for-diff"
|
||||
|
||||
cat >message <<'EOF'
|
||||
subject
|
||||
|
||||
body
|
||||
EOF
|
||||
|
||||
test_expect_success 'setup' '
|
||||
echo content >file &&
|
||||
git add file &&
|
||||
git commit -F message
|
||||
'
|
||||
|
||||
test_expect_success 'initial commit shows verbose diff' '
|
||||
git commit --amend -v
|
||||
'
|
||||
|
||||
test_expect_success 'second commit' '
|
||||
echo content modified >file &&
|
||||
git add file &&
|
||||
git commit -F message
|
||||
'
|
||||
|
||||
check_message() {
|
||||
git log -1 --pretty=format:%s%n%n%b >actual &&
|
||||
test_cmp "$1" actual
|
||||
}
|
||||
|
||||
test_expect_success 'verbose diff is stripped out' '
|
||||
git commit --amend -v &&
|
||||
check_message message
|
||||
'
|
||||
|
||||
test_expect_success 'verbose diff is stripped out (mnemonicprefix)' '
|
||||
git config diff.mnemonicprefix true &&
|
||||
git commit --amend -v &&
|
||||
check_message message
|
||||
'
|
||||
|
||||
cat >diff <<'EOF'
|
||||
This is an example commit message that contains a diff.
|
||||
|
||||
diff --git c/file i/file
|
||||
new file mode 100644
|
||||
index 0000000..f95c11d
|
||||
--- /dev/null
|
||||
+++ i/file
|
||||
@@ -0,0 +1 @@
|
||||
+this is some content
|
||||
EOF
|
||||
|
||||
test_expect_success 'diff in message is retained without -v' '
|
||||
git commit --amend -F diff &&
|
||||
check_message diff
|
||||
'
|
||||
|
||||
test_expect_failure 'diff in message is retained with -v' '
|
||||
git commit --amend -F diff -v &&
|
||||
check_message diff
|
||||
'
|
||||
|
||||
test_done
|
||||
73
t/t7700-repack.sh
Executable file
73
t/t7700-repack.sh
Executable file
@@ -0,0 +1,73 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='git repack works correctly'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success 'objects in packs marked .keep are not repacked' '
|
||||
echo content1 > file1 &&
|
||||
echo content2 > file2 &&
|
||||
git add . &&
|
||||
git commit -m initial_commit &&
|
||||
# Create two packs
|
||||
# The first pack will contain all of the objects except one
|
||||
git rev-list --objects --all | grep -v file2 |
|
||||
git pack-objects pack > /dev/null &&
|
||||
# The second pack will contain the excluded object
|
||||
packsha1=$(git rev-list --objects --all | grep file2 |
|
||||
git pack-objects pack) &&
|
||||
touch -r pack-$packsha1.pack pack-$packsha1.keep &&
|
||||
objsha1=$(git verify-pack -v pack-$packsha1.idx | head -n 1 |
|
||||
sed -e "s/^\([0-9a-f]\{40\}\).*/\1/") &&
|
||||
mv pack-* .git/objects/pack/ &&
|
||||
git repack -A -d -l &&
|
||||
git prune-packed &&
|
||||
for p in .git/objects/pack/*.idx; do
|
||||
idx=$(basename $p)
|
||||
test "pack-$packsha1.idx" = "$idx" && continue
|
||||
if git verify-pack -v $p | egrep "^$objsha1"; then
|
||||
found_duplicate_object=1
|
||||
echo "DUPLICATE OBJECT FOUND"
|
||||
break
|
||||
fi
|
||||
done &&
|
||||
test -z "$found_duplicate_object"
|
||||
'
|
||||
|
||||
test_expect_success 'loose objects in alternate ODB are not repacked' '
|
||||
mkdir alt_objects &&
|
||||
echo `pwd`/alt_objects > .git/objects/info/alternates &&
|
||||
echo content3 > file3 &&
|
||||
objsha1=$(GIT_OBJECT_DIRECTORY=alt_objects git hash-object -w file3) &&
|
||||
git add file3 &&
|
||||
git commit -m commit_file3 &&
|
||||
git repack -a -d -l &&
|
||||
git prune-packed &&
|
||||
for p in .git/objects/pack/*.idx; do
|
||||
if git verify-pack -v $p | egrep "^$objsha1"; then
|
||||
found_duplicate_object=1
|
||||
echo "DUPLICATE OBJECT FOUND"
|
||||
break
|
||||
fi
|
||||
done &&
|
||||
test -z "$found_duplicate_object"
|
||||
'
|
||||
|
||||
test_expect_success 'packed obs in alt ODB are repacked even when local repo is packless' '
|
||||
mkdir alt_objects/pack
|
||||
mv .git/objects/pack/* alt_objects/pack &&
|
||||
git repack -a &&
|
||||
myidx=$(ls -1 .git/objects/pack/*.idx) &&
|
||||
test -f "$myidx" &&
|
||||
for p in alt_objects/pack/*.idx; do
|
||||
git verify-pack -v $p | sed -n -e "/^[0-9a-f]\{40\}/p"
|
||||
done | while read sha1 rest; do
|
||||
if ! ( git verify-pack -v $myidx | grep "^$sha1" ); then
|
||||
echo "Missing object in local pack: $sha1"
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -8,7 +8,7 @@ fsha1=
|
||||
csha1=
|
||||
tsha1=
|
||||
|
||||
test_expect_success '-A option leaves unreachable objects unpacked' '
|
||||
test_expect_success '-A with -d option leaves unreachable objects unpacked' '
|
||||
echo content > file1 &&
|
||||
git add . &&
|
||||
git commit -m initial_commit &&
|
||||
@@ -58,7 +58,7 @@ compare_mtimes ()
|
||||
' -- "$@"
|
||||
}
|
||||
|
||||
test_expect_success 'unpacked objects receive timestamp of pack file' '
|
||||
test_expect_success '-A without -d option leaves unreachable objects packed' '
|
||||
fsha1path=$(echo "$fsha1" | sed -e "s|\(..\)|\1/|") &&
|
||||
fsha1path=".git/objects/$fsha1path" &&
|
||||
csha1path=$(echo "$csha1" | sed -e "s|\(..\)|\1/|") &&
|
||||
@@ -75,7 +75,19 @@ test_expect_success 'unpacked objects receive timestamp of pack file' '
|
||||
git branch -D transient_branch &&
|
||||
sleep 1 &&
|
||||
git repack -A -l &&
|
||||
compare_mtimes "$packfile" "$fsha1path" "$csha1path" "$tsha1path"
|
||||
test ! -f "$fsha1path" &&
|
||||
test ! -f "$csha1path" &&
|
||||
test ! -f "$tsha1path" &&
|
||||
git show $fsha1 &&
|
||||
git show $csha1 &&
|
||||
git show $tsha1
|
||||
'
|
||||
|
||||
test_expect_success 'unpacked objects receive timestamp of pack file' '
|
||||
tmppack=".git/objects/pack/tmp_pack" &&
|
||||
ln "$packfile" "$tmppack" &&
|
||||
git repack -A -l -d &&
|
||||
compare_mtimes "$tmppack" "$fsha1path" "$csha1path" "$tsha1path"
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -265,4 +265,13 @@ test_expect_success 'able to set-tree to a subdirectory' "
|
||||
test -z \"\`git diff refs/heads/my-bar refs/remotes/bar\`\"
|
||||
"
|
||||
|
||||
test_expect_success 'git-svn works in a bare repository' '
|
||||
mkdir bare-repo &&
|
||||
( cd bare-repo &&
|
||||
git init --bare &&
|
||||
GIT_DIR=. git svn init "$svnrepo" &&
|
||||
git svn fetch ) &&
|
||||
rm -rf bare-repo
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user