Merge branch 'jp/send-email-cc'
* jp/send-email-cc:
git-send-email --cc-cmd
diff --git a/Documentation/RelNotes-1.5.3.txt b/Documentation/RelNotes-1.5.3.txt
index 9c36e8b..51ff53b 100644
--- a/Documentation/RelNotes-1.5.3.txt
+++ b/Documentation/RelNotes-1.5.3.txt
@@ -28,7 +28,7 @@
* For people who need to import from Perforce, a front-end for
fast-import is in contrib/fast-import/.
-* Comes with git-gui 0.8.0.
+* Comes with git-gui 0.8.2.
* Comes with updated gitk.
@@ -130,6 +130,9 @@
- "git init -q" makes the command quieter.
+ - "git -p command" now has a cousin of opposite sex, "git --no-pager
+ command".
+
* Updated behavior of existing commands.
- "gitweb" can offer multiple snapshot formats.
@@ -172,6 +175,15 @@
- "git log" learned --log-size to show the number of bytes in
the log message part of the output to help qgit.
+ - "git log --name-status" does not require you to give "-r" anymore.
+ As a general rule, Porcelain commands should recurse when showing
+ diff.
+
+ - "git format-patch --root A" can be used to format everything
+ since the beginning up to A. This was supported with
+ "git format-patch --root A A" for a long time, but was not
+ properly documented.
+
- "git svn dcommit" retains local merge information.
- "git svnimport" allows an empty string to be specified as the
@@ -301,8 +313,8 @@
when switching branches that have differences in only a
handful paths.
- - "git commit paths..." has also been optimized.
-
+ - "git add paths..." and "git commit paths..." has also been
+ heavily optimized.
Fixes since v1.5.2
------------------
@@ -315,8 +327,26 @@
- "gitweb" had trouble handling non UTF-8 text with older
Encode.pm Perl module.
+ - "git-write-tree" had a bad interaction with racy-git avoidance and
+ gitattributes mechanisms.
+
+ - "git --bare command" overrode existing GIT_DIR setting and always
+ made it treat the current working directory as GIT_DIR.
+
+ - "git ls-files --error-unmatch" does not complain if you give the
+ same path pattern twice by mistake.
+
+ - "git init" autodetected core.filemode but not core.symlinks, which
+ made a new directory created automatically by "git clone" cumbersome
+ to use on filesystems that require these configurations to be set.
+
+ - "git log" family of commands behaved differently when run as "git
+ log" (no pathspec) and as "git log --" (again, no pathspec). This
+ inconsistency was introduced somewhere in v1.3.0 series but now has
+ been corrected.
+
--
exec >/var/tmp/1
-O=v1.5.3-rc4
+O=v1.5.3-rc7-15-ga65f200
echo O=`git describe refs/heads/master`
git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index 01354c2..61635bf 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -31,7 +31,8 @@
corrupt whitespaces.
- provide additional information (which is unsuitable for
the commit message) between the "---" and the diffstat
- - send the patch to the list _and_ the maintainer
+ - send the patch to the list (git@vger.kernel.org) and the
+ maintainer (gitster@pobox.com).
- if you change, add, or remove a command line option or
make some other user interface change, the associated
documentation should be updated as well.
diff --git a/Documentation/config.txt b/Documentation/config.txt
index de9e72b..866e053 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -192,7 +192,7 @@
variable and the '--work-tree' command line option.
core.logAllRefUpdates::
- Updates to a ref <ref> is logged to the file
+ Enable the reflog. Updates to a ref <ref> is logged to the file
"$GIT_DIR/logs/<ref>", by appending the new and old
SHA1, the date/time and the reason of the update, but
only when the file exists. If this configuration
@@ -283,7 +283,7 @@
core.editor::
Commands such as `commit` and `tag` that lets you edit
- messages by lauching an editor uses the value of this
+ messages by launching an editor uses the value of this
variable when it is set, and the environment variable
`GIT_EDITOR` is not set. The order of preference is
`GIT_EDITOR` environment, `core.editor`, `VISUAL` and
@@ -301,12 +301,12 @@
hide existing git commands are ignored. Arguments are split by
spaces, the usual shell quoting and escaping is supported.
quote pair and a backslash can be used to quote them.
-
- If the alias expansion is prefixed with an exclamation point,
- it will be treated as a shell command. For example, defining
- "alias.new = !gitk --all --not ORIG_HEAD", the invocation
- "git new" is equivalent to running the shell command
- "gitk --all --not ORIG_HEAD".
++
+If the alias expansion is prefixed with an exclamation point,
+it will be treated as a shell command. For example, defining
+"alias.new = !gitk --all --not ORIG_HEAD", the invocation
+"git new" is equivalent to running the shell command
+"gitk --all --not ORIG_HEAD".
apply.whitespace::
Tells `git-apply` how to handle whitespaces, in the same way
@@ -396,6 +396,16 @@
commit.template::
Specify a file to use as the template for new commit messages.
+diff.autorefreshindex::
+ When using `git diff` to compare with work tree
+ files, do not consider stat-only change as changed.
+ Instead, silently run `git update-index --refresh` to
+ update the cached stat information for paths whose
+ contents in the work tree match the contents in the
+ index. This option defaults to true. Note that this
+ affects only `git diff` Porcelain, and not lower level
+ `diff` commands, such as `git diff-files`.
+
diff.renameLimit::
The number of files to consider when performing the copy/rename
detection; equivalent to the git diff option '-l'.
@@ -465,11 +475,11 @@
be encountered again. See gitlink:git-rerere[1].
gitcvs.enabled::
- Whether the cvs server interface is enabled for this repository.
+ Whether the CVS server interface is enabled for this repository.
See gitlink:git-cvsserver[1].
gitcvs.logfile::
- Path to a log file where the cvs server interface well... logs
+ Path to a log file where the CVS server interface well... logs
various stuff. See gitlink:git-cvsserver[1].
gitcvs.allbinary::
@@ -500,10 +510,10 @@
'gitcvs.dbuser' supports variable substitution (see
gitlink:git-cvsserver[1] for details).
-All gitcvs variables except for 'gitcvs.allbinary' can also specifed
-as 'gitcvs.<access_method>.<varname>' (where 'access_method' is one
-of "ext" and "pserver") to make them apply only for the given access
-method.
+All gitcvs variables except for 'gitcvs.allbinary' can also be
+specified as 'gitcvs.<access_method>.<varname>' (where 'access_method'
+is one of "ext" and "pserver") to make them apply only for the given
+access method.
http.sslVerify::
Whether to verify the SSL certificate when fetching or pushing
@@ -615,7 +625,7 @@
not set, defaults to -1.
pack.deltaCacheSize::
- The maxium memory in bytes used for caching deltas in
+ The maximum memory in bytes used for caching deltas in
gitlink:git-pack-objects[1].
A value of 0 means no limit. Defaults to 0.
@@ -675,15 +685,11 @@
See gitlink:git-show-branch[1].
tar.umask::
- By default, gitlink:git-tar-tree[1] sets file and directories modes
- to 0666 or 0777. While this is both useful and acceptable for projects
- such as the Linux Kernel, it might be excessive for other projects.
- With this variable, it becomes possible to tell
- gitlink:git-tar-tree[1] to apply a specific umask to the modes above.
- The special value "user" indicates that the user's current umask will
- be used. This should be enough for most projects, as it will lead to
- the same permissions as gitlink:git-checkout[1] would use. The default
- value remains 0, which means world read-write.
+ This variable can be used to restrict the permission bits of
+ tar archive entries. The default is 0002, which turns off the
+ world write bit. The special value "user" indicates that the
+ archiving user's umask will be used instead. See umask(2) and
+ gitlink:git-archive[1].
user.email::
Your email address to be recorded in any newly created commits.
diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt
index 3383aca..2fe7355 100644
--- a/Documentation/git-add.txt
+++ b/Documentation/git-add.txt
@@ -7,7 +7,9 @@
SYNOPSIS
--------
-'git-add' [-n] [-v] [-f] [--interactive | -i] [-u] [--refresh] [--] <file>...
+[verse]
+'git-add' [-n] [-v] [-f] [--interactive | -i] [-u] [--refresh]
+ [--] <filepattern>...
DESCRIPTION
-----------
@@ -31,9 +33,9 @@
The 'git add' command will not add ignored files by default. If any
ignored files were explicitly specified on the command line, 'git add'
will fail with a list of ignored files. Ignored files reached by
-directory recursion or filename globbing will be silently ignored.
-The 'add' command can be used to add ignored files with the `-f`
-(force) option.
+directory recursion or filename globbing performed by Git (quote your
+globs before the shell) will be silently ignored. The 'add' command can
+be used to add ignored files with the `-f` (force) option.
Please see gitlink:git-commit[1] for alternative ways to add content to a
commit.
@@ -41,7 +43,7 @@
OPTIONS
-------
-<file>...::
+<filepattern>...::
Files to add content from. Fileglobs (e.g. `*.c`) can
be given to add all matching files. Also a
leading directory name (e.g. `dir` to add `dir/file1`
diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt
index 4da07c1..f2080eb 100644
--- a/Documentation/git-archive.txt
+++ b/Documentation/git-archive.txt
@@ -72,16 +72,13 @@
CONFIGURATION
-------------
-By default, file and directories modes are set to 0666 or 0777 in tar
-archives. It is possible to change this by setting the "umask" variable
-in the repository configuration as follows :
-[tar]
- umask = 002 ;# group friendly
-
-The special umask value "user" indicates that the user's current umask
-will be used instead. The default value remains 0, which means world
-readable/writable files and directories.
+tar.umask::
+ This variable can be used to restrict the permission bits of
+ tar archive entries. The default is 0002, which turns off the
+ world write bit. The special value "user" indicates that the
+ archiving user's umask will be used instead. See umask(2) for
+ details.
EXAMPLES
--------
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 818b720..734928b 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -35,7 +35,7 @@
OPTIONS
-------
-q::
- Quiet, supress feedback messages.
+ Quiet, suppress feedback messages.
-f::
Proceed even if the index or the working tree differs
diff --git a/Documentation/git-commit-tree.txt b/Documentation/git-commit-tree.txt
index 5870c2c..a2537e1 100644
--- a/Documentation/git-commit-tree.txt
+++ b/Documentation/git-commit-tree.txt
@@ -51,9 +51,9 @@
- author name, email and date
- committer name and email and the commit time.
-If not provided, "git-commit-tree" uses your name, hostname and domain to
-provide author and committer info. This can be overridden by
-either `.git/config` file, or using the following environment variables.
+While parent object ids are provided on the command line, author and
+committer information is taken from the following environment variables,
+if set:
GIT_AUTHOR_NAME
GIT_AUTHOR_EMAIL
@@ -65,12 +65,9 @@
(nb "<", ">" and "\n"s are stripped)
-In `.git/config` file, the following items are used for GIT_AUTHOR_NAME and
-GIT_AUTHOR_EMAIL:
-
- [user]
- name = "Your Name"
- email = "your@email.address.xz"
+In case (some of) these environment variables are not set, the information
+is taken from the configuration items user.name and user.email, or, if not
+present, system user name and fully qualified hostname.
A commit comment is read from stdin. If a changelog
entry is not provided via "<" redirection, "git-commit-tree" will just wait
diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
index c3dffff..5b794f4 100644
--- a/Documentation/git-config.txt
+++ b/Documentation/git-config.txt
@@ -139,7 +139,7 @@
FILES
-----
-If not set explicitely with '--file', there are three files where
+If not set explicitly with '--file', there are three files where
git-config will search for configuration options:
.git/config::
diff --git a/Documentation/git-cvsexportcommit.txt b/Documentation/git-cvsexportcommit.txt
index 6c423e3..4c8d1e6 100644
--- a/Documentation/git-cvsexportcommit.txt
+++ b/Documentation/git-cvsexportcommit.txt
@@ -59,7 +59,7 @@
Useful for patch series and the like.
-u::
- Update affected files from cvs repository before attempting export.
+ Update affected files from CVS repository before attempting export.
-v::
Verbose.
diff --git a/Documentation/git-cvsserver.txt b/Documentation/git-cvsserver.txt
index 60d0bcf..258a62f 100644
--- a/Documentation/git-cvsserver.txt
+++ b/Documentation/git-cvsserver.txt
@@ -102,7 +102,7 @@
in the PATH. If you have clients that do not accept the CVS_SERVER
environment variable, you can rename git-cvsserver to cvs.
-Note: Newer cvs versions (>= 1.12.11) also support specifying
+Note: Newer CVS versions (>= 1.12.11) also support specifying
CVS_SERVER directly in CVSROOT like
------
diff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt
index f902161..99e47c9 100644
--- a/Documentation/git-daemon.txt
+++ b/Documentation/git-daemon.txt
@@ -124,7 +124,8 @@
Detach from the shell. Implies --syslog.
--pid-file=file::
- Save the process id in 'file'.
+ Save the process id in 'file'. Ignored when the daemon
+ is run under `--inetd`.
--user=user, --group=group::
Change daemon's uid and gid before entering the service loop.
@@ -157,6 +158,13 @@
SERVICES
--------
+These services can be globally enabled/disabled using the
+command line options of this command. If a finer-grained
+control is desired (e.g. to allow `git-archive` to be run
+against only in a few selected repositories the daemon serves),
+the per-repository configuration file can be used to enable or
+disable them.
+
upload-pack::
This serves `git-fetch-pack` and `git-peek-remote`
clients. It is enabled by default, but a repository can
@@ -164,7 +172,19 @@
item to `false`.
upload-archive::
- This serves `git-archive --remote`.
+ This serves `git-archive --remote`. It is disabled by
+ default, but a repository can enable it by setting
+ `daemon.uploadarchive` configuration item to `true`.
+
+receive-pack::
+ This serves `git-send-pack` clients, allowing anonymous
+ push. It is disabled by default, as there is _no_
+ authentication in the protocol (in other words, anybody
+ can push anything into the repository, including removal
+ of refs). This is solely meant for a closed LAN setting
+ where everybody is friendly. This service can be
+ enabled by `daemon.receivepack` configuration item to
+ `true`.
EXAMPLES
--------
@@ -228,6 +248,18 @@
Repositories can still be accessed by hostname though, assuming
they correspond to these IP addresses.
+selectively enable/disable services per repository::
+ To enable `git-archive --remote` and disable `git-fetch` against
+ a repository, have the following in the configuration file in the
+ repository (that is the file 'config' next to 'HEAD', 'refs' and
+ 'objects').
++
+----------------------------------------------------------------
+ [daemon]
+ uploadpack = false
+ uploadarchive = true
+----------------------------------------------------------------
+
Author
------
diff --git a/Documentation/git-diff.txt b/Documentation/git-diff.txt
index b36e705..db2eb46 100644
--- a/Documentation/git-diff.txt
+++ b/Documentation/git-diff.txt
@@ -22,10 +22,10 @@
words, the differences are what you _could_ tell git to
further add to the index but you still haven't. You can
stage these changes by using gitlink:git-add[1].
-
- If exactly two paths are given, and at least one is untracked,
- compare the two files / directories. This behavior can be
- forced by --no-index.
++
+If exactly two paths are given, and at least one is untracked,
+compare the two files / directories. This behavior can be
+forced by --no-index.
'git-diff' [--options] --cached [<commit>] [--] [<path>...]::
@@ -44,16 +44,34 @@
'git-diff' [--options] <commit> <commit> [--] [<path>...]::
- This form is to view the changes between two <commit>,
- for example, tips of two branches.
+ This is to view the changes between two arbitrary
+ <commit>.
+
+'git-diff' [--options] <commit>..<commit> [--] [<path>...]::
+
+ This is synonymous to the previous form. If <commit> on
+ one side is omitted, it will have the same effect as
+ using HEAD instead.
+
+'git-diff' [--options] <commit>\...<commit> [--] [<path>...]::
+
+ This form is to view the changes on the branch containing
+ and up to the second <commit>, starting at a common ancestor
+ of both <commit>. "git-diff A\...B" is equivalent to
+ "git-diff $(git-merge-base A B) B". You can omit any one
+ of <commit>, which has the same effect as using HEAD instead.
Just in case if you are doing something exotic, it should be
-noted that all of the <commit> in the above description can be
-any <tree-ish>.
+noted that all of the <commit> in the above description, except
+for the last two forms that use ".." notations, can be any
+<tree-ish>.
For a more complete list of ways to spell <commit>, see
"SPECIFYING REVISIONS" section in gitlink:git-rev-parse[1].
-
+However, "diff" is about comparing two _endpoints_, not ranges,
+and the range notations ("<commit>..<commit>" and
+"<commit>\...<commit>") do not mean a range as defined in the
+"SPECIFYING RANGES" section in gitlink:git-rev-parse[1].
OPTIONS
-------
@@ -97,6 +115,18 @@
file "test".
<3> Compare the version before the last commit and the last commit.
+Comparing branches::
++
+------------
+$ git diff topic master <1>
+$ git diff topic..master <2>
+$ git diff topic...master <3>
+------------
++
+<1> Changes between the tips of the topic and the master branches.
+<2> Same as above.
+<3> Changes that occured on the master branch since when the topic
+branch was started off it.
Limiting the diff output::
+
diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt
index 30ee98d..d511967 100644
--- a/Documentation/git-fast-import.txt
+++ b/Documentation/git-fast-import.txt
@@ -176,6 +176,15 @@
spaces in their name, or early termination of fast-import when it encounters
unexpected input.
+Stream Comments
+~~~~~~~~~~~~~~~
+To aid in debugging frontends fast-import ignores any line that
+begins with `#` (ASCII pound/hash) up to and including the line
+ending `LF`. A comment line may contain any sequence of bytes
+that does not contain an LF and therefore may be used to include
+any detailed debugging information that might be specific to the
+frontend and useful when inspecting a fast-import data stream.
+
Date Formats
~~~~~~~~~~~~
The following date formats are supported. A frontend should select
@@ -232,7 +241,7 @@
+
Frontends should prefer the `raw` format if the source material
already uses UNIX-epoch format, can be coaxed to give dates in that
-format, or its format is easiliy convertible to it, as there is no
+format, or its format is easily convertible to it, as there is no
ambiguity in parsing.
`now`::
@@ -289,6 +298,11 @@
This command is optional and is not needed to perform
an import.
+`progress`::
+ Causes fast-import to echo the entire line to its own
+ standard output. This command is optional and is not needed
+ to perform an import.
+
`commit`
~~~~~~~~
Create or update a branch with a new commit, recording one logical
@@ -303,7 +317,7 @@
('from' SP <committish> LF)?
('merge' SP <committish> LF)?
(filemodify | filedelete | filecopy | filerename | filedeleteall)*
- LF
+ LF?
....
where `<ref>` is the name of the branch to make the commit on.
@@ -329,11 +343,13 @@
and `filedeleteall` commands
may be included to update the contents of the branch prior to
creating the commit. These commands may be supplied in any order.
-However it is recommended that a `filedeleteall` command preceed
+However it is recommended that a `filedeleteall` command precede
all `filemodify`, `filecopy` and `filerename` commands in the same
commit, as `filedeleteall`
wipes the branch clean (see below).
+The `LF` after the command is optional (it used to be required).
+
`author`
^^^^^^^^
An `author` command may optionally appear, if the author information
@@ -386,7 +402,7 @@
+
The reason fast-import uses `:` to denote a mark reference is this character
is not legal in a Git branch name. The leading `:` makes it easy
-to distingush between the mark 42 (`:42`) and the branch 42 (`42`
+to distinguish between the mark 42 (`:42`) and the branch 42 (`42`
or `refs/heads/42`), or an abbreviated SHA-1 which happened to
consist only of base-10 digits.
+
@@ -471,7 +487,7 @@
If an `LF` or double quote must be encoded into `<path>` shell-style
quoting should be used, e.g. `"path/with\n and \" in it"`.
-The value of `<path>` must be in canoncial form. That is it must not:
+The value of `<path>` must be in canonical form. That is it must not:
* contain an empty directory component (e.g. `foo//bar` is invalid),
* end with a directory separator (e.g. `foo/` is invalid),
@@ -645,12 +661,14 @@
....
'reset' SP <ref> LF
('from' SP <committish> LF)?
- LF
+ LF?
....
For a detailed description of `<ref>` and `<committish>` see above
under `commit` and `from`.
+The `LF` after the command is optional (it used to be required).
+
The `reset` command can also be used to create lightweight
(non-annotated) tags. For example:
@@ -689,29 +707,40 @@
exact byte count format, as it is more robust and performs better.
The delimited format is intended primarily for testing fast-import.
+Comment lines appearing within the `<raw>` part of `data` commands
+are always taken to be part of the body of the data and are therefore
+never ignored by fast-import. This makes it safe to import any
+file/message content whose lines might start with `#`.
+
Exact byte count format::
The frontend must specify the number of bytes of data.
+
....
'data' SP <count> LF
- <raw> LF
+ <raw> LF?
....
+
where `<count>` is the exact number of bytes appearing within
`<raw>`. The value of `<count>` is expressed as an ASCII decimal
integer. The `LF` on either side of `<raw>` is not
included in `<count>` and will not be included in the imported data.
++
+The `LF` after `<raw>` is optional (it used to be required) but
+recommended. Always including it makes debugging a fast-import
+stream easier as the next command always starts in column 0
+of the next line, even if `<raw>` did not end with an `LF`.
Delimited format::
A delimiter string is used to mark the end of the data.
fast-import will compute the length by searching for the delimiter.
- This format is primarly useful for testing and is not
+ This format is primarily useful for testing and is not
recommended for real data.
+
....
'data' SP '<<' <delim> LF
<raw> LF
<delim> LF
+ LF?
....
+
where `<delim>` is the chosen delimiter string. The string `<delim>`
@@ -720,6 +749,8 @@
immediately trailing `<raw>` is part of `<raw>`. This is one of
the limitations of the delimited format, it is impossible to supply
a data chunk which does not have an LF as its last byte.
++
+The `LF` after `<delim> LF` is optional (it used to be required).
`checkpoint`
~~~~~~~~~~~~
@@ -728,7 +759,7 @@
....
'checkpoint' LF
- LF
+ LF?
....
Note that fast-import automatically switches packfiles when the current
@@ -747,6 +778,32 @@
repository can be loaded into Git through fast-import in about 3 hours,
explicit checkpointing may not be necessary.
+The `LF` after the command is optional (it used to be required).
+
+`progress`
+~~~~~~~~~~
+Causes fast-import to print the entire `progress` line unmodified to
+its standard output channel (file descriptor 1) when the command is
+processed from the input stream. The command otherwise has no impact
+on the current import, or on any of fast-import's internal state.
+
+....
+ 'progress' SP <any> LF
+ LF?
+....
+
+The `<any>` part of the command may contain any sequence of bytes
+that does not contain `LF`. The `LF` after the command is optional.
+Callers may wish to process the output through a tool such as sed to
+remove the leading part of the line, for example:
+
+====
+ frontend | git-fast-import | sed 's/^progress //'
+====
+
+Placing a `progress` command immediately after a `checkpoint` will
+inform the reader when the `checkpoint` has been completed and it
+can safely access the refs that fast-import updated.
Tips and Tricks
---------------
@@ -816,7 +873,7 @@
Import Now, Repack Later
~~~~~~~~~~~~~~~~~~~~~~~~
As soon as fast-import completes the Git repository is completely valid
-and ready for use. Typicallly this takes only a very short time,
+and ready for use. Typically this takes only a very short time,
even for considerably large projects (100,000+ commits).
However repacking the repository is necessary to improve data
@@ -840,6 +897,15 @@
You only need to expend the effort once, and everyone using your
project will benefit from the smaller repository.
+Include Some Progress Messages
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Every once in a while have your frontend emit a `progress` message
+to fast-import. The contents of the messages are entirely free-form,
+so one suggestion would be to output the current month and year
+each time the current commit date moves into the next month.
+Your users will feel better knowing how much of the data stream
+has been processed.
+
Packfile Optimization
---------------------
@@ -876,8 +942,8 @@
------------------
There are a number of factors which affect how much memory fast-import
requires to perform an import. Like critical sections of core
-Git, fast-import uses its own memory allocators to ammortize any overheads
-associated with malloc. In practice fast-import tends to ammoritize any
+Git, fast-import uses its own memory allocators to amortize any overheads
+associated with malloc. In practice fast-import tends to amortize any
malloc overheads to 0, due to its use of large block allocations.
per object
@@ -934,7 +1000,7 @@
~~~~~~~~~~~~~~~
Trees (aka directories) use just 12 bytes of memory on top of the
memory required for their entries (see ``per active file'' below).
-The cost of a tree is virtually 0, as its overhead ammortizes out
+The cost of a tree is virtually 0, as its overhead amortizes out
over the individual file entries.
per active file entry
diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt
index 915258f..29bb8ce 100644
--- a/Documentation/git-filter-branch.txt
+++ b/Documentation/git-filter-branch.txt
@@ -12,23 +12,24 @@
[--index-filter <command>] [--parent-filter <command>]
[--msg-filter <command>] [--commit-filter <command>]
[--tag-name-filter <command>] [--subdirectory-filter <directory>]
- [-d <directory>] [-f | --force] [<rev-list options>...]
+ [--original <namespace>] [-d <directory>] [-f | --force]
+ [<rev-list options>...]
DESCRIPTION
-----------
-Lets you rewrite git revision history by creating a new branch from
-your current branch, applying custom filters on each revision.
+Lets you rewrite git revision history by rewriting the branches mentioned
+in the <rev-list options>, applying custom filters on each revision.
Those filters can modify each tree (e.g. removing a file or running
a perl rewrite on all files) or information about each commit.
Otherwise, all information (including original commit times or merge
information) will be preserved.
-The command takes the new branch name as a mandatory argument and
-the filters as optional arguments. If you specify no filters, the
-commits will be recommitted without any changes, which would normally
-have no effect. Nevertheless, this may be useful in the future for
-compensating for some git bugs or such, therefore such a usage is
-permitted.
+The command will only rewrite the _positive_ refs mentioned in the
+command line (i.e. if you pass 'a..b', only 'b' will be rewritten).
+If you specify no filters, the commits will be recommitted without any
+changes, which would normally have no effect. Nevertheless, this may be
+useful in the future for compensating for some git bugs or such,
+therefore such a usage is permitted.
*WARNING*! The rewritten history will have different object names for all
the objects and will not converge with the original branch. You will not
@@ -42,8 +43,8 @@
'refs/original/'.
Note that since this operation is extensively I/O expensive, it might
-be a good idea to redirect the temporary directory off-disk, e.g. on
-tmpfs. Reportedly the speedup is very noticeable.
+be a good idea to redirect the temporary directory off-disk with the
+'-d' option, e.g. on tmpfs. Reportedly the speedup is very noticeable.
Filters
@@ -111,6 +112,11 @@
As a special extension, the commit filter may emit multiple
commit ids; in that case, ancestors of the original commit will
have all of them as parents.
++
+You can use the 'map' convenience function in this filter, and other
+convenience functions, too. For example, calling 'skip_commit "$@"'
+will leave out the current commit (but not its changes! If you want
+that, use gitlink:git-rebase[1] instead).
--tag-name-filter <command>::
This is the filter for rewriting tag names. When passed,
@@ -120,7 +126,7 @@
tag name is expected on standard output.
+
The original tags are not deleted, but can be overwritten;
-use "--tag-name-filter=cat" to simply update the tags. In this
+use "--tag-name-filter cat" to simply update the tags. In this
case, be very careful and make sure you have the old tags
backed up in case the conversion has run afoul.
+
@@ -134,6 +140,10 @@
The result will contain that directory (and only that) as its
project root.
+--original <namespace>::
+ Use this option to set the namespace where the original commits
+ will be stored. The default value is 'refs/original'.
+
-d <directory>::
Use this option to set the path to the temporary directory used for
rewriting. When applying a tree filter, the command needs to
@@ -181,8 +191,8 @@
git filter-branch --parent-filter 'sed "s/^\$/-p <graft-id>/"' HEAD
-------------------------------------------------------------------
-(if the parent string is empty - therefore we are dealing with the
-initial commit - add graftcommit as a parent). Note that this assumes
+(if the parent string is empty - which happens when we are dealing with
+the initial commit - add graftcommit as a parent). Note that this assumes
history with a single root (that is, no merge without common ancestors
happened). If this is not the case, use:
@@ -204,34 +214,50 @@
git filter-branch --commit-filter '
if [ "$GIT_AUTHOR_NAME" = "Darl McBribe" ];
then
- shift;
- while [ -n "$1" ];
- do
- shift;
- echo "$1";
- shift;
- done;
+ skip_commit "$@";
else
git commit-tree "$@";
fi' HEAD
------------------------------------------------------------------------------
+Note that the changes introduced by the commits, and not reverted by
+subsequent commits, will still be in the rewritten branch. If you want
+to throw out _changes_ together with the commits, you should use the
+interactive mode of gitlink:git-rebase[1].
+
+The function 'skip_commits' is defined as follows:
+
+--------------------------
+skip_commit()
+{
+ shift;
+ while [ -n "$1" ];
+ do
+ shift;
+ map "$1";
+ shift;
+ done;
+}
+--------------------------
+
The shift magic first throws away the tree id and then the -p
parameters. Note that this handles merges properly! In case Darl
committed a merge between P1 and P2, it will be propagated properly
and all children of the merge will become merge commits with P1,P2
as their parents instead of the merge commit.
+
To restrict rewriting to only part of the history, specify a revision
range in addition to the new branch name. The new branch name will
point to the top-most revision that a 'git rev-list' of this range
will print.
-Note that the changes introduced by the commits, and not reverted by
-subsequent commits, will still be in the rewritten branch. If you want
+*NOTE* the changes introduced by the commits, and which are not reverted
+by subsequent commits, will still be in the rewritten branch. If you want
to throw out _changes_ together with the commits, you should use the
interactive mode of gitlink:git-rebase[1].
+
Consider this history:
------------------
diff --git a/Documentation/git-fmt-merge-msg.txt b/Documentation/git-fmt-merge-msg.txt
index 6affc5b..7088ed4 100644
--- a/Documentation/git-fmt-merge-msg.txt
+++ b/Documentation/git-fmt-merge-msg.txt
@@ -10,7 +10,7 @@
--------
[verse]
git-fmt-merge-msg [--summary | --no-summary] <$GIT_DIR/FETCH_HEAD
-git-fmt-merge-msg [--summary | --no-summray] -F <file>
+git-fmt-merge-msg [--summary | --no-summary] -F <file>
DESCRIPTION
-----------
diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt
index 6cbcf93..c9857a2 100644
--- a/Documentation/git-format-patch.txt
+++ b/Documentation/git-format-patch.txt
@@ -16,21 +16,35 @@
[--in-reply-to=Message-Id] [--suffix=.<sfx>]
[--ignore-if-in-upstream]
[--subject-prefix=Subject-Prefix]
- <since>[..<until>]
+ [ <since> | <revision range> ]
DESCRIPTION
-----------
-Prepare each commit between <since> and <until> with its patch in
+Prepare each commit with its patch in
one file per commit, formatted to resemble UNIX mailbox format.
-If ..<until> is not specified, the head of the current working
-tree is implied. For a more complete list of ways to spell
-<since> and <until>, see "SPECIFYING REVISIONS" section in
-gitlink:git-rev-parse[1].
-
The output of this command is convenient for e-mail submission or
for use with gitlink:git-am[1].
+There are two ways to specify which commits to operate on.
+
+1. A single commit, <since>, specifies that the commits leading
+ to the tip of the current branch that are not in the history
+ that leads to the <since> to be output.
+
+2. Generic <revision range> expression (see "SPECIFYING
+ REVISIONS" section in gitlink:git-rev-parse[1]) means the
+ commits in the specified range.
+
+A single commit, when interpreted as a <revision range>
+expression, means "everything that leads to that commit", but
+if you write 'git format-patch <commit>', the previous rule
+applies to that command line and you do not get "everything
+since the beginning of the time". If you want to format
+everything since project inception to one commit, say "git
+format-patch \--root <commit>" to make it clear that it is the
+latter case.
+
By default, each output file is numbered sequentially from 1, and uses the
first line of the commit message (massaged for pathname safety) as
the filename. With the --numbered-files option, the output file names
@@ -118,7 +132,7 @@
--suffix=.<sfx>::
Instead of using `.patch` as the suffix for generated
- filenames, use specifed suffix. A common alternative is
+ filenames, use specified suffix. A common alternative is
`--suffix=.txt`.
+
Note that you would need to include the leading dot `.` if you
@@ -153,6 +167,10 @@
not in the origin branch. For each commit a separate file
is created in the current directory.
+git-format-patch \--root origin::
+ Extract all commits which that leads to 'origin' since the
+ inception of the project.
+
git-format-patch -M -B origin::
The same as the previous one. Additionally, it detects
and handles renames and complete rewrites intelligently to
diff --git a/Documentation/git-gui.txt b/Documentation/git-gui.txt
index bd613b2..13252a1 100644
--- a/Documentation/git-gui.txt
+++ b/Documentation/git-gui.txt
@@ -89,7 +89,7 @@
Other
-----
git-gui is actually maintained as an independent project, but stable
-versions are distributed as part of the Git suite for the convience
+versions are distributed as part of the Git suite for the convenience
of end users.
A git-gui development repository can be obtained from:
diff --git a/Documentation/git-http-fetch.txt b/Documentation/git-http-fetch.txt
index 45e4845..389c6ed 100644
--- a/Documentation/git-http-fetch.txt
+++ b/Documentation/git-http-fetch.txt
@@ -34,7 +34,7 @@
the local end after the transfer is complete.
--stdin::
- Instead of a commit id on the commandline (which is not expected in this
+ Instead of a commit id on the command line (which is not expected in this
case), 'git-http-fetch' expects lines on stdin in the format
<commit-id>['\t'<filename-as-in--w>]
diff --git a/Documentation/git-local-fetch.txt b/Documentation/git-local-fetch.txt
index 141b767..e830dee 100644
--- a/Documentation/git-local-fetch.txt
+++ b/Documentation/git-local-fetch.txt
@@ -44,7 +44,7 @@
the local end after the transfer is complete.
--stdin::
- Instead of a commit id on the commandline (which is not expected in this
+ Instead of a commit id on the command line (which is not expected in this
case), 'git-local-fetch' expects lines on stdin in the format
<commit-id>['\t'<filename-as-in--w>]
diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index 5a90f65..5ec547c 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -49,6 +49,7 @@
-g, \--walk-reflogs::
Show commits as they were recorded in the reflog. The log contains
a record about how the tip of a reference was changed.
+ Cannot be combined with --reverse.
See also gitlink:git-reflog[1].
--decorate::
@@ -95,7 +96,7 @@
The "--" is necessary to avoid confusion with the *branch* named
'gitk'
-git log -r --name-status release..test::
+git log --name-status release..test::
Show the commits that are in the "test" branch but not yet
in the "release" branch, along with the list of paths
diff --git a/Documentation/git-name-rev.txt b/Documentation/git-name-rev.txt
index 91eede1..306e1a4 100644
--- a/Documentation/git-name-rev.txt
+++ b/Documentation/git-name-rev.txt
@@ -37,7 +37,7 @@
--name-only::
Instead of printing both the SHA-1 and the name, print only
the name. If given with --tags the usual tag prefix of
- "tags/" is also ommitted from the name, matching the output
+ "tags/" is also omitted from the name, matching the output
of gitlink::git-describe[1] more closely. This option
cannot be combined with --stdin.
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index a1b6dce..61b1810 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -8,7 +8,7 @@
SYNOPSIS
--------
[verse]
-'git-rebase' [-i | --interactive] [-v | --verbose] [--merge] [-C<n>]
+'git-rebase' [-i | --interactive] [-v | --verbose] [-m | --merge] [-C<n>]
[-p | --preserve-merges] [--onto <newbase>] <upstream> [<branch>]
'git-rebase' --continue | --skip | --abort
@@ -188,7 +188,7 @@
--skip::
Restart the rebasing process by skipping the current patch.
---merge::
+-m, \--merge::
Use merging strategies to rebase. When the recursive (default) merge
strategy is used, this allows rebase to be aware of renames on the
upstream side.
@@ -211,7 +211,8 @@
-i, \--interactive::
Make a list of the commits which are about to be rebased. Let the
- user edit that list before rebasing.
+ user edit that list before rebasing. This mode can also be used to
+ split commits (see SPLITTING COMMITS below).
-p, \--preserve-merges::
Instead of ignoring merges, try to recreate them. This option
@@ -325,6 +326,42 @@
$ git rebase -i -p --onto Q O
-----------------------------
+
+SPLITTING COMMITS
+-----------------
+
+In interactive mode, you can mark commits with the action "edit". However,
+this does not necessarily mean that 'git rebase' expects the result of this
+edit to be exactly one commit. Indeed, you can undo the commit, or you can
+add other commits. This can be used to split a commit into two:
+
+- Start an interactive rebase with 'git rebase -i <commit>^', where
+ <commit> is the commit you want to split. In fact, any commit range
+ will do, as long as it contains that commit.
+
+- Mark the commit you want to split with the action "edit".
+
+- When it comes to editing that commit, execute 'git reset HEAD^'. The
+ effect is that the HEAD is rewound by one, and the index follows suit.
+ However, the working tree stays the same.
+
+- Now add the changes to the index that you want to have in the first
+ commit. You can use gitlink:git-add[1] (possibly interactively) and/or
+ gitlink:git-gui[1] to do that.
+
+- Commit the now-current index with whatever commit message is appropriate
+ now.
+
+- Repeat the last two steps until your working tree is clean.
+
+- Continue the rebase with 'git rebase --continue'.
+
+If you are not absolutely sure that the intermediate revisions are
+consistent (they compile, pass the testsuite, etc.) you should use
+gitlink:git-stash[1] to stash away the not-yet-committed changes
+after each commit, test, and amend the commit if fixes are necessary.
+
+
Authors
------
Written by Junio C Hamano <junkio@cox.net> and
diff --git a/Documentation/git-receive-pack.txt b/Documentation/git-receive-pack.txt
index 4ef1840..2633d94 100644
--- a/Documentation/git-receive-pack.txt
+++ b/Documentation/git-receive-pack.txt
@@ -78,7 +78,7 @@
updating the named ref. Otherwise it should exit with zero.
Successful execution (a zero exit status) of this hook does not
-ensure the ref will actully be updated, it is only a prerequisite.
+ensure the ref will actually be updated, it is only a prerequisite.
As such it is not a good idea to send notices (e.g. email) from
this hook. Consider using the post-receive hook instead.
diff --git a/Documentation/git-reflog.txt b/Documentation/git-reflog.txt
index 89bc9c5..5180f68 100644
--- a/Documentation/git-reflog.txt
+++ b/Documentation/git-reflog.txt
@@ -30,9 +30,10 @@
tip, are removed from the reflog. This is typically not used
directly by the end users -- instead, see gitlink:git-gc[1].
-The subcommand "show" (which is also the default, in the absense of any
+The subcommand "show" (which is also the default, in the absence of any
subcommands) will take all the normal log options, and show the log of
-the current branch. It is basically an alias for 'git log -g --abbrev-commit
+`HEAD`, which will cover all recent actions, including branch switches.
+It is basically an alias for 'git log -g --abbrev-commit
--pretty=oneline', see gitlink:git-log[1].
diff --git a/Documentation/git-repack.txt b/Documentation/git-repack.txt
index 5283ef8..12e2079 100644
--- a/Documentation/git-repack.txt
+++ b/Documentation/git-repack.txt
@@ -14,7 +14,7 @@
-----------
This script is used to combine all objects that do not currently
-reside in a "pack", into a pack. It can also be used to re-organise
+reside in a "pack", into a pack. It can also be used to re-organize
existing packs into a single, more efficient pack.
A pack is a collection of objects, individually compressed, with
diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
index 1c19781..7cd0e89 100644
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.txt
@@ -113,7 +113,7 @@
`--date=rfc` (or `--date=rfc2822`) shows timestamps in RFC 2822
format, often found in E-mail messages.
+
-`--date=short` shows only date but not time, in `YYYY-MM-DD` fomat.
+`--date=short` shows only date but not time, in `YYYY-MM-DD` format.
+
`--date=default` shows timestamps in the original timezone
(either committer's or author's).
@@ -299,6 +299,8 @@
instead. Under '\--pretty=oneline', the commit message is
prefixed with this information on the same line.
+Cannot be combined with '\--reverse'.
+
--merge::
After a failed merge, show refs that touch files having a
@@ -373,6 +375,7 @@
--reverse::
Output the commits in reverse order.
+ Cannot be combined with '\--walk-reflogs'.
Object Traversal
~~~~~~~~~~~~~~~~
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index 4b4d229..4758c33 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -215,7 +215,10 @@
* A colon, optionally followed by a stage number (0 to 3) and a
colon, followed by a path; this names a blob object in the
index at the given path. Missing stage number (and the colon
- that follows it) names an stage 0 entry.
+ that follows it) names an stage 0 entry. During a merge, stage
+ 1 is the common ancestor, stage 2 is the target branch's version
+ (typically the current branch), and stage 3 is the version from
+ the branch being merged.
Here is an illustration, by Jon Loeliger. Both node B and C are
a commit parents of commit node A. Parent commits are ordered
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
index a63a3ad..16bfd7b 100644
--- a/Documentation/git-send-email.txt
+++ b/Documentation/git-send-email.txt
@@ -68,7 +68,7 @@
--signed-off-by-cc, --no-signed-off-by-cc::
If this is set, add emails found in Signed-off-by: or Cc: lines to the
cc list.
- Default is the value of 'sendemail.signedoffbycc' configuration value;
+ Default is the value of 'sendemail.signedoffcc' configuration value;
if that is unspecified, default to --signed-off-by-cc.
--quiet::
@@ -94,7 +94,7 @@
If this is set, do not add the From: address to the cc: list, if it
shows up in a From: line.
Default is the value of 'sendemail.suppressfrom' configuration value;
- if that is unspecified, default to --no-supress-from.
+ if that is unspecified, default to --no-suppress-from.
--thread, --no-thread::
If this is set, the In-Reply-To header will be set on each email sent.
diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt
index 816340b..be2e34e 100644
--- a/Documentation/git-svn.txt
+++ b/Documentation/git-svn.txt
@@ -44,10 +44,15 @@
--tags=<tags_subdir>;;
-b<branches_subdir>;;
--branches=<branches_subdir>;;
+-s;;
+--stdlayout;;
These are optional command-line options for init. Each of
these flags can point to a relative repository path
(--tags=project/tags') or a full url
- (--tags=https://foo.org/project/tags)
+ (--tags=https://foo.org/project/tags). The option --stdlayout is
+ a shorthand way of setting trunk,tags,branches as the relative paths,
+ which is the Subversion default. If any of the other options are given
+ as well, they take precedence.
--no-metadata;;
Set the 'noMetadata' option in the [svn-remote] config.
--use-svm-props;;
@@ -94,7 +99,7 @@
This works similarly to 'svn update' or 'git-pull' except that
it preserves linear history with 'git-rebase' instead of
-'git-merge' for ease of dcommit-ing with git-svn.
+'git-merge' for ease of dcommiting with git-svn.
This accepts all options that 'git-svn fetch' and 'git-rebase'
accepts. However '--fetch-all' only fetches from the current
@@ -479,6 +484,38 @@
history of the directory that it is tracking, however (much like
how 'svn log' works).
+CAVEATS
+-------
+
+For the sake of simplicity and interoperating with a less-capable system
+(SVN), it is recommended that all git-svn users clone, fetch and dcommit
+directly from the SVN server, and avoid all git-clone/pull/merge/push
+operations between git repositories and branches. The recommended
+method of exchanging code between git branches and users is
+git-format-patch and git-am, or just dcommiting to the SVN repository.
+
+Running 'git-merge' or 'git-pull' is NOT recommended on a branch you
+plan to dcommit from. Subversion does not represent merges in any
+reasonable or useful fashion; so users using Subversion cannot see any
+merges you've made. Furthermore, if you merge or pull from a git branch
+that is a mirror of an SVN branch, dcommit may commit to the wrong
+branch.
+
+'git-clone' does not clone branches under the refs/remotes/ hierarchy or
+any git-svn metadata, or config. So repositories created and managed with
+using git-svn should use rsync(1) for cloning, if cloning is to be done
+at all.
+
+Since 'dcommit' uses rebase internally, any git branches you git-push to
+before dcommit on will require forcing an overwrite of the existing ref
+on the remote repository. This is generally considered bad practice,
+see the git-push(1) documentation for details.
+
+Do not use the --amend option of git-commit(1) on a change you've
+already dcommitted. It is considered bad practice to --amend commits
+you've already pushed to a remote repository for other users, and
+dcommit with SVN is analogous to that.
+
BUGS
----
@@ -512,9 +549,9 @@
------------------------------------------------------------------------
Keep in mind that the '*' (asterisk) wildcard of the local ref
-(left of the ':') *must* be the farthest right path component;
+(right of the ':') *must* be the farthest right path component;
however the remote wildcard may be anywhere as long as it's own
-independent path componet (surrounded by '/' or EOL). This
+independent path component (surrounded by '/' or EOL). This
type of configuration is not automatically created by 'init' and
should be manually entered with a text-editor or using
gitlink:git-config[1]
diff --git a/Documentation/git-svnimport.txt b/Documentation/git-svnimport.txt
index e97d15e..71aad8b 100644
--- a/Documentation/git-svnimport.txt
+++ b/Documentation/git-svnimport.txt
@@ -68,6 +68,9 @@
Prepend 'rX: ' to commit messages, where X is the imported
subversion revision.
+-u::
+ Replace underscores in tag names with periods.
+
-I <ignorefile_name>::
Import the svn:ignore directory property to files with this
name in each directory. (The Subversion and GIT ignore
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 119117f..990ae4f 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -34,13 +34,6 @@
committer identity for the current user is used to find the
GnuPG key for signing.
-`-d <tag>` deletes the tag.
-
-`-v <tag>` verifies the gpg signature of the tag.
-
-`-l <pattern>` lists tags with names that match the given pattern
-(or all if no pattern is given).
-
OPTIONS
-------
-a::
diff --git a/Documentation/git-tar-tree.txt b/Documentation/git-tar-tree.txt
index 2d01d96..434607b 100644
--- a/Documentation/git-tar-tree.txt
+++ b/Documentation/git-tar-tree.txt
@@ -42,16 +42,13 @@
CONFIGURATION
-------------
-By default, file and directories modes are set to 0666 or 0777. It is
-possible to change this by setting the "umask" variable in the
-repository configuration as follows :
-[tar]
- umask = 002 ;# group friendly
-
-The special umask value "user" indicates that the user's current umask
-will be used instead. The default value is 002, which means group
-readable/writable files and directories.
+tar.umask::
+ This variable can be used to restrict the permission bits of
+ tar archive entries. The default is 0002, which turns off the
+ world write bit. The special value "user" indicates that the
+ archiving user's umask will be used instead. See umask(2) for
+ details.
EXAMPLES
--------
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 8017997..ceca892 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -9,7 +9,8 @@
SYNOPSIS
--------
[verse]
-'git' [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate]
+'git' [--version] [--exec-path[=GIT_EXEC_PATH]]
+ [-p|--paginate|--no-pager]
[--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE]
[--help] COMMAND [ARGS]
@@ -103,6 +104,9 @@
-p|--paginate::
Pipe all output into 'less' (or if set, $PAGER).
+--no-pager::
+ Do not pipe git output into a pager.
+
--git-dir=<path>::
Set the path to the repository. This can also be controlled by
setting the GIT_DIR environment variable.
@@ -116,7 +120,10 @@
variable.
--bare::
- Same as --git-dir=`pwd`.
+ Treat the repository as a bare repository. If GIT_DIR
+ environment is not set, it is set to the current working
+ directory.
+
FURTHER DOCUMENTATION
---------------------
@@ -469,7 +476,7 @@
Authors
-------
* git's founding father is Linus Torvalds <torvalds@osdl.org>.
-* The current git nurse is Junio C Hamano <junkio@cox.net>.
+* The current git nurse is Junio C Hamano <gitster@pobox.com>.
* The git potty was written by Andres Ericsson <ae@op5.se>.
* General upbringing is handled by the git-list <git@vger.kernel.org>.
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 8b90a5b..46f9d59 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -285,7 +285,7 @@
Note. A single level of backslashes are eaten by the
configuration file parser, so you would need to double the
backslashes; the pattern above picks a line that begins with a
-backslash, and zero or more occurences of `sub` followed by
+backslash, and zero or more occurrences of `sub` followed by
`section` followed by open brace, to the end of line.
There are a few built-in patterns to make this easier, and `tex`
@@ -394,7 +394,7 @@
the attributes given to path `t/abc` are computed as follows:
1. By examining `t/.gitattributes` (which is in the same
- diretory as the path in question), git finds that the first
+ directory as the path in question), git finds that the first
line matches. `merge` attribute is set. It also finds that
the second line matches, and attributes `foo` and `bar`
are unset.
@@ -410,7 +410,7 @@
a match, and `foo` is set, `bar` is reverted to unspecified
state, and `baz` is unset.
-As the result, the attributes assignement to `t/abc` becomes:
+As the result, the attributes assignment to `t/abc` becomes:
----------------------------------------------------------------
foo set to true
diff --git a/Documentation/hooks.txt b/Documentation/hooks.txt
index 6836477..c39edc5 100644
--- a/Documentation/hooks.txt
+++ b/Documentation/hooks.txt
@@ -176,7 +176,7 @@
This hook does not affect the outcome of `git-receive-pack`, as it
is called after the real work is done.
-This supersedes the <<post-update,'post-update'>> hook in that it get's
+This supersedes the <<post-update,'post-update'>> hook in that it gets
both old and new values of all the refs in addition to their
names.
diff --git a/Documentation/tutorial.txt b/Documentation/tutorial.txt
index bd9fbee..fff1068 100644
--- a/Documentation/tutorial.txt
+++ b/Documentation/tutorial.txt
@@ -339,7 +339,7 @@
-------------------------------------
Note that git pull always merges into the current branch,
-regardless of what else is given on the commandline.
+regardless of what else is given on the command line.
Later, Bob can update his repo with Alice's latest changes using
diff --git a/Documentation/urls.txt b/Documentation/urls.txt
index b38145f..e67f914 100644
--- a/Documentation/urls.txt
+++ b/Documentation/urls.txt
@@ -10,6 +10,7 @@
- https://host.xz/path/to/repo.git/
- git://host.xz/path/to/repo.git/
- git://host.xz/~user/path/to/repo.git/
+- ssh://{startsb}user@{endsb}host.xz{startsb}:port{endsb}/path/to/repo.git/
- ssh://{startsb}user@{endsb}host.xz/path/to/repo.git/
- ssh://{startsb}user@{endsb}host.xz/~user/path/to/repo.git/
- ssh://{startsb}user@{endsb}host.xz/~/path/to/repo.git
@@ -18,7 +19,8 @@
SSH is the default transport protocol over the network. You can
optionally specify which user to log-in as, and an alternate,
scp-like syntax is also supported. Both syntaxes support
-username expansion, as does the native git protocol. The following
+username expansion, as does the native git protocol, but
+only the former supports port specification. The following
three are identical to the last three above, respectively:
===============================================================
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index f89952a..35298e6 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -4,7 +4,7 @@
Git is a fast distributed revision control system.
-This manual is designed to be readable by someone with basic unix
+This manual is designed to be readable by someone with basic UNIX
command-line skills, but no previous knowledge of git.
<<repositories-and-branches>> and <<exploring-git-history>> explain how
@@ -42,10 +42,9 @@
It will be useful to have a git repository to experiment with as you
read this manual.
-The best way to get one is by using the gitlink:git-clone[1] command
-to download a copy of an existing repository for a project that you
-are interested in. If you don't already have a project in mind, here
-are some interesting examples:
+The best way to get one is by using the gitlink:git-clone[1] command to
+download a copy of an existing repository. If you don't already have a
+project in mind, here are some interesting examples:
------------------------------------------------
# git itself (approx. 10MB download):
@@ -63,21 +62,18 @@
together with a special top-level directory named ".git", which
contains all the information about the history of the project.
-In most of the following, examples will be taken from one of the two
-repositories above.
-
[[how-to-check-out]]
How to check out a different version of a project
-------------------------------------------------
-Git is best thought of as a tool for storing the history of a
-collection of files. It stores the history as a compressed
-collection of interrelated snapshots (versions) of the project's
-contents.
+Git is best thought of as a tool for storing the history of a collection
+of files. It stores the history as a compressed collection of
+interrelated snapshots of the project's contents. In git each such
+version is called a <<def_commit,commit>>.
A single git repository may contain multiple branches. It keeps track
of them by keeping a list of <<def_head,heads>> which reference the
-latest version on each branch; the gitlink:git-branch[1] command shows
+latest commit on each branch; the gitlink:git-branch[1] command shows
you the list of branch heads:
------------------------------------------------
@@ -149,32 +145,27 @@
------------------------------------------------
$ git show
-commit 2b5f6dcce5bf94b9b119e9ed8d537098ec61c3d2
-Author: Jamal Hadi Salim <hadi@cyberus.ca>
-Date: Sat Dec 2 22:22:25 2006 -0800
+commit 17cf781661e6d38f737f15f53ab552f1e95960d7
+Author: Linus Torvalds <torvalds@ppc970.osdl.org.(none)>
+Date: Tue Apr 19 14:11:06 2005 -0700
- [XFRM]: Fix aevent structuring to be more complete.
+ Remove duplicate getenv(DB_ENVIRONMENT) call
- aevents can not uniquely identify an SA. We break the ABI with this
- patch, but consensus is that since it is not yet utilized by any
- (known) application then it is fine (better do it now than later).
+ Noted by Tony Luck.
- Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
- Signed-off-by: David S. Miller <davem@davemloft.net>
-
-diff --git a/Documentation/networking/xfrm_sync.txt b/Documentation/networking/xfrm_sync.txt
-index 8be626f..d7aac9d 100644
---- a/Documentation/networking/xfrm_sync.txt
-+++ b/Documentation/networking/xfrm_sync.txt
-@@ -47,10 +47,13 @@ aevent_id structure looks like:
-
- struct xfrm_aevent_id {
- struct xfrm_usersa_id sa_id;
-+ xfrm_address_t saddr;
- __u32 flags;
-+ __u32 reqid;
- };
-...
+diff --git a/init-db.c b/init-db.c
+index 65898fa..b002dc6 100644
+--- a/init-db.c
++++ b/init-db.c
+@@ -7,7 +7,7 @@
+
+ int main(int argc, char **argv)
+ {
+- char *sha1_dir = getenv(DB_ENVIRONMENT), *path;
++ char *sha1_dir, *path;
+ int len, i;
+
+ if (mkdir(".git", 0755) < 0) {
------------------------------------------------
As you can see, a commit shows who made the latest change, what they
@@ -217,7 +208,7 @@
In the following, we say that commit X is "reachable" from commit Y
if commit X is an ancestor of commit Y. Equivalently, you could say
-that Y is a descendent of X, or that there is a chain of parents
+that Y is a descendant of X, or that there is a chain of parents
leading from commit Y to commit X.
[[history-diagrams]]
@@ -923,14 +914,14 @@
[[Finding-comments-with-given-content]]
Finding commits referencing a file with given content
------------------------------------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Somebody hands you a copy of a file, and asks which commits modified a
file such that it contained the given content either before or after the
commit. You can find out with this:
-------------------------------------------------
-$ git log --raw -r --abbrev=40 --pretty=oneline -- filename |
+$ git log --raw --abbrev=40 --pretty=oneline -- filename |
grep -B 1 `git hash-object filename`
-------------------------------------------------
@@ -1105,20 +1096,14 @@
is just a matter of 'not' calling "`git add`" on them. But it quickly becomes
annoying to have these untracked files lying around; e.g. they make
"`git add .`" and "`git commit -a`" practically useless, and they keep
-showing up in the output of "`git status`", etc.
+showing up in the output of "`git status`".
-Git therefore provides "exclude patterns" for telling git which files to
-actively ignore. Exclude patterns are thoroughly explained in the
-gitlink:gitignore[5] manual page, but the heart of the concept is simply
-a list of files which git should ignore. Entries in the list may contain
-globs to specify multiple files, or may be prefixed by "`!`" to
-explicitly include (un-ignore) a previously excluded (ignored) file
-(i.e. later exclude patterns override earlier ones). The following
-example should illustrate such patterns:
+You can tell git to ignore certain files by creating a file called .gitignore
+in the top level of your working directory, with contents such as:
-------------------------------------------------
# Lines starting with '#' are considered comments.
-# Ignore foo.txt.
+# Ignore any file named foo.txt.
foo.txt
# Ignore (generated) html files,
*.html
@@ -1128,41 +1113,20 @@
*.[oa]
-------------------------------------------------
-The next question is where to put these exclude patterns so that git can
-find them. Git looks for exclude patterns in the following files:
+See gitlink:gitignore[5] for a detailed explanation of the syntax. You can
+also place .gitignore files in other directories in your working tree, and they
+will apply to those directories and their subdirectories. The `.gitignore`
+files can be added to your repository like any other files (just run `git add
+.gitignore` and `git commit`, as usual), which is convenient when the exclude
+patterns (such as patterns matching build output files) would also make sense
+for other users who clone your repository.
-`.gitignore` files in your working tree:::
- You may store multiple `.gitignore` files at various locations in your
- working tree. Each `.gitignore` file is applied to the directory where
- it's located, including its subdirectories. Furthermore, the
- `.gitignore` files can be tracked like any other files in your working
- tree; just do a "`git add .gitignore`" and commit. `.gitignore` is
- therefore the right place to put exclude patterns that are meant to
- be shared between all project participants, such as build output files
- (e.g. `\*.o`), etc.
-`.git/info/exclude` in your repo:::
- Exclude patterns in this file are applied to the working tree as a
- whole. Since the file is not located in your working tree, it does
- not follow push/pull/clone like `.gitignore` can do. This is therefore
- the place to put exclude patterns that are local to your copy of the
- repo (i.e. 'not' shared between project participants), such as
- temporary backup files made by your editor (e.g. `\*~`), etc.
-The file specified by the `core.excludesfile` config directive:::
- By setting the `core.excludesfile` config directive you can tell git
- where to find more exclude patterns (see gitlink:git-config[1] for
- more information on configuration options). This config directive
- can be set in the per-repo `.git/config` file, in which case the
- exclude patterns will apply to that repo only. Alternatively, you
- can set the directive in the global `~/.gitconfig` file to apply
- the exclude pattern to all your git repos. As with the above
- `.git/info/exclude` (and, indeed, with git config directives in
- general), this directive does not follow push/pull/clone, but remain
- local to your repo(s).
-
-[NOTE]
-In addition to the above alternatives, there are git commands that can take
-exclude patterns directly on the command line. See gitlink:git-ls-files[1]
-for an example of this.
+If you wish the exclude patterns to affect only certain repositories
+(instead of every repository for a given project), you may instead put
+them in a file in your repository named .git/info/exclude, or in any file
+specified by the `core.excludesfile` configuration variable. Some git
+commands can also take exclude patterns directly on the command line.
+See gitlink:gitignore[5] for the details.
[[how-to-merge]]
How to merge
@@ -1796,11 +1760,12 @@
Public git repositories
-----------------------
-Another way to submit changes to a project is to tell the maintainer of
-that project to pull the changes from your repository using git-pull[1].
-In the section "<<getting-updates-with-git-pull, Getting updates with
-git pull>>" we described this as a way to get updates from the "main"
-repository, but it works just as well in the other direction.
+Another way to submit changes to a project is to tell the maintainer
+of that project to pull the changes from your repository using
+gitlink:git-pull[1]. In the section "<<getting-updates-with-git-pull,
+Getting updates with git pull>>" we described this as a way to get
+updates from the "main" repository, but it works just as well in the
+other direction.
If you and the maintainer both have accounts on the same machine, then
you can just pull changes from each other's repositories directly;
@@ -1911,7 +1876,7 @@
link:hooks.html[Hooks used by git].)
Advertise the url of proj.git. Anybody else should then be able to
-clone or pull from that url, for example with a commandline like:
+clone or pull from that url, for example with a command line like:
-------------------------------------------------
$ git clone http://yourserver.com/~you/proj.git
@@ -2057,7 +2022,8 @@
Linus's tree will be stored in the remote branch named origin/master,
and can be updated using gitlink:git-fetch[1]; you can track other
public trees using gitlink:git-remote[1] to set up a "remote" and
-git-fetch[1] to keep them up-to-date; see <<repositories-and-branches>>.
+gitlink:git-fetch[1] to keep them up-to-date; see
+<<repositories-and-branches>>.
Now create the branches in which you are going to work; these start out
at the current tip of origin/master branch, and should be set up (using
@@ -2512,9 +2478,9 @@
And browse through the list of patches in the mywork branch using gitk,
applying them (possibly in a different order) to mywork-new using
cherry-pick, and possibly modifying them as you go using commit --amend.
-The git-gui[1] command may also help as it allows you to individually
-select diff hunks for inclusion in the index (by right-clicking on the
-diff hunk and choosing "Stage Hunk for Commit").
+The gitlink:git-gui[1] command may also help as it allows you to
+individually select diff hunks for inclusion in the index (by
+right-clicking on the diff hunk and choosing "Stage Hunk for Commit").
Another technique is to use git-format-patch to create a series of
patches, then reset the state to before the patches:
@@ -2531,7 +2497,7 @@
Other tools
-----------
-There are numerous other tools, such as stgit, which exist for the
+There are numerous other tools, such as StGIT, which exist for the
purpose of maintaining a patch series. These are outside of the scope of
this manual.
@@ -3961,8 +3927,8 @@
The basic requirements:
- It must be readable in order, from beginning to end, by
- someone intelligent with a basic grasp of the unix
- commandline, but without any special knowledge of git. If
+ someone intelligent with a basic grasp of the UNIX
+ command line, but without any special knowledge of git. If
necessary, any other prerequisites should be specifically
mentioned as they arise.
- Whenever possible, section headings should clearly describe
diff --git a/Makefile b/Makefile
index 4eb4637..51af531 100644
--- a/Makefile
+++ b/Makefile
@@ -969,6 +969,8 @@
test-delta$X: diff-delta.o patch-delta.o
+.PRECIOUS: $(patsubst test-%$X,test-%.o,$(TEST_PROGRAMS))
+
test-%$X: test-%.o $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
diff --git a/builtin-add.c b/builtin-add.c
index 3dd4ded..105a9f0 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -14,7 +14,7 @@
#include "revision.h"
static const char builtin_add_usage[] =
-"git-add [-n] [-v] [-f] [--interactive | -i] [-u] [--] <filepattern>...";
+"git-add [-n] [-v] [-f] [--interactive | -i] [-u] [--refresh] [--] <filepattern>...";
static int take_worktree_changes;
static const char *excludes_file;
@@ -155,7 +155,7 @@
static struct lock_file lock_file;
-static const char ignore_warning[] =
+static const char ignore_error[] =
"The following paths are ignored by one of your .gitignore files:\n";
int cmd_add(int argc, const char **argv, const char *prefix)
@@ -250,12 +250,12 @@
die("index file corrupt");
if (dir.ignored_nr) {
- fprintf(stderr, ignore_warning);
+ fprintf(stderr, ignore_error);
for (i = 0; i < dir.ignored_nr; i++) {
fprintf(stderr, "%s\n", dir.ignored[i]->name);
}
fprintf(stderr, "Use -f if you really want to add them.\n");
- exit(1);
+ die("no files added");
}
for (i = 0; i < dir.nr; i++)
diff --git a/builtin-blame.c b/builtin-blame.c
index 0519339..dc88a95 100644
--- a/builtin-blame.c
+++ b/builtin-blame.c
@@ -98,6 +98,10 @@
num_read_blob++;
file->ptr = read_sha1_file(o->blob_sha1, &type,
(unsigned long *)(&(file->size)));
+ if (!file->ptr)
+ die("Cannot read blob %s for path %s",
+ sha1_to_hex(o->blob_sha1),
+ o->path);
o->file = *file;
}
else
@@ -1384,6 +1388,9 @@
unsigned long size;
commit->buffer =
read_sha1_file(commit->object.sha1, &type, &size);
+ if (!commit->buffer)
+ die("Cannot read commit %s",
+ sha1_to_hex(commit->object.sha1));
}
ret->author = author_buf;
get_ac_line(commit->buffer, "\nauthor ",
@@ -2382,6 +2389,10 @@
sb.final_buf = read_sha1_file(o->blob_sha1, &type,
&sb.final_buf_size);
+ if (!sb.final_buf)
+ die("Cannot read blob %s for path %s",
+ sha1_to_hex(o->blob_sha1),
+ path);
}
num_read_blob++;
lno = prepare_lines(&sb);
diff --git a/builtin-diff.c b/builtin-diff.c
index 6ed7b68..f77352b 100644
--- a/builtin-diff.c
+++ b/builtin-diff.c
@@ -188,6 +188,30 @@
add_pending_object(revs, obj, "HEAD");
}
+static void refresh_index_quietly(void)
+{
+ struct lock_file *lock_file;
+ int fd;
+
+ lock_file = xcalloc(1, sizeof(struct lock_file));
+ fd = hold_locked_index(lock_file, 0);
+ if (fd < 0)
+ return;
+ discard_cache();
+ read_cache();
+ refresh_cache(REFRESH_QUIET|REFRESH_UNMERGED);
+ if (active_cache_changed) {
+ if (write_cache(fd, active_cache, active_nr) ||
+ close(fd) ||
+ commit_locked_index(lock_file))
+ ; /*
+ * silently ignore it -- we haven't mucked
+ * with the real index.
+ */
+ }
+ rollback_lock_file(lock_file);
+}
+
int cmd_diff(int argc, const char **argv, const char *prefix)
{
int i;
@@ -222,7 +246,7 @@
prefix = setup_git_directory_gently(&nongit);
git_config(git_diff_ui_config);
init_revisions(&rev, prefix);
- rev.diffopt.skip_stat_unmatch = 1;
+ rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index;
if (!setup_diff_no_index(&rev, argc, argv, nongit, prefix))
argc = 0;
@@ -346,11 +370,7 @@
if (rev.diffopt.exit_with_status)
result = rev.diffopt.has_changes;
- if ((rev.diffopt.output_format & DIFF_FORMAT_PATCH)
- && (1 < rev.diffopt.skip_stat_unmatch))
- printf("Warning: %d path%s touched but unmodified. "
- "Consider running git-status.\n",
- rev.diffopt.skip_stat_unmatch - 1,
- rev.diffopt.skip_stat_unmatch == 2 ? "" : "s");
+ if (1 < rev.diffopt.skip_stat_unmatch)
+ refresh_index_quietly();
return result;
}
diff --git a/builtin-init-db.c b/builtin-init-db.c
index 0d9b1e0..763fa55 100644
--- a/builtin-init-db.c
+++ b/builtin-init-db.c
@@ -264,9 +264,62 @@
if (work_tree != git_work_tree_cfg)
git_config_set("core.worktree", work_tree);
}
+
+ /* Check if symlink is supported in the work tree */
+ if (!reinit) {
+ path[len] = 0;
+ strcpy(path + len, "tXXXXXX");
+ if (!close(xmkstemp(path)) &&
+ !unlink(path) &&
+ !symlink("testing", path) &&
+ !lstat(path, &st1) &&
+ S_ISLNK(st1.st_mode))
+ unlink(path); /* good */
+ else
+ git_config_set("core.symlinks", "false");
+ }
+
return reinit;
}
+static void guess_repository_type(const char *git_dir)
+{
+ char cwd[PATH_MAX];
+ const char *slash;
+
+ if (0 <= is_bare_repository_cfg)
+ return;
+ if (!git_dir)
+ return;
+
+ /*
+ * "GIT_DIR=. git init" is always bare.
+ * "GIT_DIR=`pwd` git init" too.
+ */
+ if (!strcmp(".", git_dir))
+ goto force_bare;
+ if (!getcwd(cwd, sizeof(cwd)))
+ die("cannot tell cwd");
+ if (!strcmp(git_dir, cwd))
+ goto force_bare;
+ /*
+ * "GIT_DIR=.git or GIT_DIR=something/.git is usually not.
+ */
+ if (!strcmp(git_dir, ".git"))
+ return;
+ slash = strrchr(git_dir, '/');
+ if (slash && !strcmp(slash, "/.git"))
+ return;
+
+ /*
+ * Otherwise it is often bare. At this point
+ * we are just guessing.
+ */
+ force_bare:
+ is_bare_repository_cfg = 1;
+ return;
+}
+
static const char init_db_usage[] =
"git-init [-q | --quiet] [--template=<template-directory>] [--shared]";
@@ -299,11 +352,28 @@
usage(init_db_usage);
}
- git_work_tree_cfg = xcalloc(PATH_MAX, 1);
- if (!getcwd(git_work_tree_cfg, PATH_MAX))
- die ("Cannot access current working directory.");
- if (access(get_git_work_tree(), X_OK))
- die ("Cannot access work tree '%s'", get_git_work_tree());
+ /*
+ * GIT_WORK_TREE makes sense only in conjunction with GIT_DIR
+ * without --bare. Catch the error early.
+ */
+ git_dir = getenv(GIT_DIR_ENVIRONMENT);
+ if ((!git_dir || is_bare_repository_cfg == 1)
+ && getenv(GIT_WORK_TREE_ENVIRONMENT))
+ die("%s (or --work-tree=<directory>) not allowed without "
+ "specifying %s (or --git-dir=<directory>)",
+ GIT_WORK_TREE_ENVIRONMENT,
+ GIT_DIR_ENVIRONMENT);
+
+ guess_repository_type(git_dir);
+
+ if (is_bare_repository_cfg <= 0) {
+ git_work_tree_cfg = xcalloc(PATH_MAX, 1);
+ if (!getcwd(git_work_tree_cfg, PATH_MAX))
+ die ("Cannot access current working directory.");
+ if (access(get_git_work_tree(), X_OK))
+ die ("Cannot access work tree '%s'",
+ get_git_work_tree());
+ }
/*
* Set up the default .git directory contents
diff --git a/builtin-log.c b/builtin-log.c
index 13bae31..fa81c25 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -55,6 +55,7 @@
rev->abbrev = DEFAULT_ABBREV;
rev->commit_format = CMIT_FMT_DEFAULT;
rev->verbose_header = 1;
+ rev->diffopt.recursive = 1;
rev->show_root_diff = default_show_root;
rev->subject_prefix = fmt_patch_subject_prefix;
argc = setup_revisions(argc, argv, rev, "HEAD");
@@ -116,7 +117,6 @@
git_config(git_log_config);
init_revisions(&rev, prefix);
rev.diff = 1;
- rev.diffopt.recursive = 1;
rev.simplify_history = 0;
cmd_log_init(argc, argv, prefix, &rev);
if (!rev.diffopt.output_format)
@@ -165,7 +165,6 @@
git_config(git_log_config);
init_revisions(&rev, prefix);
rev.diff = 1;
- rev.diffopt.recursive = 1;
rev.combine_merges = 1;
rev.dense_combined_merges = 1;
rev.always_show_header = 1;
@@ -586,12 +585,19 @@
}
if (rev.pending.nr == 1) {
- if (rev.max_count < 0) {
+ if (rev.max_count < 0 && !rev.show_root_diff) {
+ /*
+ * This is traditional behaviour of "git format-patch
+ * origin" that prepares what the origin side still
+ * does not have.
+ */
rev.pending.objects[0].item->flags |= UNINTERESTING;
add_head(&rev);
}
- /* Otherwise, it is "format-patch -22 HEAD", and
- * get_revision() would return only the specified count.
+ /*
+ * Otherwise, it is "format-patch -22 HEAD", and/or
+ * "format-patch --root HEAD". The user wants
+ * get_revision() to do the usual traversal.
*/
}
diff --git a/builtin-ls-files.c b/builtin-ls-files.c
index d36181a..cce17b5 100644
--- a/builtin-ls-files.c
+++ b/builtin-ls-files.c
@@ -511,8 +511,28 @@
*/
int num, errors = 0;
for (num = 0; pathspec[num]; num++) {
+ int other, found_dup;
+
if (ps_matched[num])
continue;
+ /*
+ * The caller might have fed identical pathspec
+ * twice. Do not barf on such a mistake.
+ */
+ for (found_dup = other = 0;
+ !found_dup && pathspec[other];
+ other++) {
+ if (other == num || !ps_matched[other])
+ continue;
+ if (!strcmp(pathspec[other], pathspec[num]))
+ /*
+ * Ok, we have a match already.
+ */
+ found_dup = 1;
+ }
+ if (found_dup)
+ continue;
+
error("pathspec '%s' did not match any file(s) known to git.",
pathspec[num] + prefix_offset);
errors++;
diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c
index b558754..d7cb11d 100644
--- a/builtin-mailinfo.c
+++ b/builtin-mailinfo.c
@@ -287,12 +287,12 @@
}
}
-static void decode_header(char *it);
+static void decode_header(char *it, unsigned itsize);
static char *header[MAX_HDR_PARSED] = {
"From","Subject","Date",
};
-static int check_header(char *line, char **hdr_data, int overwrite)
+static int check_header(char *line, unsigned linesize, char **hdr_data, int overwrite)
{
int i;
@@ -305,7 +305,7 @@
/* Unwrap inline B and Q encoding, and optionally
* normalize the meta information to utf8.
*/
- decode_header(line + len + 2);
+ decode_header(line + len + 2, linesize - len - 2);
hdr_data[i] = xmalloc(1000 * sizeof(char));
if (! handle_header(line, hdr_data[i], len + 2)) {
return 1;
@@ -316,14 +316,14 @@
/* Content stuff */
if (!strncasecmp(line, "Content-Type", 12) &&
line[12] == ':' && isspace(line[12 + 1])) {
- decode_header(line + 12 + 2);
+ decode_header(line + 12 + 2, linesize - 12 - 2);
if (! handle_content_type(line)) {
return 1;
}
}
if (!strncasecmp(line, "Content-Transfer-Encoding", 25) &&
line[25] == ':' && isspace(line[25 + 1])) {
- decode_header(line + 25 + 2);
+ decode_header(line + 25 + 2, linesize - 25 - 2);
if (! handle_content_transfer_encoding(line)) {
return 1;
}
@@ -432,10 +432,15 @@
return 1;
}
-static int decode_q_segment(char *in, char *ot, char *ep, int rfc2047)
+static int decode_q_segment(char *in, char *ot, unsigned otsize, char *ep, int rfc2047)
{
+ char *otend = ot + otsize;
int c;
while ((c = *in++) != 0 && (in <= ep)) {
+ if (ot == otend) {
+ *--ot = '\0';
+ return -1;
+ }
if (c == '=') {
int d = *in++;
if (d == '\n' || !d)
@@ -451,12 +456,17 @@
return 0;
}
-static int decode_b_segment(char *in, char *ot, char *ep)
+static int decode_b_segment(char *in, char *ot, unsigned otsize, char *ep)
{
/* Decode in..ep, possibly in-place to ot */
int c, pos = 0, acc = 0;
+ char *otend = ot + otsize;
while ((c = *in++) != 0 && (in <= ep)) {
+ if (ot == otend) {
+ *--ot = '\0';
+ return -1;
+ }
if (c == '+')
c = 62;
else if (c == '/')
@@ -518,7 +528,7 @@
return "latin1";
}
-static void convert_to_utf8(char *line, const char *charset)
+static void convert_to_utf8(char *line, unsigned linesize, const char *charset)
{
char *out;
@@ -534,11 +544,11 @@
if (!out)
die("cannot convert from %s to %s\n",
charset, metainfo_charset);
- strcpy(line, out);
+ strlcpy(line, out, linesize);
free(out);
}
-static int decode_header_bq(char *it)
+static int decode_header_bq(char *it, unsigned itsize)
{
char *in, *out, *ep, *cp, *sp;
char outbuf[1000];
@@ -578,56 +588,60 @@
default:
return rfc2047; /* no munging */
case 'b':
- sz = decode_b_segment(cp + 3, piecebuf, ep);
+ sz = decode_b_segment(cp + 3, piecebuf, sizeof(piecebuf), ep);
break;
case 'q':
- sz = decode_q_segment(cp + 3, piecebuf, ep, 1);
+ sz = decode_q_segment(cp + 3, piecebuf, sizeof(piecebuf), ep, 1);
break;
}
if (sz < 0)
return rfc2047;
if (metainfo_charset)
- convert_to_utf8(piecebuf, charset_q);
+ convert_to_utf8(piecebuf, sizeof(piecebuf), charset_q);
+
+ sz = strlen(piecebuf);
+ if (outbuf + sizeof(outbuf) <= out + sz)
+ return rfc2047; /* no munging */
strcpy(out, piecebuf);
- out += strlen(out);
+ out += sz;
in = ep + 2;
}
strcpy(out, in);
- strcpy(it, outbuf);
+ strlcpy(it, outbuf, itsize);
return rfc2047;
}
-static void decode_header(char *it)
+static void decode_header(char *it, unsigned itsize)
{
- if (decode_header_bq(it))
+ if (decode_header_bq(it, itsize))
return;
/* otherwise "it" is a straight copy of the input.
* This can be binary guck but there is no charset specified.
*/
if (metainfo_charset)
- convert_to_utf8(it, "");
+ convert_to_utf8(it, itsize, "");
}
-static void decode_transfer_encoding(char *line)
+static void decode_transfer_encoding(char *line, unsigned linesize)
{
char *ep;
switch (transfer_encoding) {
case TE_QP:
ep = line + strlen(line);
- decode_q_segment(line, line, ep, 0);
+ decode_q_segment(line, line, linesize, ep, 0);
break;
case TE_BASE64:
ep = line + strlen(line);
- decode_b_segment(line, line, ep);
+ decode_b_segment(line, line, linesize, ep);
break;
case TE_DONTCARE:
break;
}
}
-static int handle_filter(char *line);
+static int handle_filter(char *line, unsigned linesize);
static int find_boundary(void)
{
@@ -655,7 +669,7 @@
"can't recover\n");
exit(1);
}
- handle_filter(newline);
+ handle_filter(newline, sizeof(newline));
/* skip to the next boundary */
if (!find_boundary())
@@ -670,7 +684,7 @@
/* slurp in this section's info */
while (read_one_header_line(line, sizeof(line), fin))
- check_header(line, p_hdr_data, 0);
+ check_header(line, sizeof(line), p_hdr_data, 0);
/* eat the blank line after section info */
return (fgets(line, sizeof(line), fin) != NULL);
@@ -709,9 +723,10 @@
}
-static int handle_commit_msg(char *line)
+static int handle_commit_msg(char *line, unsigned linesize)
{
static int still_looking = 1;
+ char *endline = line + linesize;
if (!cmitmsg)
return 0;
@@ -726,13 +741,13 @@
if (!*cp)
return 0;
}
- if ((still_looking = check_header(cp, s_hdr_data, 0)) != 0)
+ if ((still_looking = check_header(cp, endline - cp, s_hdr_data, 0)) != 0)
return 0;
}
/* normalize the log message to UTF-8. */
if (metainfo_charset)
- convert_to_utf8(line, charset);
+ convert_to_utf8(line, endline - line, charset);
if (patchbreak(line)) {
fclose(cmitmsg);
@@ -751,7 +766,7 @@
return 0;
}
-static int handle_filter(char *line)
+static int handle_filter(char *line, unsigned linesize)
{
static int filter = 0;
@@ -760,7 +775,7 @@
*/
switch (filter) {
case 0:
- if (!handle_commit_msg(line))
+ if (!handle_commit_msg(line, linesize))
break;
filter++;
case 1:
@@ -792,14 +807,14 @@
/* flush any leftover */
if ((transfer_encoding == TE_BASE64) &&
(np != newline)) {
- handle_filter(newline);
+ handle_filter(newline, sizeof(newline));
}
if (!handle_boundary())
return;
}
/* Unwrap transfer encoding */
- decode_transfer_encoding(line);
+ decode_transfer_encoding(line, sizeof(line));
switch (transfer_encoding) {
case TE_BASE64:
@@ -808,7 +823,7 @@
/* binary data most likely doesn't have newlines */
if (message_type != TYPE_TEXT) {
- rc = handle_filter(line);
+ rc = handle_filter(line, sizeof(newline));
break;
}
@@ -825,7 +840,7 @@
/* should be sitting on a new line */
*(++np) = 0;
op++;
- rc = handle_filter(newline);
+ rc = handle_filter(newline, sizeof(newline));
np = newline;
}
} while (*op != 0);
@@ -835,7 +850,7 @@
break;
}
default:
- rc = handle_filter(line);
+ rc = handle_filter(line, sizeof(newline));
}
if (rc)
/* nothing left to filter */
@@ -922,7 +937,7 @@
/* process the email header */
while (read_one_header_line(line, sizeof(line), fin))
- check_header(line, p_hdr_data, 1);
+ check_header(line, sizeof(line), p_hdr_data, 1);
handle_body();
handle_info();
diff --git a/builtin-name-rev.c b/builtin-name-rev.c
index 61eba34..03083e9 100644
--- a/builtin-name-rev.c
+++ b/builtin-name-rev.c
@@ -11,14 +11,17 @@
typedef struct rev_name {
const char *tip_name;
- int merge_traversals;
int generation;
+ int distance;
} rev_name;
static long cutoff = LONG_MAX;
+/* How many generations are maximally preferred over _one_ merge traversal? */
+#define MERGE_TRAVERSAL_WEIGHT 65535
+
static void name_rev(struct commit *commit,
- const char *tip_name, int merge_traversals, int generation,
+ const char *tip_name, int generation, int distance,
int deref)
{
struct rev_name *name = (struct rev_name *)commit->util;
@@ -45,13 +48,11 @@
name = xmalloc(sizeof(rev_name));
commit->util = name;
goto copy_data;
- } else if (name->merge_traversals > merge_traversals ||
- (name->merge_traversals == merge_traversals &&
- name->generation > generation)) {
+ } else if (name->distance > distance) {
copy_data:
name->tip_name = tip_name;
- name->merge_traversals = merge_traversals;
name->generation = generation;
+ name->distance = distance;
} else
return;
@@ -74,11 +75,11 @@
sprintf(new_name, "%.*s^%d", len, tip_name,
parent_number);
- name_rev(parents->item, new_name,
- merge_traversals + 1 , 0, 0);
+ name_rev(parents->item, new_name, 0,
+ distance + MERGE_TRAVERSAL_WEIGHT, 0);
} else {
- name_rev(parents->item, tip_name, merge_traversals,
- generation + 1, 0);
+ name_rev(parents->item, tip_name, generation + 1,
+ distance + 1, 0);
}
}
}
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index 24926db..12509fa 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -979,6 +979,8 @@
int cmp;
while (tree_entry(tree,&entry)) {
+ if (S_ISGITLINK(entry.mode))
+ continue;
cmp = tree_entry_len(entry.path, entry.sha1) != cmplen ? 1 :
memcmp(name, entry.path, cmplen);
if (cmp > 0)
@@ -1354,6 +1356,9 @@
/* Load data if not already done */
if (!trg->data) {
trg->data = read_sha1_file(trg_entry->idx.sha1, &type, &sz);
+ if (!trg->data)
+ die("object %s cannot be read",
+ sha1_to_hex(trg_entry->idx.sha1));
if (sz != trg_size)
die("object %s inconsistent object length (%lu vs %lu)",
sha1_to_hex(trg_entry->idx.sha1), sz, trg_size);
@@ -1361,6 +1366,9 @@
}
if (!src->data) {
src->data = read_sha1_file(src_entry->idx.sha1, &type, &sz);
+ if (!src->data)
+ die("object %s cannot be read",
+ sha1_to_hex(src_entry->idx.sha1));
if (sz != src_size)
die("object %s inconsistent object length (%lu vs %lu)",
sha1_to_hex(src_entry->idx.sha1), sz, src_size);
@@ -1381,20 +1389,24 @@
if (!delta_buf)
return 0;
- if (trg_entry->delta_data) {
+ if (trg_entry->delta) {
/* Prefer only shallower same-sized deltas. */
if (delta_size == trg_entry->delta_size &&
src->depth + 1 >= trg->depth) {
free(delta_buf);
return 0;
}
+ }
+
+ trg_entry->delta = src_entry;
+ trg_entry->delta_size = delta_size;
+ trg->depth = src->depth + 1;
+
+ if (trg_entry->delta_data) {
delta_cache_size -= trg_entry->delta_size;
free(trg_entry->delta_data);
trg_entry->delta_data = NULL;
}
- trg_entry->delta = src_entry;
- trg_entry->delta_size = delta_size;
- trg->depth = src->depth + 1;
if (delta_cacheable(src_size, trg_size, delta_size)) {
trg_entry->delta_data = xrealloc(delta_buf, delta_size);
diff --git a/builtin-tag.c b/builtin-tag.c
index d6d38ad..348919c 100644
--- a/builtin-tag.c
+++ b/builtin-tag.c
@@ -123,22 +123,15 @@
static int list_tags(const char *pattern, int lines)
{
struct tag_filter filter;
- char *newpattern;
if (pattern == NULL)
- pattern = "";
+ pattern = "*";
- /* prepend/append * to the shell pattern: */
- newpattern = xmalloc(strlen(pattern) + 3);
- sprintf(newpattern, "*%s*", pattern);
-
- filter.pattern = newpattern;
+ filter.pattern = pattern;
filter.lines = lines;
for_each_tag_ref(show_reference, (void *) &filter);
- free(newpattern);
-
return 0;
}
diff --git a/builtin-write-tree.c b/builtin-write-tree.c
index 88f34ba..b89d02e 100644
--- a/builtin-write-tree.c
+++ b/builtin-write-tree.c
@@ -72,6 +72,7 @@
const char *prefix = NULL;
unsigned char sha1[20];
+ git_config(git_default_config);
while (1 < argc) {
const char *arg = argv[1];
if (!strcmp(arg, "--missing-ok"))
diff --git a/cache.h b/cache.h
index c7e00e7..70abbd5 100644
--- a/cache.h
+++ b/cache.h
@@ -594,6 +594,9 @@
extern char *convert_to_working_tree(const char *path, const char *src, unsigned long *sizep);
extern void *convert_sha1_file(const char *path, const unsigned char *sha1, unsigned int mode, enum object_type *type, unsigned long *size);
+/* diff.c */
+extern int diff_auto_refresh_index;
+
/* match-trees.c */
void shift_tree(const unsigned char *, const unsigned char *, unsigned char *, int);
diff --git a/connect.c b/connect.c
index ae49c5a..8b1e993 100644
--- a/connect.c
+++ b/connect.c
@@ -453,6 +453,22 @@
#define MAX_CMD_LEN 1024
+char *get_port(char *host)
+{
+ char *end;
+ char *p = strchr(host, ':');
+
+ if (p) {
+ strtol(p+1, &end, 10);
+ if (*end == '\0') {
+ *p = '\0';
+ return p+1;
+ }
+ }
+
+ return NULL;
+}
+
/*
* This returns 0 if the transport protocol does not need fork(2),
* or a process id if it does. Once done, finish the connection
@@ -471,6 +487,7 @@
pid_t pid;
enum protocol protocol = PROTO_LOCAL;
int free_path = 0;
+ char *port = NULL;
/* Without this we cannot rely on waitpid() to tell
* what happened to our children.
@@ -527,6 +544,12 @@
*ptr = '\0';
}
+ /*
+ * Add support for ssh port: ssh://host.xy:<port>/...
+ */
+ if (protocol == PROTO_SSH && host != url)
+ port = get_port(host);
+
if (protocol == PROTO_GIT) {
/* These underlying connection commands die() if they
* cannot connect.
@@ -583,7 +606,12 @@
ssh_basename = ssh;
else
ssh_basename++;
- execlp(ssh, ssh_basename, host, command, NULL);
+
+ if (!port)
+ execlp(ssh, ssh_basename, host, command, NULL);
+ else
+ execlp(ssh, ssh_basename, "-p", port, host,
+ command, NULL);
}
else {
unsetenv(ALTERNATE_DB_ENVIRONMENT);
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 82b9ed4..cad842a 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -114,6 +114,27 @@
done
}
+__git_tags ()
+{
+ local cmd i is_hash=y dir="$(__gitdir "$1")"
+ if [ -d "$dir" ]; then
+ for i in $(git --git-dir="$dir" \
+ for-each-ref --format='%(refname)' \
+ refs/tags ); do
+ echo "${i#refs/tags/}"
+ done
+ return
+ fi
+ for i in $(git-ls-remote "$1" 2>/dev/null); do
+ case "$is_hash,$i" in
+ y,*) is_hash=n ;;
+ n,*^{}) is_hash=y ;;
+ n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}" ;;
+ n,*) is_hash=y; echo "$i" ;;
+ esac
+ done
+}
+
__git_refs ()
{
local cmd i is_hash=y dir="$(__gitdir "$1")"
@@ -419,7 +440,7 @@
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
- __gitcomp "--interactive"
+ __gitcomp "--interactive --refresh"
return
esac
COMPREPLY=()
@@ -459,6 +480,35 @@
__gitcomp "$(__git_refs)"
}
+_git_bundle ()
+{
+ local mycword="$COMP_CWORD"
+ case "${COMP_WORDS[0]}" in
+ git)
+ local cmd="${COMP_WORDS[2]}"
+ mycword="$((mycword-1))"
+ ;;
+ git-bundle*)
+ local cmd="${COMP_WORDS[1]}"
+ ;;
+ esac
+ case "$mycword" in
+ 1)
+ __gitcomp "create list-heads verify unbundle"
+ ;;
+ 2)
+ # looking for a file
+ ;;
+ *)
+ case "$cmd" in
+ create)
+ __git_complete_revlist
+ ;;
+ esac
+ ;;
+ esac
+}
+
_git_checkout ()
{
__gitcomp "$(__git_refs)"
@@ -496,6 +546,11 @@
COMPREPLY=()
}
+_git_describe ()
+{
+ __gitcomp "$(__git_refs)"
+}
+
_git_diff ()
{
__git_complete_file
@@ -544,6 +599,7 @@
--stdout --attach --thread
--output-directory
--numbered --start-number
+ --numbered-files
--keep-subject
--signoff
--in-reply-to=
@@ -561,7 +617,7 @@
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
- __gitcomp "--prune"
+ __gitcomp "--prune --aggressive"
return
;;
esac
@@ -588,18 +644,25 @@
" "" "${cur##--pretty=}"
return
;;
+ --date=*)
+ __gitcomp "
+ relative iso8601 rfc2822 short local default
+ " "" "${cur##--date=}"
+ return
+ ;;
--*)
__gitcomp "
--max-count= --max-age= --since= --after=
--min-age= --before= --until=
--root --topo-order --date-order --reverse
- --no-merges
+ --no-merges --follow
--abbrev-commit --abbrev=
- --relative-date
+ --relative-date --date=
--author= --committer= --grep=
--all-match
--pretty= --name-status --name-only --raw
--not --all
+ --left-right --cherry-pick
"
return
;;
@@ -767,7 +830,7 @@
case "$cur" in
--*)
__gitcomp "
- --global --system
+ --global --system --file=
--list --replace-all
--get --get-all --get-regexp
--add --unset --unset-all
@@ -810,6 +873,7 @@
core.ignoreStat
core.preferSymlinkRefs
core.logAllRefUpdates
+ core.loosecompression
core.repositoryFormatVersion
core.sharedRepository
core.warnAmbiguousRefs
@@ -841,6 +905,7 @@
diff.renames
fetch.unpackLimit
format.headers
+ format.subjectprefix
gitcvs.enabled
gitcvs.logfile
gitcvs.allbinary
@@ -867,6 +932,10 @@
merge.verbosity
pack.window
pack.depth
+ pack.windowMemory
+ pack.compression
+ pack.deltaCacheSize
+ pack.deltaCacheLimit
pull.octopus
pull.twohead
repack.useDeltaBaseOffset
@@ -977,6 +1046,65 @@
__gitcomp 'list show apply clear'
}
+_git_submodule ()
+{
+ local i c=1 command
+ while [ $c -lt $COMP_CWORD ]; do
+ i="${COMP_WORDS[c]}"
+ case "$i" in
+ add|status|init|update) command="$i"; break ;;
+ esac
+ c=$((++c))
+ done
+
+ if [ $c -eq $COMP_CWORD -a -z "$command" ]; then
+ local cur="${COMP_WORDS[COMP_CWORD]}"
+ case "$cur" in
+ --*)
+ __gitcomp "--quiet --cached"
+ ;;
+ *)
+ __gitcomp "add status init update"
+ ;;
+ esac
+ return
+ fi
+}
+
+_git_tag ()
+{
+ local i c=1 f=0
+ while [ $c -lt $COMP_CWORD ]; do
+ i="${COMP_WORDS[c]}"
+ case "$i" in
+ -d|-v)
+ __gitcomp "$(__git_tags)"
+ return
+ ;;
+ -f)
+ f=1
+ ;;
+ esac
+ c=$((++c))
+ done
+
+ case "${COMP_WORDS[COMP_CWORD-1]}" in
+ -m|-F)
+ COMPREPLY=()
+ ;;
+ -*|tag|git-tag)
+ if [ $f = 1 ]; then
+ __gitcomp "$(__git_tags)"
+ else
+ COMPREPLY=()
+ fi
+ ;;
+ *)
+ __gitcomp "$(__git_refs)"
+ ;;
+ esac
+}
+
_git ()
{
local i c=1 command __git_dir
@@ -995,7 +1123,14 @@
if [ $c -eq $COMP_CWORD -a -z "$command" ]; then
case "${COMP_WORDS[COMP_CWORD]}" in
--*=*) COMPREPLY=() ;;
- --*) __gitcomp "--git-dir= --bare --version --exec-path" ;;
+ --*) __gitcomp "
+ --no-pager
+ --git-dir=
+ --bare
+ --version
+ --exec-path
+ "
+ ;;
*) __gitcomp "$(__git_commands) $(__git_aliases)" ;;
esac
return
@@ -1009,12 +1144,14 @@
add) _git_add ;;
apply) _git_apply ;;
bisect) _git_bisect ;;
+ bundle) _git_bundle ;;
branch) _git_branch ;;
checkout) _git_checkout ;;
cherry) _git_cherry ;;
cherry-pick) _git_cherry_pick ;;
commit) _git_commit ;;
config) _git_config ;;
+ describe) _git_describe ;;
diff) _git_diff ;;
fetch) _git_fetch ;;
format-patch) _git_format_patch ;;
@@ -1034,6 +1171,8 @@
show) _git_show ;;
show-branch) _git_log ;;
stash) _git_stash ;;
+ submodule) _git_submodule ;;
+ tag) _git_tag ;;
whatchanged) _git_log ;;
*) COMPREPLY=() ;;
esac
@@ -1057,10 +1196,12 @@
complete -o default -o nospace -F _git_apply git-apply
complete -o default -o nospace -F _git_bisect git-bisect
complete -o default -o nospace -F _git_branch git-branch
+complete -o default -o nospace -F _git_bundle git-bundle
complete -o default -o nospace -F _git_checkout git-checkout
complete -o default -o nospace -F _git_cherry git-cherry
complete -o default -o nospace -F _git_cherry_pick git-cherry-pick
complete -o default -o nospace -F _git_commit git-commit
+complete -o default -o nospace -F _git_describe git-describe
complete -o default -o nospace -F _git_diff git-diff
complete -o default -o nospace -F _git_fetch git-fetch
complete -o default -o nospace -F _git_format_patch git-format-patch
@@ -1080,7 +1221,9 @@
complete -o default -o nospace -F _git_shortlog git-shortlog
complete -o default -o nospace -F _git_show git-show
complete -o default -o nospace -F _git_stash git-stash
+complete -o default -o nospace -F _git_submodule git-submodule
complete -o default -o nospace -F _git_log git-show-branch
+complete -o default -o nospace -F _git_tag git-tag
complete -o default -o nospace -F _git_log git-whatchanged
# The following are necessary only for Cygwin, and only are needed
@@ -1092,7 +1235,9 @@
complete -o default -o nospace -F _git_apply git-apply.exe
complete -o default -o nospace -F _git git.exe
complete -o default -o nospace -F _git_branch git-branch.exe
+complete -o default -o nospace -F _git_bundle git-bundle.exe
complete -o default -o nospace -F _git_cherry git-cherry.exe
+complete -o default -o nospace -F _git_describe git-describe.exe
complete -o default -o nospace -F _git_diff git-diff.exe
complete -o default -o nospace -F _git_format_patch git-format-patch.exe
complete -o default -o nospace -F _git_log git-log.exe
@@ -1104,5 +1249,6 @@
complete -o default -o nospace -F _git_shortlog git-shortlog.exe
complete -o default -o nospace -F _git_show git-show.exe
complete -o default -o nospace -F _git_log git-show-branch.exe
+complete -o default -o nospace -F _git_tag git-tag.exe
complete -o default -o nospace -F _git_log git-whatchanged.exe
fi
diff --git a/contrib/emacs/git.el b/contrib/emacs/git.el
index be44e06..280557e 100644
--- a/contrib/emacs/git.el
+++ b/contrib/emacs/git.el
@@ -99,47 +99,56 @@
(defface git-status-face
- '((((class color) (background light)) (:foreground "purple")))
+ '((((class color) (background light)) (:foreground "purple"))
+ (((class color) (background dark)) (:foreground "salmon")))
"Git mode face used to highlight added and modified files."
:group 'git)
(defface git-unmerged-face
- '((((class color) (background light)) (:foreground "red" :bold t)))
+ '((((class color) (background light)) (:foreground "red" :bold t))
+ (((class color) (background dark)) (:foreground "red" :bold t)))
"Git mode face used to highlight unmerged files."
:group 'git)
(defface git-unknown-face
- '((((class color) (background light)) (:foreground "goldenrod" :bold t)))
+ '((((class color) (background light)) (:foreground "goldenrod" :bold t))
+ (((class color) (background dark)) (:foreground "goldenrod" :bold t)))
"Git mode face used to highlight unknown files."
:group 'git)
(defface git-uptodate-face
- '((((class color) (background light)) (:foreground "grey60")))
+ '((((class color) (background light)) (:foreground "grey60"))
+ (((class color) (background dark)) (:foreground "grey40")))
"Git mode face used to highlight up-to-date files."
:group 'git)
(defface git-ignored-face
- '((((class color) (background light)) (:foreground "grey60")))
+ '((((class color) (background light)) (:foreground "grey60"))
+ (((class color) (background dark)) (:foreground "grey40")))
"Git mode face used to highlight ignored files."
:group 'git)
(defface git-mark-face
- '((((class color) (background light)) (:foreground "red" :bold t)))
+ '((((class color) (background light)) (:foreground "red" :bold t))
+ (((class color) (background dark)) (:foreground "tomato" :bold t)))
"Git mode face used for the file marks."
:group 'git)
(defface git-header-face
- '((((class color) (background light)) (:foreground "blue")))
+ '((((class color) (background light)) (:foreground "blue"))
+ (((class color) (background dark)) (:foreground "blue")))
"Git mode face used for commit headers."
:group 'git)
(defface git-separator-face
- '((((class color) (background light)) (:foreground "brown")))
+ '((((class color) (background light)) (:foreground "brown"))
+ (((class color) (background dark)) (:foreground "brown")))
"Git mode face used for commit separator."
:group 'git)
(defface git-permission-face
- '((((class color) (background light)) (:foreground "green" :bold t)))
+ '((((class color) (background light)) (:foreground "green" :bold t))
+ (((class color) (background dark)) (:foreground "green" :bold t)))
"Git mode face used for permission changes."
:group 'git)
@@ -664,9 +673,11 @@
(ewoc-set-hf status
(format "Directory: %s\nBranch: %s\nHead: %s%s\n"
default-directory
- (if (string-match "^refs/heads/" branch)
- (substring branch (match-end 0))
- branch)
+ (if branch
+ (if (string-match "^refs/heads/" branch)
+ (substring branch (match-end 0))
+ branch)
+ "none (detached HEAD)")
head
(if merge-heads
(concat "\nMerging: "
diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4
index 6d01062..55778c5 100755
--- a/contrib/fast-import/git-p4
+++ b/contrib/fast-import/git-p4
@@ -231,6 +231,56 @@
return ["", settings]
+def createOrUpdateBranchesFromOrigin(localRefPrefix = "refs/remotes/p4/", silent=True):
+ if not silent:
+ print ("Creating/updating branch(es) in %s based on origin branch(es)"
+ % localRefPrefix)
+
+ originPrefix = "origin/p4/"
+
+ for line in read_pipe_lines("git rev-parse --symbolic --remotes"):
+ line = line.strip()
+ if (not line.startswith(originPrefix)) or line.endswith("HEAD"):
+ continue
+
+ headName = line[len(originPrefix):]
+ remoteHead = localRefPrefix + headName
+ originHead = line
+
+ original = extractSettingsGitLog(extractLogMessageFromGitCommit(originHead))
+ if (not original.has_key('depot-paths')
+ or not original.has_key('change')):
+ continue
+
+ update = False
+ if not gitBranchExists(remoteHead):
+ if verbose:
+ print "creating %s" % remoteHead
+ update = True
+ else:
+ settings = extractSettingsGitLog(extractLogMessageFromGitCommit(remoteHead))
+ if settings.has_key('change') > 0:
+ if settings['depot-paths'] == original['depot-paths']:
+ originP4Change = int(original['change'])
+ p4Change = int(settings['change'])
+ if originP4Change > p4Change:
+ print ("%s (%s) is newer than %s (%s). "
+ "Updating p4 branch from origin."
+ % (originHead, originP4Change,
+ remoteHead, p4Change))
+ update = True
+ else:
+ print ("Ignoring: %s was imported from %s while "
+ "%s was imported from %s"
+ % (originHead, ','.join(original['depot-paths']),
+ remoteHead, ','.join(settings['depot-paths'])))
+
+ if update:
+ system("git update-ref %s %s" % (remoteHead, originHead))
+
+def originP4BranchesExist():
+ return gitBranchExists("origin") or gitBranchExists("origin/p4") or gitBranchExists("origin/p4/master")
+
class Command:
def __init__(self):
self.usage = "usage: %prog [options]"
@@ -1041,53 +1091,6 @@
for branch in branches.keys():
self.initialParents[self.refPrefix + branch] = branches[branch]
- def createOrUpdateBranchesFromOrigin(self):
- if not self.silent:
- print ("Creating/updating branch(es) in %s based on origin branch(es)"
- % self.refPrefix)
-
- originPrefix = "origin/p4/"
-
- for line in read_pipe_lines("git rev-parse --symbolic --remotes"):
- line = line.strip()
- if (not line.startswith(originPrefix)) or line.endswith("HEAD"):
- continue
-
- headName = line[len(originPrefix):]
- remoteHead = self.refPrefix + headName
- originHead = line
-
- original = extractSettingsGitLog(extractLogMessageFromGitCommit(originHead))
- if (not original.has_key('depot-paths')
- or not original.has_key('change')):
- continue
-
- update = False
- if not gitBranchExists(remoteHead):
- if self.verbose:
- print "creating %s" % remoteHead
- update = True
- else:
- settings = extractSettingsGitLog(extractLogMessageFromGitCommit(remoteHead))
- if settings.has_key('change') > 0:
- if settings['depot-paths'] == original['depot-paths']:
- originP4Change = int(original['change'])
- p4Change = int(settings['change'])
- if originP4Change > p4Change:
- print ("%s (%s) is newer than %s (%s). "
- "Updating p4 branch from origin."
- % (originHead, originP4Change,
- remoteHead, p4Change))
- update = True
- else:
- print ("Ignoring: %s was imported from %s while "
- "%s was imported from %s"
- % (originHead, ','.join(original['depot-paths']),
- remoteHead, ','.join(settings['depot-paths'])))
-
- if update:
- system("git update-ref %s %s" % (remoteHead, originHead))
-
def updateOptionDict(self, d):
option_keys = {}
if self.keepRepoPath:
@@ -1108,7 +1111,7 @@
# map from branch depot path to parent branch
self.knownBranches = {}
self.initialParents = {}
- self.hasOrigin = gitBranchExists("origin") or gitBranchExists("origin/p4") or gitBranchExists("origin/p4/master")
+ self.hasOrigin = originP4BranchesExist()
if not self.syncWithOrigin:
self.hasOrigin = False
@@ -1128,14 +1131,14 @@
system("git update-ref %s refs/heads/p4" % self.branch)
system("git branch -D p4");
# create it /after/ importing, when master exists
- if not gitBranchExists(self.refPrefix + "HEAD") and self.importIntoRemotes:
+ if not gitBranchExists(self.refPrefix + "HEAD") and self.importIntoRemotes and gitBranchExists(self.branch):
system("git symbolic-ref %sHEAD %s" % (self.refPrefix, self.branch))
# TODO: should always look at previous commits,
# merge with previous imports, if possible.
if args == []:
if self.hasOrigin:
- self.createOrUpdateBranchesFromOrigin()
+ createOrUpdateBranchesFromOrigin(self.refPrefix, self.silent)
self.listExistingP4GitBranches()
if len(self.p4BranchesInGit) > 1:
@@ -1518,6 +1521,9 @@
self.verbose = False
def run(self, args):
+ if originP4BranchesExist():
+ createOrUpdateBranchesFromOrigin()
+
cmdline = "git rev-parse --symbolic "
cmdline += " --remotes"
diff --git a/contrib/workdir/git-new-workdir b/contrib/workdir/git-new-workdir
index 3ff6bd1..c6e154a 100755
--- a/contrib/workdir/git-new-workdir
+++ b/contrib/workdir/git-new-workdir
@@ -24,9 +24,21 @@
git rev-parse --git-dir 2>/dev/null) ||
die "\"$orig_git\" is not a git repository!"
-if test "$git_dir" = ".git"
-then
+case "$git_dir" in
+.git)
git_dir="$orig_git/.git"
+ ;;
+.)
+ git_dir=$orig_git
+ ;;
+esac
+
+# don't link to a configured bare repository
+isbare=$(git --git-dir="$git_dir" config --bool --get core.bare)
+if test ztrue = z$isbare
+then
+ die "\"$git_dir\" has core.bare set to true," \
+ " remove from \"$git_dir/config\" to use $0"
fi
# don't link to a workdir
diff --git a/diff-delta.c b/diff-delta.c
index 3af5835..0dde2f2 100644
--- a/diff-delta.c
+++ b/diff-delta.c
@@ -213,7 +213,7 @@
entry = hash[i];
do {
struct index_entry *keep = entry;
- int skip = hash_count[i] / HASH_LIMIT / 2;
+ int skip = hash_count[i] / HASH_LIMIT;
do {
entry = entry->next;
} while(--skip && entry);
diff --git a/diff.c b/diff.c
index 97cc5bc..0d30d05 100644
--- a/diff.c
+++ b/diff.c
@@ -19,6 +19,7 @@
static int diff_detect_rename_default;
static int diff_rename_limit_default = -1;
static int diff_use_color_default;
+int diff_auto_refresh_index = 1;
static char diff_colors[][COLOR_MAXLEN] = {
"\033[m", /* reset */
@@ -166,6 +167,10 @@
diff_detect_rename_default = DIFF_DETECT_RENAME;
return 0;
}
+ if (!strcmp(var, "diff.autorefreshindex")) {
+ diff_auto_refresh_index = git_config_bool(var, value);
+ return 0;
+ }
if (!prefixcmp(var, "diff.")) {
const char *ep = strrchr(var, '.');
@@ -2919,10 +2924,6 @@
fill_mmfile(&mf2, p->two) < 0)
return error("unable to read files to diff");
- /* Maybe hash p->two? into the patch id? */
- if (diff_filespec_is_binary(p->two))
- continue;
-
len1 = remove_space(p->one->path, strlen(p->one->path));
len2 = remove_space(p->two->path, strlen(p->two->path));
if (p->one->mode == 0)
diff --git a/fast-import.c b/fast-import.c
index 170cccd..078079d 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -8,10 +8,11 @@
| new_tag
| reset_branch
| checkpoint
+ | progress
;
new_blob ::= 'blob' lf
- mark?
+ mark?
file_content;
file_content ::= data;
@@ -23,7 +24,7 @@
('from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)?
('merge' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)*
file_change*
- lf;
+ lf?;
commit_msg ::= data;
file_change ::= file_clr
@@ -42,33 +43,36 @@
new_tag ::= 'tag' sp tag_str lf
'from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf
- 'tagger' sp name '<' email '>' when lf
+ 'tagger' sp name '<' email '>' when lf
tag_msg;
tag_msg ::= data;
reset_branch ::= 'reset' sp ref_str lf
('from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)?
- lf;
+ lf?;
checkpoint ::= 'checkpoint' lf
- lf;
+ lf?;
+
+ progress ::= 'progress' sp not_lf* lf
+ lf?;
# note: the first idnum in a stream should be 1 and subsequent
# idnums should not have gaps between values as this will cause
# the stream parser to reserve space for the gapped values. An
- # idnum can be updated in the future to a new object by issuing
+ # idnum can be updated in the future to a new object by issuing
# a new mark directive with the old idnum.
- #
+ #
mark ::= 'mark' sp idnum lf;
data ::= (delimited_data | exact_data)
- lf;
+ lf?;
# note: delim may be any string but must not contain lf.
# data_line may contain any data but must not be exactly
# delim.
delimited_data ::= 'data' sp '<<' delim lf
(data_line lf)*
- delim lf;
+ delim lf;
# note: declen indicates the length of binary_data in bytes.
# declen does not include the lf preceeding the binary data.
@@ -78,10 +82,10 @@
# note: quoted strings are C-style quoting supporting \c for
# common escapes of 'c' (e..g \n, \t, \\, \") or \nnn where nnn
- # is the signed byte value in octal. Note that the only
+ # is the signed byte value in octal. Note that the only
# characters which must actually be escaped to protect the
# stream formatting is: \, " and LF. Otherwise these values
- # are UTF8.
+ # are UTF8.
#
ref_str ::= ref;
sha1exp_str ::= sha1exp;
@@ -104,9 +108,9 @@
lf ::= # ASCII newline (LF) character;
# note: a colon (':') must precede the numerical value assigned to
- # an idnum. This is to distinguish it from a ref or tag name as
+ # an idnum. This is to distinguish it from a ref or tag name as
# GIT does not permit ':' in ref or tag strings.
- #
+ #
idnum ::= ':' bigint;
path ::= # GIT style file path, e.g. "a/b/c";
ref ::= # GIT ref name, e.g. "refs/heads/MOZ_GECKO_EXPERIMENT";
@@ -115,13 +119,24 @@
hexsha1 ::= # SHA1 in hexadecimal format;
# note: name and email are UTF8 strings, however name must not
- # contain '<' or lf and email must not contain any of the
+ # contain '<' or lf and email must not contain any of the
# following: '<', '>', lf.
- #
+ #
name ::= # valid GIT author/committer name;
email ::= # valid GIT author/committer email;
ts ::= # time since the epoch in seconds, ascii base10 notation;
tz ::= # GIT style timezone;
+
+ # note: comments may appear anywhere in the input, except
+ # within a data command. Any form of the data command
+ # always escapes the related input from comment processing.
+ #
+ # In case it is not clear, the '#' that starts the comment
+ # must be the first character on that the line (an lf have
+ # preceeded it).
+ #
+ comment ::= '#' not_lf* lf;
+ not_lf ::= # Any byte that is not ASCII newline (LF);
*/
#include "builtin.h"
@@ -254,6 +269,13 @@
WHENSPEC_NOW,
} whenspec_type;
+struct recent_command
+{
+ struct recent_command *prev;
+ struct recent_command *next;
+ char *buf;
+};
+
/* Configured limits on output */
static unsigned long max_depth = 10;
static off_t max_packsize = (1LL << 32) - 1;
@@ -319,9 +341,120 @@
/* Input stream parsing */
static whenspec_type whenspec = WHENSPEC_RAW;
static struct strbuf command_buf;
+static int unread_command_buf;
+static struct recent_command cmd_hist = {&cmd_hist, &cmd_hist, NULL};
+static struct recent_command *cmd_tail = &cmd_hist;
+static struct recent_command *rc_free;
+static unsigned int cmd_save = 100;
static uintmax_t next_mark;
static struct dbuf new_data;
+static void write_branch_report(FILE *rpt, struct branch *b)
+{
+ fprintf(rpt, "%s:\n", b->name);
+
+ fprintf(rpt, " status :");
+ if (b->active)
+ fputs(" active", rpt);
+ if (b->branch_tree.tree)
+ fputs(" loaded", rpt);
+ if (is_null_sha1(b->branch_tree.versions[1].sha1))
+ fputs(" dirty", rpt);
+ fputc('\n', rpt);
+
+ fprintf(rpt, " tip commit : %s\n", sha1_to_hex(b->sha1));
+ fprintf(rpt, " old tree : %s\n", sha1_to_hex(b->branch_tree.versions[0].sha1));
+ fprintf(rpt, " cur tree : %s\n", sha1_to_hex(b->branch_tree.versions[1].sha1));
+ fprintf(rpt, " commit clock: %" PRIuMAX "\n", b->last_commit);
+
+ fputs(" last pack : ", rpt);
+ if (b->pack_id < MAX_PACK_ID)
+ fprintf(rpt, "%u", b->pack_id);
+ fputc('\n', rpt);
+
+ fputc('\n', rpt);
+}
+
+static void write_crash_report(const char *err)
+{
+ char *loc = git_path("fast_import_crash_%d", getpid());
+ FILE *rpt = fopen(loc, "w");
+ struct branch *b;
+ unsigned long lu;
+ struct recent_command *rc;
+
+ if (!rpt) {
+ error("can't write crash report %s: %s", loc, strerror(errno));
+ return;
+ }
+
+ fprintf(stderr, "fast-import: dumping crash report to %s\n", loc);
+
+ fprintf(rpt, "fast-import crash report:\n");
+ fprintf(rpt, " fast-import process: %d\n", getpid());
+ fprintf(rpt, " parent process : %d\n", getppid());
+ fprintf(rpt, " at %s\n", show_date(time(NULL), 0, DATE_LOCAL));
+ fputc('\n', rpt);
+
+ fputs("fatal: ", rpt);
+ fputs(err, rpt);
+ fputc('\n', rpt);
+
+ fputc('\n', rpt);
+ fputs("Most Recent Commands Before Crash\n", rpt);
+ fputs("---------------------------------\n", rpt);
+ for (rc = cmd_hist.next; rc != &cmd_hist; rc = rc->next) {
+ if (rc->next == &cmd_hist)
+ fputs("* ", rpt);
+ else
+ fputs(" ", rpt);
+ fputs(rc->buf, rpt);
+ fputc('\n', rpt);
+ }
+
+ fputc('\n', rpt);
+ fputs("Active Branch LRU\n", rpt);
+ fputs("-----------------\n", rpt);
+ fprintf(rpt, " active_branches = %lu cur, %lu max\n",
+ cur_active_branches,
+ max_active_branches);
+ fputc('\n', rpt);
+ fputs(" pos clock name\n", rpt);
+ fputs(" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", rpt);
+ for (b = active_branches, lu = 0; b; b = b->active_next_branch)
+ fprintf(rpt, " %2lu) %6" PRIuMAX" %s\n",
+ ++lu, b->last_commit, b->name);
+
+ fputc('\n', rpt);
+ fputs("Inactive Branches\n", rpt);
+ fputs("-----------------\n", rpt);
+ for (lu = 0; lu < branch_table_sz; lu++) {
+ for (b = branch_table[lu]; b; b = b->table_next_branch)
+ write_branch_report(rpt, b);
+ }
+
+ fputc('\n', rpt);
+ fputs("-------------------\n", rpt);
+ fputs("END OF CRASH REPORT\n", rpt);
+ fclose(rpt);
+}
+
+static NORETURN void die_nicely(const char *err, va_list params)
+{
+ static int zombie;
+ char message[2 * PATH_MAX];
+
+ vsnprintf(message, sizeof(message), err, params);
+ fputs("fatal: ", stderr);
+ fputs(message, stderr);
+ fputc('\n', stderr);
+
+ if (!zombie) {
+ zombie = 1;
+ write_crash_report(message);
+ }
+ exit(128);
+}
static void alloc_objects(unsigned int cnt)
{
@@ -524,8 +657,12 @@
if (b)
die("Invalid attempt to create duplicate branch: %s", name);
- if (check_ref_format(name))
+ switch (check_ref_format(name)) {
+ case 0: break; /* its valid */
+ case -2: break; /* valid, but too few '/', allow anyway */
+ default:
die("Branch name doesn't conform to GIT standards: %s", name);
+ }
b = pool_calloc(1, sizeof(struct branch));
b->name = pool_strdup(name);
@@ -1450,7 +1587,43 @@
static void read_next_command(void)
{
- read_line(&command_buf, stdin, '\n');
+ do {
+ if (unread_command_buf) {
+ unread_command_buf = 0;
+ if (command_buf.eof)
+ return;
+ } else {
+ struct recent_command *rc;
+
+ command_buf.buf = NULL;
+ read_line(&command_buf, stdin, '\n');
+ if (command_buf.eof)
+ return;
+
+ rc = rc_free;
+ if (rc)
+ rc_free = rc->next;
+ else {
+ rc = cmd_hist.next;
+ cmd_hist.next = rc->next;
+ cmd_hist.next->prev = &cmd_hist;
+ free(rc->buf);
+ }
+
+ rc->buf = command_buf.buf;
+ rc->prev = cmd_tail;
+ rc->next = cmd_hist.prev;
+ rc->prev->next = rc;
+ cmd_tail = rc;
+ }
+ } while (command_buf.buf[0] == '#');
+}
+
+static void skip_optional_lf(void)
+{
+ int term_char = fgetc(stdin);
+ if (term_char != '\n' && term_char != EOF)
+ ungetc(term_char, stdin);
}
static void cmd_mark(void)
@@ -1476,19 +1649,15 @@
size_t sz = 8192, term_len = command_buf.len - 5 - 2;
length = 0;
buffer = xmalloc(sz);
+ command_buf.buf = NULL;
for (;;) {
- read_next_command();
+ read_line(&command_buf, stdin, '\n');
if (command_buf.eof)
die("EOF in data (terminator '%s' not found)", term);
if (term_len == command_buf.len
&& !strcmp(term, command_buf.buf))
break;
- if (sz < (length + command_buf.len)) {
- sz = sz * 3 / 2 + 16;
- if (sz < (length + command_buf.len))
- sz = length + command_buf.len;
- buffer = xrealloc(buffer, sz);
- }
+ ALLOC_GROW(buffer, length + command_buf.len, sz);
memcpy(buffer + length,
command_buf.buf,
command_buf.len - 1);
@@ -1510,9 +1679,7 @@
}
}
- if (fgetc(stdin) != '\n')
- die("An lf did not trail the binary data as expected.");
-
+ skip_optional_lf();
*size = length;
return buffer;
}
@@ -1808,13 +1975,13 @@
}
}
-static void cmd_from(struct branch *b)
+static int cmd_from(struct branch *b)
{
const char *from;
struct branch *s;
if (prefixcmp(command_buf.buf, "from "))
- return;
+ return 0;
if (b->branch_tree.tree) {
release_tree_content_recursive(b->branch_tree.tree);
@@ -1849,6 +2016,7 @@
die("Invalid ref name or SHA1 expression: %s", from);
read_next_command();
+ return 1;
}
static struct hash_list *cmd_merge(unsigned int *count)
@@ -1933,10 +2101,8 @@
}
/* file_change* */
- for (;;) {
- if (1 == command_buf.len)
- break;
- else if (!prefixcmp(command_buf.buf, "M "))
+ while (!command_buf.eof && command_buf.len > 1) {
+ if (!prefixcmp(command_buf.buf, "M "))
file_change_m(b);
else if (!prefixcmp(command_buf.buf, "D "))
file_change_d(b);
@@ -1946,8 +2112,10 @@
file_change_cr(b, 0);
else if (!strcmp("deleteall", command_buf.buf))
file_change_deleteall(b);
- else
- die("Unsupported file_change: %s", command_buf.buf);
+ else {
+ unread_command_buf = 1;
+ break;
+ }
read_next_command();
}
@@ -2088,7 +2256,8 @@
else
b = new_branch(sp);
read_next_command();
- cmd_from(b);
+ if (!cmd_from(b) && command_buf.len > 1)
+ unread_command_buf = 1;
}
static void cmd_checkpoint(void)
@@ -2099,7 +2268,15 @@
dump_tags();
dump_marks();
}
- read_next_command();
+ skip_optional_lf();
+}
+
+static void cmd_progress(void)
+{
+ fwrite(command_buf.buf, 1, command_buf.len - 1, stdout);
+ fputc('\n', stdout);
+ fflush(stdout);
+ skip_optional_lf();
}
static void import_marks(const char *input_file)
@@ -2142,7 +2319,7 @@
int main(int argc, const char **argv)
{
- int i, show_stats = 1;
+ unsigned int i, show_stats = 1;
git_config(git_default_config);
alloc_objects(object_entry_alloc);
@@ -2196,8 +2373,14 @@
if (i != argc)
usage(fast_import_usage);
+ rc_free = pool_alloc(cmd_save * sizeof(*rc_free));
+ for (i = 0; i < (cmd_save - 1); i++)
+ rc_free[i].next = &rc_free[i + 1];
+ rc_free[cmd_save - 1].next = NULL;
+
prepare_packed_git();
start_packfile();
+ set_die_routine(die_nicely);
for (;;) {
read_next_command();
if (command_buf.eof)
@@ -2212,6 +2395,8 @@
cmd_reset_branch();
else if (!strcmp("checkpoint", command_buf.buf))
cmd_checkpoint();
+ else if (!prefixcmp(command_buf.buf, "progress "))
+ cmd_progress();
else
die("Unsupported command: %s", command_buf.buf);
}
diff --git a/git-am.sh b/git-am.sh
index b5ed8ca..6809aa0 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -2,8 +2,10 @@
#
# Copyright (c) 2005, 2006 Junio C Hamano
-USAGE='[--signoff] [--dotest=<dir>] [--utf8 | --no-utf8] [--binary] [--3way]
- [--interactive] [--whitespace=<option>] [-C<n>] [-p<n>] <mbox>...
+USAGE='[--signoff] [--dotest=<dir>] [--keep] [--utf8 | --no-utf8]
+ [--3way] [--interactive] [--binary]
+ [--whitespace=<option>] [-C<n>] [-p<n>]
+ <mbox>|<Maildir>...
or, when resuming [--skip | --resolved]'
. git-sh-setup
set_reflog_action am
diff --git a/git-archimport.perl b/git-archimport.perl
index b210772..9a7a906 100755
--- a/git-archimport.perl
+++ b/git-archimport.perl
@@ -595,7 +595,11 @@
my $pid = open2(*READER, *WRITER,'git-commit-tree',$tree,@par)
or die $!;
print WRITER $ps->{summary},"\n\n";
- print WRITER $ps->{message},"\n";
+
+ # only print message if it's not empty, to avoid a spurious blank line;
+ # also append an extra newline, so there's a blank line before the
+ # following "git-archimport-id:" line.
+ print WRITER $ps->{message},"\n\n" if ($ps->{message} ne "");
# make it easy to backtrack and figure out which Arch revision this was:
print WRITER 'git-archimport-id: ',$ps->{id},"\n";
diff --git a/git-clone.sh b/git-clone.sh
index e4a9ac4..18003ab 100755
--- a/git-clone.sh
+++ b/git-clone.sh
@@ -99,6 +99,7 @@
use_separate_remote=t
depth=
no_progress=
+local_explicitly_asked_for=
test -t 1 || no_progress=--no-progress
while
case "$#,$1" in
@@ -109,6 +110,7 @@
*,--na|*,--nak|*,--nake|*,--naked|\
*,-b|*,--b|*,--ba|*,--bar|*,--bare) bare=yes ;;
*,-l|*,--l|*,--lo|*,--loc|*,--loca|*,--local)
+ local_explicitly_asked_for=yes
use_local_hardlink=yes ;;
*,--no-h|*,--no-ha|*,--no-har|*,--no-hard|*,--no-hardl|\
*,--no-hardli|*,--no-hardlin|*,--no-hardlink|*,--no-hardlinks)
@@ -281,7 +283,8 @@
then
rm -f "$GIT_DIR/objects/sample"
l=l
- else
+ elif test -n "$local_explicitly_asked_for"
+ then
echo >&2 "Warning: -l asked but cannot hardlink to $repo"
fi
fi &&
diff --git a/git-commit.sh b/git-commit.sh
index d7e7028..1d04f1f 100755
--- a/git-commit.sh
+++ b/git-commit.sh
@@ -49,10 +49,11 @@
export GIT_INDEX_FILE
fi
- case "$status_only" in
- t) color= ;;
- *) color=--nocolor ;;
- esac
+ if test "$status_only" = "t" -o "$use_status_color" = "t"; then
+ color=
+ else
+ color=--nocolor
+ fi
git runstatus ${color} \
${verbose:+--verbose} \
${amend:+--amend} \
@@ -556,6 +557,7 @@
if [ "$?" != "0" -a ! -f "$GIT_DIR/MERGE_HEAD" -a -z "$amend" ]
then
rm -f "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
+ use_status_color=t
run_status
exit 1
fi
diff --git a/git-filter-branch.sh b/git-filter-branch.sh
index c42e451..a4b6577 100755
--- a/git-filter-branch.sh
+++ b/git-filter-branch.sh
@@ -8,9 +8,6 @@
# a new branch. You can specify a number of filters to modify the commits,
# files and trees.
-USAGE="git-filter-branch [-d TEMPDIR] [FILTERS] DESTBRANCH [REV-RANGE]"
-. git-sh-setup
-
warn () {
echo "$*" >&2
}
@@ -26,6 +23,20 @@
fi
}
+# if you run 'skip_commit "$@"' in a commit filter, it will print
+# the (mapped) parents, effectively skipping the commit.
+
+skip_commit()
+{
+ shift;
+ while [ -n "$1" ];
+ do
+ shift;
+ map "$1";
+ shift;
+ done;
+}
+
# override die(): this version puts in an extra line break, so that
# the progress is still visible
@@ -69,6 +80,20 @@
echo "[ -n \"\$GIT_${uid}_NAME\" ] || export GIT_${uid}_NAME=\"\${GIT_${uid}_EMAIL%%@*}\""
}
+# This script can be sourced by the commit filter to get the functions
+test "a$SOURCE_FUNCTIONS" = a1 && return
+this_script="$(cd "$(dirname "$0")"; pwd)"/$(basename "$0")
+export this_script
+
+USAGE="[--env-filter <command>] [--tree-filter <command>] \
+[--index-filter <command>] [--parent-filter <command>] \
+[--msg-filter <command>] [--commit-filter <command>] \
+[--tag-name-filter <command>] [--subdirectory-filter <directory>] \
+[--original <namespace>] [-d <directory>] [-f | --force] \
+[<rev-list options>...]"
+
+. git-sh-setup
+
tempdir=.git-rewrite
filter_env=
filter_tree=
@@ -125,7 +150,7 @@
filter_msg="$OPTARG"
;;
--commit-filter)
- filter_commit="$OPTARG"
+ filter_commit='SOURCE_FUNCTIONS=1 . "$this_script";'" $OPTARG"
;;
--tag-name-filter)
filter_tag_name="$OPTARG"
@@ -134,7 +159,7 @@
filter_subdir="$OPTARG"
;;
--original)
- orig_namespace="$OPTARG"
+ orig_namespace=$(expr "$OPTARG/" : '\(.*[^/]\)/*$')/
;;
*)
usage
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 671b887..fa30ccc 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -62,54 +62,6 @@
######################################################################
##
-## configure our library
-
-set oguilib {@@GITGUI_LIBDIR@@}
-set oguirel {@@GITGUI_RELATIVE@@}
-if {$oguirel eq {1}} {
- set oguilib [file dirname [file dirname [file normalize $argv0]]]
- set oguilib [file join $oguilib share git-gui lib]
-} elseif {[string match @@* $oguirel]} {
- set oguilib [file join [file dirname [file normalize $argv0]] lib]
-}
-
-set idx [file join $oguilib tclIndex]
-if {[catch {set fd [open $idx r]} err]} {
- catch {wm withdraw .}
- tk_messageBox \
- -icon error \
- -type ok \
- -title "git-gui: fatal error" \
- -message $err
- exit 1
-}
-if {[gets $fd] eq {# Autogenerated by git-gui Makefile}} {
- set idx [list]
- while {[gets $fd n] >= 0} {
- if {$n ne {} && ![string match #* $n]} {
- lappend idx $n
- }
- }
-} else {
- set idx {}
-}
-close $fd
-
-if {$idx ne {}} {
- set loaded [list]
- foreach p $idx {
- if {[lsearch -exact $loaded $p] >= 0} continue
- source [file join $oguilib $p]
- lappend loaded $p
- }
- unset loaded p
-} else {
- set auto_path [concat [list $oguilib] $auto_path]
-}
-unset -nocomplain oguirel idx fd
-
-######################################################################
-##
## read only globals
set _appname [lindex [file split $argv0] end]
@@ -532,7 +484,11 @@
if {[catch {set _git_version [git --version]} err]} {
catch {wm withdraw .}
- error_popup "Cannot determine Git version:
+ tk_messageBox \
+ -icon error \
+ -type ok \
+ -title "git-gui: fatal error" \
+ -message "Cannot determine Git version:
$err
@@ -541,7 +497,11 @@
}
if {![regsub {^git version } $_git_version {} _git_version]} {
catch {wm withdraw .}
- error_popup "Cannot parse Git version string:\n\n$_git_version"
+ tk_messageBox \
+ -icon error \
+ -type ok \
+ -title "git-gui: fatal error" \
+ -message "Cannot parse Git version string:\n\n$_git_version"
exit 1
}
@@ -619,7 +579,11 @@
if {[git-version < 1.5]} {
catch {wm withdraw .}
- error_popup "[appname] requires Git 1.5.0 or later.
+ tk_messageBox \
+ -icon error \
+ -type ok \
+ -title "git-gui: fatal error" \
+ -message "[appname] requires Git 1.5.0 or later.
You are using [git-version]:
@@ -629,6 +593,54 @@
######################################################################
##
+## configure our library
+
+set oguilib {@@GITGUI_LIBDIR@@}
+set oguirel {@@GITGUI_RELATIVE@@}
+if {$oguirel eq {1}} {
+ set oguilib [file dirname [file dirname [file normalize $argv0]]]
+ set oguilib [file join $oguilib share git-gui lib]
+} elseif {[string match @@* $oguirel]} {
+ set oguilib [file join [file dirname [file normalize $argv0]] lib]
+}
+
+set idx [file join $oguilib tclIndex]
+if {[catch {set fd [open $idx r]} err]} {
+ catch {wm withdraw .}
+ tk_messageBox \
+ -icon error \
+ -type ok \
+ -title "git-gui: fatal error" \
+ -message $err
+ exit 1
+}
+if {[gets $fd] eq {# Autogenerated by git-gui Makefile}} {
+ set idx [list]
+ while {[gets $fd n] >= 0} {
+ if {$n ne {} && ![string match #* $n]} {
+ lappend idx $n
+ }
+ }
+} else {
+ set idx {}
+}
+close $fd
+
+if {$idx ne {}} {
+ set loaded [list]
+ foreach p $idx {
+ if {[lsearch -exact $loaded $p] >= 0} continue
+ source [file join $oguilib $p]
+ lappend loaded $p
+ }
+ unset loaded p
+} else {
+ set auto_path [concat [list $oguilib] $auto_path]
+}
+unset -nocomplain oguirel idx fd
+
+######################################################################
+##
## feature option selection
if {[regexp {^git-(.+)$} [appname] _junk subcommand]} {
@@ -691,7 +703,15 @@
error_popup "Git directory not found:\n\n$_gitdir"
exit 1
}
-if {![is_enabled bare]} {
+if {$_prefix ne {}} {
+ regsub -all {[^/]+/} $_prefix ../ cdup
+ if {[catch {cd $cdup} err]} {
+ catch {wm withdraw .}
+ error_popup "Cannot move to top of working directory:\n\n$err"
+ exit 1
+ }
+ unset cdup
+} elseif {![is_enabled bare]} {
if {[lindex [file split $_gitdir] end] ne {.git}} {
catch {wm withdraw .}
error_popup "Cannot use funny .git directory:\n\n$_gitdir"
@@ -726,6 +746,7 @@
set current_branch {}
set is_detached 0
set current_diff_path {}
+set is_3way_diff 0
set selected_commit_type new
######################################################################
@@ -1348,6 +1369,9 @@
proc bind_button3 {w cmd} {
bind $w <Any-Button-3> $cmd
if {[is_MacOSX]} {
+ # Mac OS X sends Button-2 on right click through three-button mouse,
+ # or through trackpad right-clicking (two-finger touch + click).
+ bind $w <Any-Button-2> $cmd
bind $w <Control-Button-1> $cmd
}
}
@@ -1933,6 +1957,12 @@
}
unset browser doc_path doc_url
+set root_exists 0
+bind . <Visibility> {
+ bind . <Visibility> {}
+ set root_exists 1
+}
+
# -- Standard bindings
#
wm protocol . WM_DELETE_WINDOW do_quit
@@ -2407,21 +2437,26 @@
$ctxm add command -label {Options...} \
-command do_options
proc popup_diff_menu {ctxm x y X Y} {
+ global current_diff_path file_states
set ::cursorX $x
set ::cursorY $y
if {$::ui_index eq $::current_diff_side} {
- $ctxm entryconf $::ui_diff_applyhunk \
- -state normal \
- -label {Unstage Hunk From Commit}
- } elseif {{_O} eq [lindex $::file_states($::current_diff_path) 0]} {
- $ctxm entryconf $::ui_diff_applyhunk \
- -state disabled \
- -label {Stage Hunk For Commit}
+ set s normal
+ set l "Unstage Hunk From Commit"
} else {
- $ctxm entryconf $::ui_diff_applyhunk \
- -state normal \
- -label {Stage Hunk For Commit}
+ if {$current_diff_path eq {}
+ || ![info exists file_states($current_diff_path)]
+ || {_O} eq [lindex $file_states($current_diff_path) 0]} {
+ set s disabled
+ } else {
+ set s normal
+ }
+ set l "Stage Hunk For Commit"
}
+ if {$::is_3way_diff} {
+ set s disabled
+ }
+ $ctxm entryconf $::ui_diff_applyhunk -state $s -label $l
tk_popup $ctxm $X $Y
}
bind_button3 $ui_diff [list popup_diff_menu $ctxm %x %y %X %Y]
diff --git a/git-gui/lib/class.tcl b/git-gui/lib/class.tcl
index 24e8cec..dc21411 100644
--- a/git-gui/lib/class.tcl
+++ b/git-gui/lib/class.tcl
@@ -148,11 +148,12 @@
}
}
- if {[winfo ismapped .]} {
+ if {$::root_exists || [winfo ismapped .]} {
regsub -all {::} $this {__} w
set top .$w
set pfx $top
toplevel $top
+ set ::root_exists 1
} else {
set top .
set pfx {}
diff --git a/git-gui/lib/merge.tcl b/git-gui/lib/merge.tcl
index 5de0d82..0e50919 100644
--- a/git-gui/lib/merge.tcl
+++ b/git-gui/lib/merge.tcl
@@ -114,7 +114,7 @@
lappend cmd --strategy=recursive
lappend cmd [git fmt-merge-msg <[gitdir FETCH_HEAD]]
lappend cmd HEAD
- lappend cmd $cmit
+ lappend cmd $name
set msg "Merging $current_branch and $stitle"
ui_status "$msg..."
diff --git a/git-merge-resolve.sh b/git-merge-resolve.sh
index bb19da2..93bcfc2 100755
--- a/git-merge-resolve.sh
+++ b/git-merge-resolve.sh
@@ -25,7 +25,7 @@
esac
done
-# Give up if we are given more than two remotes -- not handling octopus.
+# Give up if we are given two or more remotes -- not handling octopus.
case "$remotes" in
?*' '?*)
exit 2 ;;
diff --git a/git-merge-stupid.sh b/git-merge-stupid.sh
index 4b1e595..f612d47 100755
--- a/git-merge-stupid.sh
+++ b/git-merge-stupid.sh
@@ -24,7 +24,7 @@
esac
done
-# Give up if we are given more than two remotes -- not handling octopus.
+# Give up if we are given two or more remotes -- not handling octopus.
case "$remotes" in
?*' '?*)
exit 2 ;;
diff --git a/git-merge.sh b/git-merge.sh
index 5ccf282..3a01db0 100755
--- a/git-merge.sh
+++ b/git-merge.sh
@@ -19,10 +19,12 @@
all_strategies='recur recursive octopus resolve stupid ours subtree'
default_twohead_strategies='recursive'
default_octopus_strategies='octopus'
-no_trivial_merge_strategies='ours subtree'
+no_fast_forward_strategies='subtree ours'
+no_trivial_strategies='recursive recur subtree ours'
use_strategies=
-index_merge=t
+allow_fast_forward=t
+allow_trivial_merge=t
dropsave() {
rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" \
@@ -265,11 +267,20 @@
for s in $use_strategies
do
- for nt in $no_trivial_merge_strategies
+ for ss in $no_fast_forward_strategies
do
case " $s " in
- *" $nt "*)
- index_merge=f
+ *" $ss "*)
+ allow_fast_forward=f
+ break
+ ;;
+ esac
+ done
+ for ss in $no_trivial_strategies
+ do
+ case " $s " in
+ *" $ss "*)
+ allow_trivial_merge=f
break
;;
esac
@@ -286,10 +297,7 @@
esac
echo "$head" >"$GIT_DIR/ORIG_HEAD"
-case "$index_merge,$#,$common,$no_commit" in
-f,*)
- # We've been told not to try anything clever. Skip to real merge.
- ;;
+case "$allow_fast_forward,$#,$common,$no_commit" in
?,*,'',*)
# No common ancestors found. We need a real merge.
;;
@@ -299,7 +307,7 @@
finish_up_to_date "Already up-to-date."
exit 0
;;
-?,1,"$head",*)
+t,1,"$head",*)
# Again the most common case of merging one remote.
echo "Updating $(git rev-parse --short $head)..$(git rev-parse --short $1)"
git update-index --refresh 2>/dev/null
@@ -322,11 +330,8 @@
# We are not doing octopus, not fast forward, and have only
# one common.
git update-index --refresh 2>/dev/null
- case " $use_strategies " in
- *' recursive '*|*' recur '*)
- : run merge later
- ;;
- *)
+ case "$allow_trivial_merge" in
+ t)
# See if it is really trivial.
git var GIT_COMMITTER_IDENT >/dev/null || exit
echo "Trying really trivial in-index merge..."
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index bdec462..abc2b1c 100755
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -96,13 +96,14 @@
}
pick_one () {
- case "$1" in -n) sha1=$2 ;; *) sha1=$1 ;; esac
+ no_ff=
+ case "$1" in -n) sha1=$2; no_ff=t ;; *) sha1=$1 ;; esac
output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1"
test -d "$REWRITTEN" &&
pick_one_preserving_merges "$@" && return
parent_sha1=$(git rev-parse --verify $sha1^ 2>/dev/null)
current_sha1=$(git rev-parse --verify HEAD)
- if test $current_sha1 = $parent_sha1; then
+ if test $no_ff$current_sha1 = $parent_sha1; then
output git reset --hard $sha1
test "a$1" = a-n && output git reset --soft $current_sha1
sha1=$(git rev-parse --short $sha1)
@@ -189,7 +190,7 @@
make_squash_message () {
if test -f "$SQUASH_MSG"; then
- COUNT=$(($(sed -n "s/^# This is [^0-9]*\([0-9]\+\).*/\1/p" \
+ COUNT=$(($(sed -n "s/^# This is [^0-9]*\([1-9][0-9]*\).*/\1/p" \
< "$SQUASH_MSG" | tail -n 1)+1))
echo "# This is a combination of $COUNT commits."
sed -n "2,\$p" < "$SQUASH_MSG"
diff --git a/git-rebase.sh b/git-rebase.sh
index cbafa14..3bd66b0 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -59,20 +59,20 @@
die "$RESOLVEMSG"
fi
+ cmt=`cat $dotest/current`
if ! git diff-index --quiet HEAD
then
- if ! git-commit -C "`cat $dotest/current`"
+ if ! git-commit -C "$cmt"
then
echo "Commit failed, please do not call \"git commit\""
echo "directly, but instead do one of the following: "
die "$RESOLVEMSG"
fi
- printf "Committed: %0${prec}d" $msgnum
+ printf "Committed: %0${prec}d " $msgnum
else
- printf "Already applied: %0${prec}d" $msgnum
+ printf "Already applied: %0${prec}d " $msgnum
fi
- echo ' '`git rev-list --pretty=oneline -1 HEAD | \
- sed 's/^[a-f0-9]\+ //'`
+ git rev-list --pretty=oneline -1 "$cmt" | sed -e 's/^[^ ]* //'
prev_head=`git rev-parse HEAD^0`
# save the resulting commit so we can read-tree on it later
diff --git a/git-send-email.perl b/git-send-email.perl
index 4767249..e0b7d12 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -21,8 +21,11 @@
use Term::ReadLine;
use Getopt::Long;
use Data::Dumper;
+use Term::ANSIColor;
use Git;
+$SIG{INT} = sub { print color("reset"), "\n"; exit };
+
package FakeTerm;
sub new {
my ($class, $reason) = @_;
diff --git a/git-submodule.sh b/git-submodule.sh
index 2cfeadd..3320998 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -313,7 +313,7 @@
,,1,,)
modules_update "$@"
;;
-,,,1,*)
+,,,*,*)
modules_list "$@"
;;
*)
diff --git a/git-svn.perl b/git-svn.perl
index d162114..d3c8cd0 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -77,11 +77,12 @@
\$Git::SVN::_repack_flags,
%remote_opts );
-my ($_trunk, $_tags, $_branches);
+my ($_trunk, $_tags, $_branches, $_stdlayout);
my %icv;
my %init_opts = ( 'template=s' => \$_template, 'shared:s' => \$_shared,
'trunk|T=s' => \$_trunk, 'tags|t=s' => \$_tags,
'branches|b=s' => \$_branches, 'prefix=s' => \$_prefix,
+ 'stdlayout|s' => \$_stdlayout,
'minimize-url|m' => \$Git::SVN::_minimize_url,
'no-metadata' => sub { $icv{noMetadata} = 1 },
'use-svm-props' => sub { $icv{useSvmProps} = 1 },
@@ -292,7 +293,8 @@
sub cmd_clone {
my ($url, $path) = @_;
if (!defined $path &&
- (defined $_trunk || defined $_branches || defined $_tags) &&
+ (defined $_trunk || defined $_branches || defined $_tags ||
+ defined $_stdlayout) &&
$url !~ m#^[a-z\+]+://#) {
$path = $url;
}
@@ -302,6 +304,11 @@
}
sub cmd_init {
+ if (defined $_stdlayout) {
+ $_trunk = 'trunk' if (!defined $_trunk);
+ $_tags = 'tags' if (!defined $_tags);
+ $_branches = 'branches' if (!defined $_branches);
+ }
if (defined $_trunk || defined $_branches || defined $_tags) {
return cmd_multi_init(@_);
}
@@ -370,12 +377,19 @@
$head ||= 'HEAD';
my @refs;
my ($url, $rev, $uuid, $gs) = working_head_info($head, \@refs);
+ print "Committing to $url ...\n";
unless ($gs) {
die "Unable to determine upstream SVN information from ",
"$head history\n";
}
my $last_rev;
my ($linear_refs, $parents) = linearize_history($gs, \@refs);
+ if ($_no_rebase && scalar(@$linear_refs) > 1) {
+ warn "Attempting to commit more than one change while ",
+ "--no-rebase is enabled.\n",
+ "If these changes depend on each other, re-running ",
+ "without --no-rebase will be required."
+ }
foreach my $d (@$linear_refs) {
unless (defined $last_rev) {
(undef, $last_rev, undef) = cmt_metadata("$d~1");
@@ -387,6 +401,7 @@
if ($_dry_run) {
print "diff-tree $d~1 $d\n";
} else {
+ my $cmt_rev;
my %ed_opts = ( r => $last_rev,
log => get_commit_entry($d)->{log},
ra => Git::SVN::Ra->new($gs->full_url),
@@ -394,42 +409,39 @@
tree_b => $d,
editor_cb => sub {
print "Committed r$_[0]\n";
- $last_rev = $_[0]; },
+ $cmt_rev = $_[0];
+ },
svn_path => '');
if (!SVN::Git::Editor->new(\%ed_opts)->apply_diff) {
print "No changes\n$d~1 == $d\n";
} elsif ($parents->{$d} && @{$parents->{$d}}) {
- $gs->{inject_parents_dcommit}->{$last_rev} =
+ $gs->{inject_parents_dcommit}->{$cmt_rev} =
$parents->{$d};
}
+ $_fetch_all ? $gs->fetch_all : $gs->fetch;
+ next if $_no_rebase;
+
+ # we always want to rebase against the current HEAD,
+ # not any head that was passed to us
+ my @diff = command('diff-tree', 'HEAD',
+ $gs->refname, '--');
+ my @finish;
+ if (@diff) {
+ @finish = rebase_cmd();
+ print STDERR "W: HEAD and ", $gs->refname,
+ " differ, using @finish:\n",
+ "@diff";
+ } else {
+ print "No changes between current HEAD and ",
+ $gs->refname,
+ "\nResetting to the latest ",
+ $gs->refname, "\n";
+ @finish = qw/reset --mixed/;
+ }
+ command_noisy(@finish, $gs->refname);
+ $last_rev = $cmt_rev;
}
}
- return if $_dry_run;
- unless ($gs) {
- warn "Could not determine fetch information for $url\n",
- "Will not attempt to fetch and rebase commits.\n",
- "This probably means you have useSvmProps and should\n",
- "now resync your SVN::Mirror repository.\n";
- return;
- }
- $_fetch_all ? $gs->fetch_all : $gs->fetch;
- unless ($_no_rebase) {
- # we always want to rebase against the current HEAD, not any
- # head that was passed to us
- my @diff = command('diff-tree', 'HEAD', $gs->refname, '--');
- my @finish;
- if (@diff) {
- @finish = rebase_cmd();
- print STDERR "W: HEAD and ", $gs->refname, " differ, ",
- "using @finish:\n", "@diff";
- } else {
- print "No changes between current HEAD and ",
- $gs->refname, "\nResetting to the latest ",
- $gs->refname, "\n";
- @finish = qw/reset --mixed/;
- }
- command_noisy(@finish, $gs->refname);
- }
}
sub cmd_find_rev {
@@ -799,7 +811,7 @@
sub working_head_info {
my ($head, $refs) = @_;
- my ($fh, $ctx) = command_output_pipe('log', $head);
+ my ($fh, $ctx) = command_output_pipe('log', '--no-color', $head);
my $hash;
my %max;
while (<$fh>) {
@@ -2064,7 +2076,7 @@
return;
}
print "Rebuilding $db_path ...\n";
- my ($log, $ctx) = command_output_pipe("log", $self->refname);
+ my ($log, $ctx) = command_output_pipe("log", '--no-color', $self->refname);
my $latest;
my $full_url = $self->full_url;
remove_username($full_url);
diff --git a/git.c b/git.c
index cab0e72..fd3d83c 100644
--- a/git.c
+++ b/git.c
@@ -4,7 +4,7 @@
#include "quote.h"
const char git_usage_string[] =
- "git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate] [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE] [--help] COMMAND [ARGS]";
+ "git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate|--no-pager] [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE] [--help] COMMAND [ARGS]";
static void prepend_to_path(const char *dir, int len)
{
@@ -58,6 +58,10 @@
}
} else if (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) {
setup_pager();
+ } else if (!strcmp(cmd, "--no-pager")) {
+ setenv("GIT_PAGER", "cat", 1);
+ if (envchanged)
+ *envchanged = 1;
} else if (!strcmp(cmd, "--git-dir")) {
if (*argc < 2) {
fprintf(stderr, "No directory given for --git-dir.\n" );
@@ -89,7 +93,8 @@
*envchanged = 1;
} else if (!strcmp(cmd, "--bare")) {
static char git_dir[PATH_MAX+1];
- setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 1);
+ is_bare_repository_cfg = 1;
+ setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 0);
if (envchanged)
*envchanged = 1;
} else {
diff --git a/gitk b/gitk
index 57617d5..300fdce 100755
--- a/gitk
+++ b/gitk
@@ -519,6 +519,7 @@
global textfont mainfont uifont tabstop
global findtype findtypemenu findloc findstring fstring geometry
global entries sha1entry sha1string sha1but
+ global diffcontextstring diffcontext
global maincursor textcursor curtextcursor
global rowctxmenu fakerowmenu mergemax wrapcomment
global highlight_files gdttype
@@ -532,6 +533,7 @@
menu .bar.file
.bar.file add command -label "Update" -command updatecommits
.bar.file add command -label "Reread references" -command rereadrefs
+ .bar.file add command -label "List references" -command showrefs
.bar.file add command -label "Quit" -command doquit
.bar.file configure -font $uifont
menu .bar.edit
@@ -733,7 +735,17 @@
-command changediffdisp -variable diffelide -value {0 1}
radiobutton .bleft.mid.new -text "New version" \
-command changediffdisp -variable diffelide -value {1 0}
+ label .bleft.mid.labeldiffcontext -text " Lines of context: " \
+ -font $uifont
pack .bleft.mid.diff .bleft.mid.old .bleft.mid.new -side left
+ spinbox .bleft.mid.diffcontext -width 5 -font $textfont \
+ -from 1 -increment 1 -to 10000000 \
+ -validate all -validatecommand "diffcontextvalidate %P" \
+ -textvariable diffcontextstring
+ .bleft.mid.diffcontext set $diffcontext
+ trace add variable diffcontextstring write diffcontextchange
+ lappend entries .bleft.mid.diffcontext
+ pack .bleft.mid.labeldiffcontext .bleft.mid.diffcontext -side left
set ctext .bleft.ctext
text $ctext -background $bgcolor -foreground $fgcolor \
-tabs "[expr {$tabstop * $charspc}]" \
@@ -1001,8 +1013,8 @@
global stuffsaved findmergefiles maxgraphpct
global maxwidth showneartags showlocalchanges
global viewname viewfiles viewargs viewperm nextviewnum
- global cmitmode wrapcomment
- global colors bgcolor fgcolor diffcolors selectbgcolor
+ global cmitmode wrapcomment datetimeformat
+ global colors bgcolor fgcolor diffcolors diffcontext selectbgcolor
if {$stuffsaved} return
if {![winfo viewable .]} return
@@ -1019,10 +1031,12 @@
puts $f [list set wrapcomment $wrapcomment]
puts $f [list set showneartags $showneartags]
puts $f [list set showlocalchanges $showlocalchanges]
+ puts $f [list set datetimeformat $datetimeformat]
puts $f [list set bgcolor $bgcolor]
puts $f [list set fgcolor $fgcolor]
puts $f [list set colors $colors]
puts $f [list set diffcolors $diffcolors]
+ puts $f [list set diffcontext $diffcontext]
puts $f [list set selectbgcolor $selectbgcolor]
puts $f "set geometry(main) [wm geometry .]"
@@ -1453,6 +1467,38 @@
0x00, 0x00};
}
+image create bitmap reficon-T -background black -foreground yellow -data {
+ #define tagicon_width 13
+ #define tagicon_height 9
+ static unsigned char tagicon_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xf0, 0x07, 0xf8, 0x07,
+ 0xfc, 0x07, 0xf8, 0x07, 0xf0, 0x07, 0x00, 0x00, 0x00, 0x00};
+} -maskdata {
+ #define tagicon-mask_width 13
+ #define tagicon-mask_height 9
+ static unsigned char tagicon-mask_bits[] = {
+ 0x00, 0x00, 0xf0, 0x0f, 0xf8, 0x0f, 0xfc, 0x0f,
+ 0xfe, 0x0f, 0xfc, 0x0f, 0xf8, 0x0f, 0xf0, 0x0f, 0x00, 0x00};
+}
+set rectdata {
+ #define headicon_width 13
+ #define headicon_height 9
+ static unsigned char headicon_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0xf8, 0x07,
+ 0xf8, 0x07, 0xf8, 0x07, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00};
+}
+set rectmask {
+ #define headicon-mask_width 13
+ #define headicon-mask_height 9
+ static unsigned char headicon-mask_bits[] = {
+ 0x00, 0x00, 0xfc, 0x0f, 0xfc, 0x0f, 0xfc, 0x0f,
+ 0xfc, 0x0f, 0xfc, 0x0f, 0xfc, 0x0f, 0xfc, 0x0f, 0x00, 0x00};
+}
+image create bitmap reficon-H -background black -foreground green \
+ -data $rectdata -maskdata $rectmask
+image create bitmap reficon-o -background black -foreground "#ddddff" \
+ -data $rectdata -maskdata $rectmask
+
proc init_flist {first} {
global cflist cflist_top selectedline difffilestart
@@ -1975,6 +2021,7 @@
} elseif {$numcommits == 0} {
show_status "No commits selected"
}
+ run refill_reflist
}
# Stuff relating to the highlighting facility
@@ -2738,13 +2785,22 @@
proc showstuff {canshow last} {
global numcommits commitrow pending_select selectedline curview
global lookingforhead mainheadid displayorder selectfirst
- global lastscrollset
+ global lastscrollset commitinterest
if {$numcommits == 0} {
global phase
set phase "incrdraw"
allcanvs delete all
}
+ for {set l $numcommits} {$l < $canshow} {incr l} {
+ set id [lindex $displayorder $l]
+ if {[info exists commitinterest($id)]} {
+ foreach script $commitinterest($id) {
+ eval [string map [list "%I" $id] $script]
+ }
+ unset commitinterest($id)
+ }
+ }
set r0 $numcommits
set prev $numcommits
set numcommits $canshow
@@ -4471,6 +4527,7 @@
$canv delete hover
normalline
cancel_next_highlight
+ unsel_reflist
if {$l < 0 || $l >= $numcommits} return
set y [expr {$canvy0 + $l * $linespc}]
set ymax [lindex [$canv cget -scrollregion] 3]
@@ -5052,12 +5109,29 @@
return 0
}
+# empty string or positive integer
+proc diffcontextvalidate {v} {
+ return [regexp {^(|[1-9][0-9]*)$} $v]
+}
+
+proc diffcontextchange {n1 n2 op} {
+ global diffcontextstring diffcontext
+
+ if {[string is integer -strict $diffcontextstring]} {
+ if {$diffcontextstring > 0} {
+ set diffcontext $diffcontextstring
+ reselectline
+ }
+ }
+}
+
proc getblobdiffs {ids} {
global diffopts blobdifffd diffids env
global diffinhdr treediffs
+ global diffcontext
set env(GIT_DIFF_OPTS) $diffopts
- if {[catch {set bdf [open [diffcmd $ids {-p -C --no-commit-id}] r]} err]} {
+ if {[catch {set bdf [open [diffcmd $ids "-p -C --no-commit-id -U$diffcontext"] r]} err]} {
puts "error getting diffs: $err"
return
}
@@ -5116,8 +5190,8 @@
# the middle char will be a space, and the two bits either
# side will be a/name and b/name, or "a/name" and "b/name".
# If the name has changed we'll get "rename from" and
- # "rename to" lines following this, and we'll use them
- # to get the filenames.
+ # "rename to" or "copy from" and "copy to" lines following this,
+ # and we'll use them to get the filenames.
# This complexity is necessary because spaces in the filename(s)
# don't get escaped.
set l [string length $line]
@@ -5141,8 +5215,9 @@
set diffinhdr 0
} elseif {$diffinhdr} {
- if {![string compare -length 12 "rename from " $line]} {
- set fname [string range $line 12 end]
+ if {![string compare -length 12 "rename from " $line] ||
+ ![string compare -length 10 "copy from " $line]} {
+ set fname [string range $line [expr 6 + [string first " from " $line] ] end]
if {[string index $fname 0] eq "\""} {
set fname [lindex $fname 0]
}
@@ -5150,8 +5225,9 @@
if {$i >= 0} {
setinlist difffilestart $i $curdiffstart
}
- } elseif {![string compare -length 10 $line "rename to "]} {
- set fname [string range $line 10 end]
+ } elseif {![string compare -length 10 $line "rename to "] ||
+ ![string compare -length 8 $line "copy to "]} {
+ set fname [string range $line [expr 4 + [string first " to " $line] ] end]
if {[string index $fname 0] eq "\""} {
set fname [lindex $fname 0]
}
@@ -5382,7 +5458,7 @@
}
proc incrfont {inc} {
- global mainfont textfont ctext canv phase cflist
+ global mainfont textfont ctext canv phase cflist showrefstop
global charspc tabstop
global stopped entries
unmarkmatches
@@ -5398,6 +5474,9 @@
if {$phase eq "getcommits"} {
$canv itemconf textitems -font $mainfont
}
+ if {[info exists showrefstop] && [winfo exists $showrefstop]} {
+ $showrefstop.list conf -font $mainfont
+ }
redisplay
}
@@ -5856,6 +5935,8 @@
lappend idtags($id) $tag
redrawtags $id
addedtag $id
+ dispneartags 0
+ run refill_reflist
}
proc redrawtags {id} {
@@ -5997,6 +6078,7 @@
notbusy newbranch
redrawtags $id
dispneartags 0
+ run refill_reflist
}
}
@@ -6168,7 +6250,7 @@
proc rmbranch {} {
global headmenuid headmenuhead mainhead
- global headids idheads
+ global idheads
set head $headmenuhead
set id $headmenuid
@@ -6178,7 +6260,7 @@
return
}
set dheads [descheads $id]
- if {$dheads eq $headids($head)} {
+ if {[llength $dheads] == 1 && $idheads($dheads) eq $head} {
# the stuff on this branch isn't on any other branch
if {![confirm_popup "The commits on branch $head aren't on any other\
branch.\nReally delete branch $head?"]} return
@@ -6195,6 +6277,163 @@
redrawtags $id
notbusy rmbranch
dispneartags 0
+ run refill_reflist
+}
+
+# Display a list of tags and heads
+proc showrefs {} {
+ global showrefstop bgcolor fgcolor selectbgcolor mainfont
+ global bglist fglist uifont reflistfilter reflist maincursor
+
+ set top .showrefs
+ set showrefstop $top
+ if {[winfo exists $top]} {
+ raise $top
+ refill_reflist
+ return
+ }
+ toplevel $top
+ wm title $top "Tags and heads: [file tail [pwd]]"
+ text $top.list -background $bgcolor -foreground $fgcolor \
+ -selectbackground $selectbgcolor -font $mainfont \
+ -xscrollcommand "$top.xsb set" -yscrollcommand "$top.ysb set" \
+ -width 30 -height 20 -cursor $maincursor \
+ -spacing1 1 -spacing3 1 -state disabled
+ $top.list tag configure highlight -background $selectbgcolor
+ lappend bglist $top.list
+ lappend fglist $top.list
+ scrollbar $top.ysb -command "$top.list yview" -orient vertical
+ scrollbar $top.xsb -command "$top.list xview" -orient horizontal
+ grid $top.list $top.ysb -sticky nsew
+ grid $top.xsb x -sticky ew
+ frame $top.f
+ label $top.f.l -text "Filter: " -font $uifont
+ entry $top.f.e -width 20 -textvariable reflistfilter -font $uifont
+ set reflistfilter "*"
+ trace add variable reflistfilter write reflistfilter_change
+ pack $top.f.e -side right -fill x -expand 1
+ pack $top.f.l -side left
+ grid $top.f - -sticky ew -pady 2
+ button $top.close -command [list destroy $top] -text "Close" \
+ -font $uifont
+ grid $top.close -
+ grid columnconfigure $top 0 -weight 1
+ grid rowconfigure $top 0 -weight 1
+ bind $top.list <1> {break}
+ bind $top.list <B1-Motion> {break}
+ bind $top.list <ButtonRelease-1> {sel_reflist %W %x %y; break}
+ set reflist {}
+ refill_reflist
+}
+
+proc sel_reflist {w x y} {
+ global showrefstop reflist headids tagids otherrefids
+
+ if {![winfo exists $showrefstop]} return
+ set l [lindex [split [$w index "@$x,$y"] "."] 0]
+ set ref [lindex $reflist [expr {$l-1}]]
+ set n [lindex $ref 0]
+ switch -- [lindex $ref 1] {
+ "H" {selbyid $headids($n)}
+ "T" {selbyid $tagids($n)}
+ "o" {selbyid $otherrefids($n)}
+ }
+ $showrefstop.list tag add highlight $l.0 "$l.0 lineend"
+}
+
+proc unsel_reflist {} {
+ global showrefstop
+
+ if {![info exists showrefstop] || ![winfo exists $showrefstop]} return
+ $showrefstop.list tag remove highlight 0.0 end
+}
+
+proc reflistfilter_change {n1 n2 op} {
+ global reflistfilter
+
+ after cancel refill_reflist
+ after 200 refill_reflist
+}
+
+proc refill_reflist {} {
+ global reflist reflistfilter showrefstop headids tagids otherrefids
+ global commitrow curview commitinterest
+
+ if {![info exists showrefstop] || ![winfo exists $showrefstop]} return
+ set refs {}
+ foreach n [array names headids] {
+ if {[string match $reflistfilter $n]} {
+ if {[info exists commitrow($curview,$headids($n))]} {
+ lappend refs [list $n H]
+ } else {
+ set commitinterest($headids($n)) {run refill_reflist}
+ }
+ }
+ }
+ foreach n [array names tagids] {
+ if {[string match $reflistfilter $n]} {
+ if {[info exists commitrow($curview,$tagids($n))]} {
+ lappend refs [list $n T]
+ } else {
+ set commitinterest($tagids($n)) {run refill_reflist}
+ }
+ }
+ }
+ foreach n [array names otherrefids] {
+ if {[string match $reflistfilter $n]} {
+ if {[info exists commitrow($curview,$otherrefids($n))]} {
+ lappend refs [list $n o]
+ } else {
+ set commitinterest($otherrefids($n)) {run refill_reflist}
+ }
+ }
+ }
+ set refs [lsort -index 0 $refs]
+ if {$refs eq $reflist} return
+
+ # Update the contents of $showrefstop.list according to the
+ # differences between $reflist (old) and $refs (new)
+ $showrefstop.list conf -state normal
+ $showrefstop.list insert end "\n"
+ set i 0
+ set j 0
+ while {$i < [llength $reflist] || $j < [llength $refs]} {
+ if {$i < [llength $reflist]} {
+ if {$j < [llength $refs]} {
+ set cmp [string compare [lindex $reflist $i 0] \
+ [lindex $refs $j 0]]
+ if {$cmp == 0} {
+ set cmp [string compare [lindex $reflist $i 1] \
+ [lindex $refs $j 1]]
+ }
+ } else {
+ set cmp -1
+ }
+ } else {
+ set cmp 1
+ }
+ switch -- $cmp {
+ -1 {
+ $showrefstop.list delete "[expr {$j+1}].0" "[expr {$j+2}].0"
+ incr i
+ }
+ 0 {
+ incr i
+ incr j
+ }
+ 1 {
+ set l [expr {$j + 1}]
+ $showrefstop.list image create $l.0 -align baseline \
+ -image reficon-[lindex $refs $j 1] -padx 2
+ $showrefstop.list insert $l.1 "[lindex $refs $j 0]\n"
+ incr j
+ }
+ }
+ }
+ set reflist $refs
+ # delete last newline
+ $showrefstop.list delete end-2c end-1c
+ $showrefstop.list conf -state disabled
}
# Stuff for finding nearby tags
@@ -6402,8 +6641,9 @@
proc addnewchild {id p} {
global allids allparents allchildren idtags nextarc nbmp
global arcnos arcids arctags arcout arcend arcstart archeads growing
- global seeds
+ global seeds allcommits
+ if {![info exists allcommits]} return
lappend allids $id
set allparents($id) [list $p]
set allchildren($id) {}
@@ -7092,6 +7332,7 @@
redrawtags $id
}
}
+ run refill_reflist
}
proc listrefs {id} {
@@ -7312,8 +7553,9 @@
}
proc formatdate {d} {
+ global datetimeformat
if {$d ne {}} {
- set d [clock format $d -format "%Y-%m-%d %H:%M:%S"]
+ set d [clock format $d -format $datetimeformat]
}
return $d
}
@@ -7626,11 +7868,13 @@
set maxrefs 20
set maxlinelen 200
set showlocalchanges 1
+set datetimeformat "%Y-%m-%d %H:%M:%S"
set colors {green red blue magenta darkgrey brown orange}
set bgcolor white
set fgcolor black
set diffcolors {red "#00a000" blue}
+set diffcontext 3
set selectbgcolor gray85
catch {source ~/.gitk}
diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css
index 096313b..1b88879 100644
--- a/gitweb/gitweb.css
+++ b/gitweb/gitweb.css
@@ -430,7 +430,7 @@
font-size: 100%;
font-weight: normal;
margin: 4px 8px;
- position: absolute;
+ float: right;
top: 56px;
right: 12px
}
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index f282a67..b2bae1b 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -471,9 +471,6 @@
our $searchtext = $cgi->param('s');
our $search_regexp;
if (defined $searchtext) {
- if ($searchtype ne 'grep' and $searchtype ne 'pickaxe' and $searchtext =~ m/[^a-zA-Z0-9_\.\/\-\+\:\@ ]/) {
- die_error(undef, "Invalid search parameter");
- }
if (length($searchtext) < 2) {
die_error(undef, "At least two characters are required for search parameter");
}
@@ -3422,7 +3419,7 @@
"<td>" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary"),
-class => "list", -title => $pr->{'descr_long'}},
esc_html($pr->{'descr'})) . "</td>\n" .
- "<td><i>" . chop_str($pr->{'owner'}, 15) . "</i></td>\n";
+ "<td><i>" . esc_html(chop_str($pr->{'owner'}, 15)) . "</i></td>\n";
print "<td class=\"". age_class($pr->{'age'}) . "\">" .
(defined $pr->{'age_string'} ? $pr->{'age_string'} : "No commits") . "</td>\n" .
"<td class=\"link\">" .
@@ -3798,7 +3795,7 @@
print "<div class=\"title\"> </div>\n";
print "<table cellspacing=\"0\">\n" .
"<tr><td>description</td><td>" . esc_html($descr) . "</td></tr>\n" .
- "<tr><td>owner</td><td>$owner</td></tr>\n";
+ "<tr><td>owner</td><td>" . esc_html($owner) . "</td></tr>\n";
if (defined $cd{'rfc2822'}) {
print "<tr><td>last change</td><td>$cd{'rfc2822'}</td></tr>\n";
}
diff --git a/perl/Git.pm b/perl/Git.pm
index 8fd3611..3f4080c 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -860,7 +860,13 @@
if ($self->{i} >= scalar @{$self->{data}}) {
return undef;
}
- return $self->{'data'}->[ $self->{i}++ ];
+ my $i = $self->{i};
+ if (wantarray) {
+ $self->{i} = $#{$self->{'data'}} + 1;
+ return splice(@{$self->{'data'}}, $i);
+ }
+ $self->{i} = $i + 1;
+ return $self->{'data'}->[ $i ];
}
sub CLOSE {
diff --git a/perl/Makefile.PL b/perl/Makefile.PL
index 4375161..6aecd89 100644
--- a/perl/Makefile.PL
+++ b/perl/Makefile.PL
@@ -29,5 +29,6 @@
VERSION_FROM => 'Git.pm',
PM => \%pm,
MAKEFILE => 'perl.mak',
+ INSTALLSITEMAN3DIR => '$(SITEPREFIX)/share/man/man3',
%extra
);
diff --git a/revision.c b/revision.c
index 7d32a89..c193c3e 100644
--- a/revision.c
+++ b/revision.c
@@ -896,7 +896,8 @@
continue;
argv[i] = NULL;
argc = i;
- revs->prune_data = get_pathspec(revs->prefix, argv + i + 1);
+ if (argv[i + 1])
+ revs->prune_data = get_pathspec(revs->prefix, argv + i + 1);
seen_dashdash = 1;
break;
}
@@ -1277,6 +1278,9 @@
compile_grep_patterns(revs->grep_filter);
}
+ if (revs->reverse && revs->reflog_info)
+ die("cannot combine --reverse with --walk-reflogs");
+
return left;
}
diff --git a/sha1_file.c b/sha1_file.c
index b219d4d..9978a58 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1570,6 +1570,10 @@
(uintmax_t)base_offset, p->pack_name);
delta_data = unpack_compressed_entry(p, w_curs, curpos, delta_size);
+ if (!delta_data)
+ die("failed to unpack compressed delta"
+ " at %"PRIuMAX" from %s",
+ (uintmax_t)curpos, p->pack_name);
result = patch_delta(base, base_size,
delta_data, delta_size,
sizep);
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
new file mode 100755
index 0000000..b14b3ec
--- /dev/null
+++ b/t/t0001-init.sh
@@ -0,0 +1,116 @@
+#!/bin/sh
+
+test_description='git init'
+
+. ./test-lib.sh
+
+check_config () {
+ if test -d "$1" && test -f "$1/config" && test -d "$1/refs"
+ then
+ : happy
+ else
+ echo "expected a directory $1, a file $1/config and $1/refs"
+ return 1
+ fi
+ bare=$(GIT_CONFIG="$1/config" git config --bool core.bare)
+ worktree=$(GIT_CONFIG="$1/config" git config core.worktree) ||
+ worktree=unset
+
+ test "$bare" = "$2" && test "$worktree" = "$3" || {
+ echo "expected bare=$2 worktree=$3"
+ echo " got bare=$bare worktree=$worktree"
+ return 1
+ }
+}
+
+test_expect_success 'plain' '
+ (
+ unset GIT_DIR GIT_WORK_TREE &&
+ mkdir plain &&
+ cd plain &&
+ git init
+ ) &&
+ check_config plain/.git false unset
+'
+
+test_expect_success 'plain with GIT_WORK_TREE' '
+ if (
+ unset GIT_DIR &&
+ mkdir plain-wt &&
+ cd plain-wt &&
+ GIT_WORK_TREE=$(pwd) git init
+ )
+ then
+ echo Should have failed -- GIT_WORK_TREE should not be used
+ false
+ fi
+'
+
+test_expect_success 'plain bare' '
+ (
+ unset GIT_DIR GIT_WORK_TREE GIT_CONFIG &&
+ mkdir plain-bare-1 &&
+ cd plain-bare-1 &&
+ git --bare init
+ ) &&
+ check_config plain-bare-1 true unset
+'
+
+test_expect_success 'plain bare with GIT_WORK_TREE' '
+ if (
+ unset GIT_DIR GIT_CONFIG &&
+ mkdir plain-bare-2 &&
+ cd plain-bare-2 &&
+ GIT_WORK_TREE=$(pwd) git --bare init
+ )
+ then
+ echo Should have failed -- GIT_WORK_TREE should not be used
+ false
+ fi
+'
+
+test_expect_success 'GIT_DIR bare' '
+
+ (
+ unset GIT_CONFIG &&
+ mkdir git-dir-bare.git &&
+ GIT_DIR=git-dir-bare.git git init
+ ) &&
+ check_config git-dir-bare.git true unset
+'
+
+test_expect_success 'GIT_DIR non-bare' '
+
+ (
+ unset GIT_CONFIG &&
+ mkdir non-bare &&
+ cd non-bare &&
+ GIT_DIR=.git git init
+ ) &&
+ check_config non-bare/.git false unset
+'
+
+test_expect_success 'GIT_DIR & GIT_WORK_TREE (1)' '
+
+ (
+ unset GIT_CONFIG &&
+ mkdir git-dir-wt-1.git &&
+ GIT_WORK_TREE=$(pwd) GIT_DIR=git-dir-wt-1.git git init
+ ) &&
+ check_config git-dir-wt-1.git false "$(pwd)"
+'
+
+test_expect_success 'GIT_DIR & GIT_WORK_TREE (2)' '
+
+ if (
+ unset GIT_CONFIG &&
+ mkdir git-dir-wt-2.git &&
+ GIT_WORK_TREE=$(pwd) GIT_DIR=git-dir-wt-2.git git --bare init
+ )
+ then
+ echo Should have failed -- --bare should not be used
+ false
+ fi
+'
+
+test_done
diff --git a/t/t0023-crlf-am.sh b/t/t0023-crlf-am.sh
new file mode 100755
index 0000000..6f8a434
--- /dev/null
+++ b/t/t0023-crlf-am.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+test_description='Test am with auto.crlf'
+
+. ./test-lib.sh
+
+cat >patchfile <<\EOF
+From 38be10072e45dd6b08ce40851e3fca60a31a340b Mon Sep 17 00:00:00 2001
+From: Marius Storm-Olsen <x@y.com>
+Date: Thu, 23 Aug 2007 13:00:00 +0200
+Subject: test1
+
+---
+ foo | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+ create mode 100644 foo
+
+diff --git a/foo b/foo
+new file mode 100644
+index 0000000000000000000000000000000000000000..5716ca5987cbf97d6bb54920bea6adde242d87e6
+--- /dev/null
++++ b/foo
+@@ -0,0 +1 @@
++bar
+EOF
+
+test_expect_success 'setup' '
+
+ git config core.autocrlf true &&
+ echo foo >bar &&
+ git add bar &&
+ test_tick &&
+ git commit -m initial
+
+'
+
+test_expect_success 'am' '
+
+ git am --binary -3 <patchfile &&
+ git diff-files --name-status --exit-code
+
+'
+
+test_done
diff --git a/t/t3050-subprojects-fetch.sh b/t/t3050-subprojects-fetch.sh
new file mode 100755
index 0000000..34f26a8
--- /dev/null
+++ b/t/t3050-subprojects-fetch.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+test_description='fetching and pushing project with subproject'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+ test_tick &&
+ mkdir -p sub && (
+ cd sub &&
+ git init &&
+ >subfile &&
+ git add subfile
+ git commit -m "subproject commit #1"
+ ) &&
+ >mainfile
+ git add sub mainfile &&
+ test_tick &&
+ git commit -m "superproject commit #1"
+'
+
+test_expect_success clone '
+ git clone file://`pwd`/.git cloned &&
+ (git rev-parse HEAD; git ls-files -s) >expected &&
+ (
+ cd cloned &&
+ (git rev-parse HEAD; git ls-files -s) >../actual
+ ) &&
+ diff -u expected actual
+'
+
+test_expect_success advance '
+ echo more >mainfile &&
+ git update-index --force-remove sub &&
+ mv sub/.git sub/.git-disabled &&
+ git add sub/subfile mainfile &&
+ mv sub/.git-disabled sub/.git &&
+ test_tick &&
+ git commit -m "superproject commit #2"
+'
+
+test_expect_success fetch '
+ (git rev-parse HEAD; git ls-files -s) >expected &&
+ (
+ cd cloned &&
+ git pull &&
+ (git rev-parse HEAD; git ls-files -s) >../actual
+ ) &&
+ diff -u expected actual
+'
+
+test_done
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 40d6799..718c9c1 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -264,6 +264,27 @@
test $one = $(git rev-parse HEAD~2)
'
+test_expect_success 'interrupted squash works as expected (case 2)' '
+ for n in one two three four
+ do
+ echo $n >> conflict &&
+ git add conflict &&
+ git commit -m $n
+ done &&
+ one=$(git rev-parse HEAD~3) &&
+ ! FAKE_LINES="3 squash 1 2" git rebase -i HEAD~3 &&
+ (echo one; echo four) > conflict &&
+ git add conflict &&
+ ! git rebase --continue &&
+ (echo one; echo two; echo four) > conflict &&
+ git add conflict &&
+ ! git rebase --continue &&
+ echo resolved > conflict &&
+ git add conflict &&
+ git rebase --continue &&
+ test $one = $(git rev-parse HEAD~2)
+'
+
test_expect_success 'ignore patch if in upstream' '
HEAD=$(git rev-parse HEAD) &&
git checkout -b has-cherry-picked HEAD^ &&
diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh
new file mode 100755
index 0000000..332b2b2
--- /dev/null
+++ b/t/t3406-rebase-message.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+test_description='messages from rebase operation'
+
+. ./test-lib.sh
+
+quick_one () {
+ echo "$1" >"file$1" &&
+ git add "file$1" &&
+ test_tick &&
+ git commit -m "$1"
+}
+
+test_expect_success setup '
+ quick_one O &&
+ git branch topic &&
+ quick_one X &&
+ quick_one A &&
+ quick_one B &&
+ quick_one Y &&
+
+ git checkout topic &&
+ quick_one A &&
+ quick_one B &&
+ quick_one Z
+
+'
+
+cat >expect <<\EOF
+Already applied: 0001 A
+Already applied: 0002 B
+Committed: 0003 Z
+EOF
+
+test_expect_success 'rebase -m' '
+
+ git rebase -m master >report &&
+ sed -n -e "/^Already applied: /p" \
+ -e "/^Committed: /p" report >actual &&
+ diff -u expect actual
+
+'
+
+test_done
diff --git a/t/t6028-merge-up-to-date.sh b/t/t6028-merge-up-to-date.sh
new file mode 100755
index 0000000..f8f3e3f
--- /dev/null
+++ b/t/t6028-merge-up-to-date.sh
@@ -0,0 +1,77 @@
+#!/bin/sh
+
+test_description='merge fast forward and up to date'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+ >file &&
+ git add file &&
+ test_tick &&
+ git commit -m initial &&
+ git tag c0 &&
+
+ echo second >file &&
+ git add file &&
+ test_tick &&
+ git commit -m second &&
+ git tag c1 &&
+ git branch test
+'
+
+test_expect_success 'merge -s recursive up-to-date' '
+
+ git reset --hard c1 &&
+ test_tick &&
+ git merge -s recursive c0 &&
+ expect=$(git rev-parse c1) &&
+ current=$(git rev-parse HEAD) &&
+ test "$expect" = "$current"
+
+'
+
+test_expect_success 'merge -s recursive fast-forward' '
+
+ git reset --hard c0 &&
+ test_tick &&
+ git merge -s recursive c1 &&
+ expect=$(git rev-parse c1) &&
+ current=$(git rev-parse HEAD) &&
+ test "$expect" = "$current"
+
+'
+
+test_expect_success 'merge -s ours up-to-date' '
+
+ git reset --hard c1 &&
+ test_tick &&
+ git merge -s ours c0 &&
+ expect=$(git rev-parse c1) &&
+ current=$(git rev-parse HEAD) &&
+ test "$expect" = "$current"
+
+'
+
+test_expect_success 'merge -s ours fast-forward' '
+
+ git reset --hard c0 &&
+ test_tick &&
+ git merge -s ours c1 &&
+ expect=$(git rev-parse c0^{tree}) &&
+ current=$(git rev-parse HEAD^{tree}) &&
+ test "$expect" = "$current"
+
+'
+
+test_expect_success 'merge -s subtree up-to-date' '
+
+ git reset --hard c1 &&
+ test_tick &&
+ git merge -s subtree c0 &&
+ expect=$(git rev-parse c1) &&
+ current=$(git rev-parse HEAD) &&
+ test "$expect" = "$current"
+
+'
+
+test_done
diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh
index bc6e2dd..e935b20 100755
--- a/t/t7003-filter-branch.sh
+++ b/t/t7003-filter-branch.sh
@@ -138,13 +138,7 @@
git-filter-branch -f --commit-filter "\
if [ \"\$GIT_AUTHOR_NAME\" = \"B V Uips\" ];\
then\
- shift;\
- while [ -n \"\$1\" ];\
- do\
- shift;\
- echo \"\$1\";\
- shift;\
- done;\
+ skip_commit \"\$@\";
else\
git commit-tree \"\$@\";\
fi" removed-author &&
@@ -159,4 +153,14 @@
! git filter-branch -f HEAD^
'
+test_expect_success '"map" works in commit filter' '
+ git filter-branch -f --commit-filter "\
+ parent=\$(git rev-parse \$GIT_COMMIT^) &&
+ mapped=\$(map \$parent) &&
+ actual=\$(echo \"\$@\" | sed \"s/^.*-p //\") &&
+ test \$mapped = \$actual &&
+ git commit-tree \"\$@\";" master~2..master &&
+ git rev-parse --verify master
+'
+
test_done
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index c4fa446..606d4f2 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -185,18 +185,17 @@
EOF
test_expect_success \
'listing tags with substring as pattern must print those matching' '
- git-tag -l a > actual &&
+ git-tag -l "*a*" > actual &&
git diff expect actual
'
cat >expect <<EOF
v0.2.1
v1.0.1
-v1.1.3
EOF
test_expect_success \
- 'listing tags with substring as pattern must print those matching' '
- git-tag -l .1 > actual &&
+ 'listing tags with a suffix as pattern must print those matching' '
+ git-tag -l "*.1" > actual &&
git diff expect actual
'
@@ -205,37 +204,36 @@
t211
EOF
test_expect_success \
- 'listing tags with substring as pattern must print those matching' '
- git-tag -l t21 > actual &&
+ 'listing tags with a prefix as pattern must print those matching' '
+ git-tag -l "t21*" > actual &&
git diff expect actual
'
cat >expect <<EOF
a1
-aa1
EOF
test_expect_success \
- 'listing tags using a name as pattern must print those matching' '
+ 'listing tags using a name as pattern must print that one matching' '
git-tag -l a1 > actual &&
git diff expect actual
'
cat >expect <<EOF
v1.0
-v1.0.1
EOF
test_expect_success \
- 'listing tags using a name as pattern must print those matching' '
+ 'listing tags using a name as pattern must print that one matching' '
git-tag -l v1.0 > actual &&
git diff expect actual
'
cat >expect <<EOF
+v1.0.1
v1.1.3
EOF
test_expect_success \
'listing tags with ? in the pattern should print those matching' '
- git-tag -l "1.1?" > actual &&
+ git-tag -l "v1.?.?" > actual &&
git diff expect actual
'
diff --git a/t/t9106-git-svn-commit-diff-clobber.sh b/t/t9106-git-svn-commit-diff-clobber.sh
index 6f132f2..79b7968 100755
--- a/t/t9106-git-svn-commit-diff-clobber.sh
+++ b/t/t9106-git-svn-commit-diff-clobber.sh
@@ -66,4 +66,34 @@
git-svn dcommit
"
+test_expect_success 'commit another change from svn side' "
+ svn co $svnrepo t.svn &&
+ cd t.svn &&
+ echo third line from svn >> file &&
+ poke file &&
+ svn commit -m 'third line from svn' &&
+ cd .. &&
+ rm -rf t.svn
+ "
+
+test_expect_failure 'multiple dcommit from git-svn will not clobber svn' "
+ git reset --hard refs/remotes/git-svn &&
+ echo new file >> new-file &&
+ git update-index --add new-file &&
+ git commit -a -m 'new file' &&
+ echo clobber > file &&
+ git commit -a -m 'clobber' &&
+ git svn dcommit
+ " || true
+
+
+test_expect_success 'check that rebase really failed' 'test -d .dotest'
+
+test_expect_success 'resolve, continue the rebase and dcommit' "
+ echo clobber and I really mean it > file &&
+ git update-index file &&
+ git rebase --continue &&
+ git svn dcommit
+ "
+
test_done
diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index 6f95305..0595041 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -170,6 +170,53 @@
'git-fast-import <input'
rm -f .git/objects/pack_* .git/objects/index_*
+cat >input <<INPUT_END
+commit .badbranchname
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+corrupt
+COMMIT
+
+from refs/heads/master
+
+INPUT_END
+test_expect_failure \
+ 'B: fail on invalid branch name ".badbranchname"' \
+ 'git-fast-import <input'
+rm -f .git/objects/pack_* .git/objects/index_*
+
+cat >input <<INPUT_END
+commit bad[branch]name
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+corrupt
+COMMIT
+
+from refs/heads/master
+
+INPUT_END
+test_expect_failure \
+ 'B: fail on invalid branch name "bad[branch]name"' \
+ 'git-fast-import <input'
+rm -f .git/objects/pack_* .git/objects/index_*
+
+cat >input <<INPUT_END
+commit TEMP_TAG
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+tag base
+COMMIT
+
+from refs/heads/master
+
+INPUT_END
+test_expect_success \
+ 'B: accept branch name "TEMP_TAG"' \
+ 'git-fast-import <input &&
+ test -f .git/TEMP_TAG &&
+ test `git rev-parse master` = `git rev-parse TEMP_TAG^`'
+rm -f .git/TEMP_TAG
+
###
### series C
###
@@ -731,4 +778,142 @@
'git-fast-import <input &&
test `git-rev-parse N2^{tree}` = `git-rev-parse N3^{tree}`'
+###
+### series O
+###
+
+cat >input <<INPUT_END
+#we will
+commit refs/heads/O1
+# -- ignore all of this text
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+# $GIT_COMMITTER_NAME has inserted here for his benefit.
+data <<COMMIT
+dirty directory copy
+COMMIT
+
+# don't forget the import blank line!
+#
+# yes, we started from our usual base of branch^0.
+# i like branch^0.
+from refs/heads/branch^0
+# and we need to reuse file2/file5 from N3 above.
+M 644 inline file2/file5
+# otherwise the tree will be different
+data <<EOF
+$file5_data
+EOF
+
+# don't forget to copy file2 to file3
+C file2 file3
+#
+# or to delete file5 from file2.
+D file2/file5
+# are we done yet?
+
+INPUT_END
+
+test_expect_success \
+ 'O: comments are all skipped' \
+ 'git-fast-import <input &&
+ test `git-rev-parse N3` = `git-rev-parse O1`'
+
+cat >input <<INPUT_END
+commit refs/heads/O2
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+dirty directory copy
+COMMIT
+from refs/heads/branch^0
+M 644 inline file2/file5
+data <<EOF
+$file5_data
+EOF
+C file2 file3
+D file2/file5
+
+INPUT_END
+
+test_expect_success \
+ 'O: blank lines not necessary after data commands' \
+ 'git-fast-import <input &&
+ test `git-rev-parse N3` = `git-rev-parse O2`'
+
+test_expect_success \
+ 'O: repack before next test' \
+ 'git repack -a -d'
+
+cat >input <<INPUT_END
+commit refs/heads/O3
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+zstring
+COMMIT
+commit refs/heads/O3
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+zof
+COMMIT
+checkpoint
+commit refs/heads/O3
+mark :5
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+zempty
+COMMIT
+checkpoint
+commit refs/heads/O3
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+zcommits
+COMMIT
+reset refs/tags/O3-2nd
+from :5
+INPUT_END
+
+cat >expect <<INPUT_END
+string
+of
+empty
+commits
+INPUT_END
+test_expect_success \
+ 'O: blank lines not necessary after other commands' \
+ 'git-fast-import <input &&
+ test 8 = `find .git/objects/pack -type f | wc -l` &&
+ test `git rev-parse refs/tags/O3-2nd` = `git rev-parse O3^` &&
+ git log --reverse --pretty=oneline O3 | sed s/^.*z// >actual &&
+ git diff expect actual'
+
+cat >input <<INPUT_END
+commit refs/heads/O4
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+zstring
+COMMIT
+commit refs/heads/O4
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+zof
+COMMIT
+progress Two commits down, 2 to go!
+commit refs/heads/O4
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+zempty
+COMMIT
+progress Three commits down, 1 to go!
+commit refs/heads/O4
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+zcommits
+COMMIT
+progress I'm done!
+INPUT_END
+test_expect_success \
+ 'O: progress outputs as requested by input' \
+ 'git-fast-import <input >actual &&
+ grep "progress " <input >expect &&
+ git diff expect actual'
+
test_done