mirror of
https://github.com/git/git.git
synced 2026-01-11 21:33:13 +09:00
Merge branch 'master' into pb/gitpm
This is to resolve the conflicts with Ryan's annotate updates early.
This commit is contained in:
commit
9673198ee8
8
.gitignore
vendored
8
.gitignore
vendored
@ -46,6 +46,7 @@ git-http-push
|
||||
git-imap-send
|
||||
git-index-pack
|
||||
git-init-db
|
||||
git-instaweb
|
||||
git-local-fetch
|
||||
git-log
|
||||
git-lost-found
|
||||
@ -106,6 +107,7 @@ git-ssh-push
|
||||
git-ssh-upload
|
||||
git-status
|
||||
git-stripspace
|
||||
git-svn
|
||||
git-svnimport
|
||||
git-symbolic-ref
|
||||
git-tag
|
||||
@ -135,4 +137,10 @@ git-core.spec
|
||||
*.[ao]
|
||||
*.py[co]
|
||||
config.mak
|
||||
autom4te.cache
|
||||
config.log
|
||||
config.status
|
||||
config.mak.in
|
||||
config.mak.autogen
|
||||
configure
|
||||
git-blame
|
||||
|
||||
@ -25,10 +25,10 @@ DOC_MAN1=$(patsubst %.txt,%.1,$(MAN1_TXT))
|
||||
DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT))
|
||||
|
||||
prefix?=$(HOME)
|
||||
bin=$(prefix)/bin
|
||||
mandir=$(prefix)/man
|
||||
man1=$(mandir)/man1
|
||||
man7=$(mandir)/man7
|
||||
bindir?=$(prefix)/bin
|
||||
mandir?=$(prefix)/man
|
||||
man1dir=$(mandir)/man1
|
||||
man7dir=$(mandir)/man7
|
||||
# DESTDIR=
|
||||
|
||||
INSTALL?=install
|
||||
@ -46,15 +46,16 @@ all: html man
|
||||
|
||||
html: $(DOC_HTML)
|
||||
|
||||
$(DOC_HTML) $(DOC_MAN1) $(DOC_MAN7): asciidoc.conf
|
||||
|
||||
man: man1 man7
|
||||
man1: $(DOC_MAN1)
|
||||
man7: $(DOC_MAN7)
|
||||
|
||||
install: man
|
||||
$(INSTALL) -d -m755 $(DESTDIR)$(man1) $(DESTDIR)$(man7)
|
||||
$(INSTALL) $(DOC_MAN1) $(DESTDIR)$(man1)
|
||||
$(INSTALL) $(DOC_MAN7) $(DESTDIR)$(man7)
|
||||
$(INSTALL) -d -m755 $(DESTDIR)$(man1dir) $(DESTDIR)$(man7dir)
|
||||
$(INSTALL) $(DOC_MAN1) $(DESTDIR)$(man1dir)
|
||||
$(INSTALL) $(DOC_MAN7) $(DESTDIR)$(man7dir)
|
||||
|
||||
|
||||
#
|
||||
|
||||
@ -49,7 +49,7 @@ People on the git mailing list need to be able to read and
|
||||
comment on the changes you are submitting. It is important for
|
||||
a developer to be able to "quote" your changes, using standard
|
||||
e-mail tools, so that they may comment on specific portions of
|
||||
your code. For this reason, all patches should be submited
|
||||
your code. For this reason, all patches should be submitted
|
||||
"inline". WARNING: Be wary of your MUAs word-wrap
|
||||
corrupting your patch. Do not cut-n-paste your patch; you can
|
||||
lose tabs that way if you are not careful.
|
||||
|
||||
@ -9,6 +9,8 @@
|
||||
|
||||
[attributes]
|
||||
caret=^
|
||||
startsb=[
|
||||
endsb=]
|
||||
|
||||
ifdef::backend-docbook[]
|
||||
[gitlink-inlinemacro]
|
||||
|
||||
@ -91,6 +91,18 @@ core.warnAmbiguousRefs::
|
||||
If true, git will warn you if the ref name you passed it is ambiguous
|
||||
and might match multiple refs in the .git/refs/ tree. True by default.
|
||||
|
||||
core.compression::
|
||||
An integer -1..9, indicating the compression level for objects that
|
||||
are not in a pack file. -1 is the zlib and git default. 0 means no
|
||||
compression, and 1..9 are various speed/size tradeoffs, 9 being
|
||||
slowest.
|
||||
|
||||
core.legacyheaders::
|
||||
A boolean which enables the legacy object header format in case
|
||||
you want to interoperate with old clients accessing the object
|
||||
database directly (where the "http://" and "rsync://" protocols
|
||||
count as direct access).
|
||||
|
||||
alias.*::
|
||||
Command aliases for the gitlink:git[1] command wrapper - e.g.
|
||||
after defining "alias.last = cat-file commit HEAD", the invocation
|
||||
@ -104,10 +116,35 @@ apply.whitespace::
|
||||
Tells `git-apply` how to handle whitespaces, in the same way
|
||||
as the '--whitespace' option. See gitlink:git-apply[1].
|
||||
|
||||
pager.color::
|
||||
A boolean to enable/disable colored output when the pager is in
|
||||
use (default is true).
|
||||
|
||||
diff.color::
|
||||
When true (or `always`), always use colors in patch.
|
||||
When false (or `never`), never. When set to `auto`, use
|
||||
colors only when the output is to the terminal.
|
||||
|
||||
diff.color.<slot>::
|
||||
Use customized color for diff colorization. `<slot>`
|
||||
specifies which part of the patch to use the specified
|
||||
color, and is one of `plain` (context text), `meta`
|
||||
(metainformation), `frag` (hunk header), `old` (removed
|
||||
lines), or `new` (added lines). The value for these
|
||||
configuration variables can be one of: `normal`, `bold`,
|
||||
`dim`, `ul`, `blink`, `reverse`, `reset`, `black`,
|
||||
`red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, or
|
||||
`white`.
|
||||
|
||||
diff.renameLimit::
|
||||
The number of files to consider when performing the copy/rename
|
||||
detection; equivalent to the git diff option '-l'.
|
||||
|
||||
diff.renames::
|
||||
Tells git to detect renames. If set to any boolean value, it
|
||||
will enable basic rename detection. If set to "copies" or
|
||||
"copy", it will detect copies, as well.
|
||||
|
||||
format.headers::
|
||||
Additional email headers to include in a patch to be submitted
|
||||
by mail. See gitlink:git-format-patch[1].
|
||||
@ -166,6 +203,10 @@ merge.summary::
|
||||
Whether to include summaries of merged commits in newly created
|
||||
merge commit messages. False by default.
|
||||
|
||||
pack.window::
|
||||
The size of the window used by gitlink:git-pack-objects[1] when no
|
||||
window size is given on the command line. Defaults to 10.
|
||||
|
||||
pull.octopus::
|
||||
The default merge strategy to use when pulling multiple branches
|
||||
at once.
|
||||
@ -181,6 +222,17 @@ showbranch.default::
|
||||
The default set of branches for gitlink:git-show-branch[1].
|
||||
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.
|
||||
|
||||
user.email::
|
||||
Your email address to be recorded in any newly created commits.
|
||||
Can be overridden by the 'GIT_AUTHOR_EMAIL' and 'GIT_COMMITTER_EMAIL'
|
||||
|
||||
@ -93,7 +93,7 @@ machine where the repository is hosted. If you don't want to give them a
|
||||
full shell on the machine, there is a restricted shell which only allows
|
||||
users to do git pushes and pulls; see gitlink:git-shell[1].
|
||||
|
||||
Put all the committers should in the same group, and make the repository
|
||||
Put all the committers in the same group, and make the repository
|
||||
writable by that group:
|
||||
|
||||
------------------------------------------------
|
||||
|
||||
@ -4,18 +4,21 @@
|
||||
-u::
|
||||
Synonym for "-p".
|
||||
|
||||
--raw::
|
||||
Generate the raw format.
|
||||
|
||||
--patch-with-raw::
|
||||
Generate patch but keep also the default raw diff output.
|
||||
Synonym for "-p --raw".
|
||||
|
||||
--stat::
|
||||
Generate a diffstat instead of a patch.
|
||||
Generate a diffstat.
|
||||
|
||||
--summary::
|
||||
Output a condensed summary of extended header information
|
||||
such as creations, renames and mode changes.
|
||||
|
||||
--patch-with-stat::
|
||||
Generate patch and prepend its diffstat.
|
||||
Synonym for "-p --stat".
|
||||
|
||||
-z::
|
||||
\0 line termination on output
|
||||
@ -26,10 +29,25 @@
|
||||
--name-status::
|
||||
Show only names and status of changed files.
|
||||
|
||||
--color::
|
||||
Show colored diff.
|
||||
|
||||
--no-color::
|
||||
Turn off colored diff, even when the configuration file
|
||||
gives the default to color output.
|
||||
|
||||
--no-renames::
|
||||
Turn off rename detection, even when the configuration
|
||||
file gives the default to do so.
|
||||
|
||||
--full-index::
|
||||
Instead of the first handful characters, show full
|
||||
object name of pre- and post-image blob on the "index"
|
||||
line when generating a patch format output.
|
||||
line when generating a patch format output.
|
||||
|
||||
--binary::
|
||||
In addition to --full-index, output "binary diff" that
|
||||
can be applied with "git apply".
|
||||
|
||||
--abbrev[=<n>]::
|
||||
Instead of showing the full 40-byte hexadecimal object
|
||||
@ -94,5 +112,11 @@
|
||||
Swap two inputs; that is, show differences from index or
|
||||
on-disk file to tree contents.
|
||||
|
||||
--text::
|
||||
Treat all files as text.
|
||||
|
||||
-a::
|
||||
Shorthand for "--text".
|
||||
|
||||
For more detailed explanation on these common options, see also
|
||||
link:diffcore.html[diffcore documentation].
|
||||
|
||||
@ -8,7 +8,7 @@ git-cvsexportcommit - Export a commit to a CVS checkout
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-cvsexportcommmit' [-h] [-v] [-c] [-p] [-f] [-m msgprefix] [PARENTCOMMIT] COMMITID
|
||||
'git-cvsexportcommit' [-h] [-v] [-c] [-p] [-a] [-f] [-m msgprefix] [PARENTCOMMIT] COMMITID
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
@ -36,9 +36,13 @@ OPTIONS
|
||||
commit if any hunks fail to apply or there were other problems.
|
||||
|
||||
-p::
|
||||
Be pedantic (paranoid) when applying patches. Invokes patch with
|
||||
Be pedantic (paranoid) when applying patches. Invokes patch with
|
||||
--fuzz=0
|
||||
|
||||
-a::
|
||||
Add authorship information. Adds Author line, and Committer (if
|
||||
different from Author) to the message.
|
||||
|
||||
-f::
|
||||
Force the merge even if the files are not up to date.
|
||||
|
||||
|
||||
@ -116,7 +116,7 @@ file each time git-cvsimport is run.
|
||||
+
|
||||
It is not recommended to use this feature if you intend to
|
||||
export changes back to CVS again later with
|
||||
git-link[1]::git-cvsexportcommit.
|
||||
gitlink:git-cvsexportcommit[1].
|
||||
|
||||
OUTPUT
|
||||
------
|
||||
|
||||
@ -11,7 +11,7 @@ SYNOPSIS
|
||||
'git-daemon' [--verbose] [--syslog] [--inetd | --port=n] [--export-all]
|
||||
[--timeout=n] [--init-timeout=n] [--strict-paths]
|
||||
[--base-path=path] [--user-path | --user-path=path]
|
||||
[directory...]
|
||||
[--reuseaddr] [--detach] [--pid-file=file] [directory...]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@ -82,6 +82,17 @@ OPTIONS
|
||||
--verbose::
|
||||
Log details about the incoming connections and requested files.
|
||||
|
||||
--reuseaddr::
|
||||
Use SO_REUSEADDR when binding the listening socket.
|
||||
This allows the server to restart without waiting for
|
||||
old connections to time out.
|
||||
|
||||
--detach::
|
||||
Detach from the shell. Implies --syslog.
|
||||
|
||||
--pid-file=file::
|
||||
Save the process id in 'file'.
|
||||
|
||||
<directory>::
|
||||
A directory to add to the whitelist of allowed directories. Unless
|
||||
--strict-paths is specified this will also include subdirectories
|
||||
|
||||
@ -37,7 +37,7 @@ omit diff output for unmerged entries and just show "Unmerged".
|
||||
commit with these flags.
|
||||
|
||||
-q::
|
||||
Remain silent even on nonexisting files
|
||||
Remain silent even on nonexistent files
|
||||
|
||||
Output format
|
||||
-------------
|
||||
|
||||
@ -8,24 +8,24 @@ git-diff - Show changes between commits, commit and working tree, etc
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-diff' [ --diff-options ] <ent>{0,2} [<path>...]
|
||||
'git-diff' [ --diff-options ] <tree-ish>{0,2} [<path>...]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Show changes between two ents, an ent and the working tree, an
|
||||
ent and the index file, or the index file and the working tree.
|
||||
Show changes between two trees, a tree and the working tree, a
|
||||
tree and the index file, or the index file and the working tree.
|
||||
The combination of what is compared with what is determined by
|
||||
the number of ents given to the command.
|
||||
the number of trees given to the command.
|
||||
|
||||
* When no <ent> is given, the working tree and the index
|
||||
file is compared, using `git-diff-files`.
|
||||
* When no <tree-ish> is given, the working tree and the index
|
||||
file are compared, using `git-diff-files`.
|
||||
|
||||
* When one <ent> is given, the working tree and the named
|
||||
tree is compared, using `git-diff-index`. The option
|
||||
* When one <tree-ish> is given, the working tree and the named
|
||||
tree are compared, using `git-diff-index`. The option
|
||||
`--cached` can be given to compare the index file and
|
||||
the named tree.
|
||||
|
||||
* When two <ent>s are given, these two trees are compared
|
||||
* When two <tree-ish>s are given, these two trees are compared
|
||||
using `git-diff-tree`.
|
||||
|
||||
OPTIONS
|
||||
|
||||
@ -9,8 +9,9 @@ git-format-patch - Prepare patches for e-mail submission
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-format-patch' [-n | -k] [-o <dir> | --stdout] [--attach]
|
||||
'git-format-patch' [-n | -k] [-o <dir> | --stdout] [--attach] [--thread]
|
||||
[-s | --signoff] [--diff-options] [--start-number <n>]
|
||||
[--in-reply-to=Message-Id]
|
||||
<since>[..<until>]
|
||||
|
||||
DESCRIPTION
|
||||
@ -35,6 +36,10 @@ they are created in the current working directory.
|
||||
If -n is specified, instead of "[PATCH] Subject", the first line
|
||||
is formatted as "[PATCH n/m] Subject".
|
||||
|
||||
If given --thread, git-format-patch will generate In-Reply-To and
|
||||
References headers to make the second and subsequent patch mails appear
|
||||
as replies to the first mail; this also generates a Message-Id header to
|
||||
reference.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
@ -63,6 +68,15 @@ OPTIONS
|
||||
--attach::
|
||||
Create attachments instead of inlining patches.
|
||||
|
||||
--thread::
|
||||
Add In-Reply-To and References headers to make the second and
|
||||
subsequent mails appear as replies to the first. Also generates
|
||||
the Message-Id header to reference.
|
||||
|
||||
--in-reply-to=Message-Id::
|
||||
Make the first mail (or all the mails with --no-thread) appear as a
|
||||
reply to the given Message-Id, which avoids breaking threads to
|
||||
provide a new patch series.
|
||||
|
||||
CONFIGURATION
|
||||
-------------
|
||||
|
||||
@ -16,7 +16,7 @@ SYNOPSIS
|
||||
[-n] [-l | --files-with-matches] [-L | --files-without-match]
|
||||
[-c | --count]
|
||||
[-A <post-context>] [-B <pre-context>] [-C <context>]
|
||||
[-f <file>] [-e] <pattern>
|
||||
[-f <file>] [-e] <pattern> [--and|--or|--not|(|)|-e <pattern>...]
|
||||
[<tree>...]
|
||||
[--] [<path>...]
|
||||
|
||||
@ -74,16 +74,30 @@ OPTIONS
|
||||
-e::
|
||||
The next parameter is the pattern. This option has to be
|
||||
used for patterns starting with - and should be used in
|
||||
scripts passing user input to grep.
|
||||
scripts passing user input to grep. Multiple patterns are
|
||||
combined by 'or'.
|
||||
|
||||
--and | --or | --not | ( | )::
|
||||
Specify how multiple patterns are combined using boolean
|
||||
expressions. `--or` is the default operator. `--and` has
|
||||
higher precedence than `--or`. `-e` has to be used for all
|
||||
patterns.
|
||||
|
||||
`<tree>...`::
|
||||
Search blobs in the trees for specified patterns.
|
||||
|
||||
`--`::
|
||||
\--::
|
||||
Signals the end of options; the rest of the parameters
|
||||
are <path> limiters.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
git grep -e \'#define\' --and \( -e MAX_PATH -e PATH_MAX \)::
|
||||
Looks for a line that has `#define` and either `MAX_PATH` or
|
||||
`PATH_MAX`.
|
||||
|
||||
Author
|
||||
------
|
||||
Originally written by Linus Torvalds <torvalds@osdl.org>, later
|
||||
|
||||
@ -8,7 +8,7 @@ git-http-fetch - downloads a remote git repository via HTTP
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-http-fetch' [-c] [-t] [-a] [-d] [-v] [-w filename] [--recover] <commit> <url>
|
||||
'git-http-fetch' [-c] [-t] [-a] [-d] [-v] [-w filename] [--recover] [--stdin] <commit> <url>
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@ -33,6 +33,12 @@ commit-id::
|
||||
Writes the commit-id into the filename under $GIT_DIR/refs/<filename> on
|
||||
the local end after the transfer is complete.
|
||||
|
||||
--stdin::
|
||||
Instead of a commit id on the commandline (which is not expected in this
|
||||
case), 'git-http-fetch' expects lines on stdin in the format
|
||||
|
||||
<commit-id>['\t'<filename-as-in--w>]
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Linus Torvalds <torvalds@osdl.org>
|
||||
|
||||
@ -25,7 +25,7 @@ DESCRIPTION
|
||||
-----------
|
||||
This command creates an empty git repository - basically a `.git` directory
|
||||
with subdirectories for `objects`, `refs/heads`, `refs/tags`, and
|
||||
templated files.
|
||||
template files.
|
||||
An initial `HEAD` file that references the HEAD of the master branch
|
||||
is also created.
|
||||
|
||||
|
||||
84
Documentation/git-instaweb.txt
Normal file
84
Documentation/git-instaweb.txt
Normal file
@ -0,0 +1,84 @@
|
||||
git-instaweb(1)
|
||||
===============
|
||||
|
||||
NAME
|
||||
----
|
||||
git-instaweb - instantly browse your working repository in gitweb
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-instaweb' [--local] [--httpd=<httpd>] [--port=<port>] [--browser=<browser>]
|
||||
|
||||
'git-instaweb' [--start] [--stop] [--restart]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
A simple script to setup gitweb and a web server for browsing the local
|
||||
repository.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
|
||||
-l|--local::
|
||||
Only bind the web server to the local IP (127.0.0.1).
|
||||
|
||||
-d|--httpd::
|
||||
The HTTP daemon command-line that will be executed.
|
||||
Command-line options may be specified here, and the
|
||||
configuration file will be added at the end of the command-line.
|
||||
Currently, lighttpd and apache2 are the only supported servers.
|
||||
(Default: lighttpd)
|
||||
|
||||
-m|--module-path::
|
||||
The module path (only needed if httpd is Apache).
|
||||
(Default: /usr/lib/apache2/modules)
|
||||
|
||||
-p|--port::
|
||||
The port number to bind the httpd to. (Default: 1234)
|
||||
|
||||
-b|--browser::
|
||||
|
||||
The web browser command-line to execute to view the gitweb page.
|
||||
If blank, the URL of the gitweb instance will be printed to
|
||||
stdout. (Default: 'firefox')
|
||||
|
||||
--start::
|
||||
Start the httpd instance and exit. This does not generate
|
||||
any of the configuration files for spawning a new instance.
|
||||
|
||||
--stop::
|
||||
Stop the httpd instance and exit. This does not generate
|
||||
any of the configuration files for spawning a new instance,
|
||||
nor does it close the browser.
|
||||
|
||||
--restart::
|
||||
Restart the httpd instance and exit. This does not generate
|
||||
any of the configuration files for spawning a new instance.
|
||||
|
||||
CONFIGURATION
|
||||
-------------
|
||||
|
||||
You may specify configuration in your .git/config
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
[instaweb]
|
||||
local = true
|
||||
httpd = apache2 -f
|
||||
port = 4321
|
||||
browser = konqueror
|
||||
modulepath = /usr/lib/apache2/modules
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Eric Wong <normalperson@yhbt.net>
|
||||
|
||||
Documentation
|
||||
--------------
|
||||
Documentation by Eric Wong <normalperson@yhbt.net>.
|
||||
|
||||
GIT
|
||||
---
|
||||
Part of the gitlink:git[7] suite
|
||||
|
||||
@ -29,6 +29,12 @@ OPTIONS
|
||||
Writes the commit-id into the filename under $GIT_DIR/refs/<filename> on
|
||||
the local end after the transfer is complete.
|
||||
|
||||
--stdin::
|
||||
Instead of a commit id on the commandline (which is not expected in this
|
||||
case), 'git-local-fetch' expects lines on stdin in the format
|
||||
|
||||
<commit-id>['\t'<filename-as-in--w>]
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Junio C Hamano <junkio@cox.net>
|
||||
|
||||
@ -207,7 +207,7 @@ An exclude pattern is of the following format:
|
||||
An example:
|
||||
|
||||
--------------------------------------------------------------
|
||||
$ cat .git/ignore
|
||||
$ cat .git/info/exclude
|
||||
# ignore objects and archives, anywhere in the tree.
|
||||
*.[oa]
|
||||
$ cat Documentation/.gitignore
|
||||
@ -217,7 +217,7 @@ An example:
|
||||
!foo.html
|
||||
$ git-ls-files --ignored \
|
||||
--exclude='Documentation/*.[0-9]' \
|
||||
--exclude-from=.git/ignore \
|
||||
--exclude-from=.git/info/exclude \
|
||||
--exclude-per-directory=.gitignore
|
||||
--------------------------------------------------------------
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ OPTIONS
|
||||
|
||||
-b::
|
||||
If any file doesn't begin with a From line, assume it is a
|
||||
single mail message instead of signalling error.
|
||||
single mail message instead of signaling error.
|
||||
|
||||
-d<prec>::
|
||||
Instead of the default 4 digits with leading zeros,
|
||||
|
||||
@ -83,7 +83,7 @@ your local modifications interfere with the merge, again, it
|
||||
stops before touching anything.
|
||||
|
||||
So in the above two "failed merge" case, you do not have to
|
||||
worry about lossage of data --- you simply were not ready to do
|
||||
worry about loss of data --- you simply were not ready to do
|
||||
a merge, so no merge happened at all. You may want to finish
|
||||
whatever you were in the middle of doing, and retry the same
|
||||
pull after you are done and ready.
|
||||
|
||||
@ -26,14 +26,14 @@ OPTIONS
|
||||
List all commits reachable from all refs
|
||||
|
||||
--stdin::
|
||||
Read from stdin, append "(<rev_name>)" to all sha1's of name'able
|
||||
Read from stdin, append "(<rev_name>)" to all sha1's of nameable
|
||||
commits, and pass to stdout
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
|
||||
Given a commit, find out where it is relative to the local refs. Say somebody
|
||||
wrote you about that phantastic commit 33db5f4d9027a10e477ccf054b2c1ab94f74c85a.
|
||||
wrote you about that fantastic commit 33db5f4d9027a10e477ccf054b2c1ab94f74c85a.
|
||||
Of course, you look into the commit, but that only tells you what happened, but
|
||||
not the context.
|
||||
|
||||
|
||||
@ -128,7 +128,7 @@ Tags
|
||||
A git tag of the form p4/xx is created for every change imported from
|
||||
the Perforce repository where xx is the Perforce changeset number.
|
||||
Therefore after the import you can use git to access any commit by its
|
||||
Perforce number, eg. git show p4/327.
|
||||
Perforce number, e.g. git show p4/327.
|
||||
|
||||
The tag associated with the HEAD commit is also how `git-p4import`
|
||||
determines if there are new changes to incrementally import from the
|
||||
@ -143,7 +143,7 @@ may delete the tags.
|
||||
|
||||
Notes
|
||||
-----
|
||||
You can interrupt the import (eg. ctrl-c) at any time and restart it
|
||||
You can interrupt the import (e.g. ctrl-c) at any time and restart it
|
||||
without worry.
|
||||
|
||||
Author information is automatically determined by querying the
|
||||
|
||||
@ -29,7 +29,7 @@ OPTIONS
|
||||
|
||||
|
||||
--all::
|
||||
Processes all packs. Any filenames on the commandline are ignored.
|
||||
Processes all packs. Any filenames on the command line are ignored.
|
||||
|
||||
--alt-odb::
|
||||
Don't require objects present in packs from alternate object
|
||||
|
||||
@ -8,7 +8,7 @@ git-push - Update remote refs along with associated objects
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-push' [--all] [--tags] [--force] <repository> <refspec>...
|
||||
'git-push' [--all] [--tags] [-f | --force] <repository> <refspec>...
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@ -67,7 +67,7 @@ Some short-cut notations are also supported.
|
||||
|
||||
-f, \--force::
|
||||
Usually, the command refuses to update a remote ref that is
|
||||
not a descendent of the local ref used to overwrite it.
|
||||
not a descendant of the local ref used to overwrite it.
|
||||
This flag disables the check. This can cause the
|
||||
remote repository to lose commits; use it with care.
|
||||
|
||||
|
||||
@ -120,8 +120,8 @@ you can set the filemode to true with
|
||||
% git repo-config core.filemode true
|
||||
------------
|
||||
|
||||
The hypothetic proxy command entries actually have a postfix to discern
|
||||
to what URL they apply. Here is how to change the entry for kernel.org
|
||||
The hypothetical proxy command entries actually have a postfix to discern
|
||||
what URL they apply to. Here is how to change the entry for kernel.org
|
||||
to "ssh".
|
||||
|
||||
------------
|
||||
|
||||
@ -15,12 +15,14 @@ SYNOPSIS
|
||||
[ \--sparse ]
|
||||
[ \--no-merges ]
|
||||
[ \--remove-empty ]
|
||||
[ \--not ]
|
||||
[ \--all ]
|
||||
[ \--topo-order ]
|
||||
[ \--parents ]
|
||||
[ [\--objects | \--objects-edge] [ \--unpacked ] ]
|
||||
[ \--pretty | \--header ]
|
||||
[ \--bisect ]
|
||||
[ \--merge ]
|
||||
<commit>... [ \-- <paths>... ]
|
||||
|
||||
DESCRIPTION
|
||||
@ -37,6 +39,14 @@ not in 'baz'".
|
||||
A special notation <commit1>..<commit2> can be used as a
|
||||
short-hand for {caret}<commit1> <commit2>.
|
||||
|
||||
Another special notation is <commit1>...<commit2> which is useful for
|
||||
merges. The resulting set of commits is the symmetric difference
|
||||
between the two operands. The following two commands are equivalent:
|
||||
|
||||
------------
|
||||
$ git-rev-list A B --not $(git-merge-base --all A B)
|
||||
$ git-rev-list A...B
|
||||
------------
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
@ -47,6 +57,9 @@ OPTIONS
|
||||
Print the contents of the commit in raw-format; each
|
||||
record is separated with a NUL character.
|
||||
|
||||
--parents::
|
||||
Print the parents of the commit.
|
||||
|
||||
--objects::
|
||||
Print the object IDs of any object referenced by the listed commits.
|
||||
'git-rev-list --objects foo ^bar' thus means "send me all object IDs
|
||||
@ -55,7 +68,7 @@ OPTIONS
|
||||
|
||||
--objects-edge::
|
||||
Similar to `--objects`, but also print the IDs of
|
||||
excluded commits refixed with a `-` character. This is
|
||||
excluded commits prefixed with a `-` character. This is
|
||||
used by `git-pack-objects` to build 'thin' pack, which
|
||||
records objects in deltified form based on objects
|
||||
contained in these excluded commits to reduce network
|
||||
@ -93,6 +106,14 @@ OPTIONS
|
||||
--remove-empty::
|
||||
Stop when a given path disappears from the tree.
|
||||
|
||||
--no-merges::
|
||||
Do not print commits with more than one parent.
|
||||
|
||||
--not::
|
||||
Reverses the meaning of the '{caret}' prefix (or lack
|
||||
thereof) for all following revision specifiers, up to
|
||||
the next `--not`.
|
||||
|
||||
--all::
|
||||
Pretend as if all the refs in `$GIT_DIR/refs/` are
|
||||
listed on the command line as <commit>.
|
||||
@ -103,6 +124,10 @@ OPTIONS
|
||||
topological order (i.e. descendant commits are shown
|
||||
before their parents).
|
||||
|
||||
--merge::
|
||||
After a failed merge, show refs that touch files having a
|
||||
conflict and don't exist on all heads to merge.
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Linus Torvalds <torvalds@osdl.org>
|
||||
|
||||
@ -156,11 +156,6 @@ syntax.
|
||||
and dereference the tag recursively until a non-tag object is
|
||||
found.
|
||||
|
||||
'git-rev-parse' also accepts a prefix '{caret}' to revision parameter,
|
||||
which is passed to 'git-rev-list'. Two revision parameters
|
||||
concatenated with '..' is a short-hand for writing a range
|
||||
between them. I.e. 'r1..r2' is equivalent to saying '{caret}r1 r2'
|
||||
|
||||
Here is an illustration, by Jon Loeliger. Both node B and C are
|
||||
a commit parents of commit node A. Parent commits are ordered
|
||||
left-to-right.
|
||||
@ -168,9 +163,9 @@ left-to-right.
|
||||
G H I J
|
||||
\ / \ /
|
||||
D E F
|
||||
\ | /
|
||||
\ | /
|
||||
\|/
|
||||
\ | / \
|
||||
\ | / |
|
||||
\|/ |
|
||||
B C
|
||||
\ /
|
||||
\ /
|
||||
@ -188,6 +183,40 @@ left-to-right.
|
||||
J = F^2 = B^3^2 = A^^3^2
|
||||
|
||||
|
||||
SPECIFYING RANGES
|
||||
-----------------
|
||||
|
||||
History traversing commands such as `git-log` operate on a set
|
||||
of commits, not just a single commit. To these commands,
|
||||
specifying a single revision with the notation described in the
|
||||
previous section means the set of commits reachable from that
|
||||
commit, following the commit ancestry chain.
|
||||
|
||||
To exclude commits reachable from a commit, a prefix `{caret}`
|
||||
notation is used. E.g. "`{caret}r1 r2`" means commits reachable
|
||||
from `r2` but exclude the ones reachable from `r1`.
|
||||
|
||||
This set operation appears so often that there is a shorthand
|
||||
for it. "`r1..r2`" is equivalent to "`{caret}r1 r2`". It is
|
||||
the difference of two sets (subtract the set of commits
|
||||
reachable from `r1` from the set of commits reachable from
|
||||
`r2`).
|
||||
|
||||
A similar notation "`r1\...r2`" is called symmetric difference
|
||||
of `r1` and `r2` and is defined as
|
||||
"`r1 r2 --not $(git-merge-base --all r1 r2)`".
|
||||
It it the set of commits that are reachable from either one of
|
||||
`r1` or `r2` but not from both.
|
||||
|
||||
Here are a few examples:
|
||||
|
||||
D A B D
|
||||
D F A B C D F
|
||||
^A G B D
|
||||
^A F B C F
|
||||
G...I C D F G I
|
||||
^B G I C D F G I
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Linus Torvalds <torvalds@osdl.org> and
|
||||
|
||||
@ -52,6 +52,11 @@ OPTIONS
|
||||
appear in topological order (i.e., descendant commits
|
||||
are shown before their parents).
|
||||
|
||||
--sparse::
|
||||
By default, the output omits merges that are reachable
|
||||
from only one tip being shown. This option makes them
|
||||
visible.
|
||||
|
||||
--more=<n>::
|
||||
Usually the command stops output upon showing the commit
|
||||
that is the common ancestor of all the branches. This
|
||||
|
||||
@ -224,7 +224,7 @@ Merge tracking in Subversion is lacking and doing branched development
|
||||
with Subversion is cumbersome as a result. git-svn completely forgoes
|
||||
any automated merge/branch tracking on the Subversion side and leaves it
|
||||
entirely up to the user on the git side. It's simply not worth it to do
|
||||
a useful translation when the the original signal is weak.
|
||||
a useful translation when the original signal is weak.
|
||||
|
||||
TRACKING MULTIPLE REPOSITORIES OR BRANCHES
|
||||
------------------------------------------
|
||||
@ -37,7 +37,20 @@ OPTIONS
|
||||
Instead of making a tar archive from local repository,
|
||||
retrieve a tar archive from a remote repository.
|
||||
|
||||
Examples
|
||||
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 remains 0, which means world
|
||||
readable/writable files and directories.
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
git tar-tree HEAD junk | (cd /var/tmp/ && tar xf -)::
|
||||
|
||||
@ -58,6 +71,11 @@ git tar-tree --remote=example.com:git.git v1.4.0 >git-1.4.0.tar::
|
||||
|
||||
Get a tarball v1.4.0 from example.com.
|
||||
|
||||
git tar-tree HEAD:Documentation/ git-docs > git-1.4.0-docs.tar::
|
||||
|
||||
Put everything in the current head's Documentation/ directory
|
||||
into 'git-1.4.0-docs.tar', with the prefix 'git-docs/'.
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Rene Scharfe.
|
||||
|
||||
@ -42,7 +42,7 @@ History Viewers
|
||||
|
||||
- *gitk* (shipped with git-core)
|
||||
|
||||
gitk is a simple TK GUI for browsing history of GIT repositories easily.
|
||||
gitk is a simple Tk GUI for browsing history of GIT repositories easily.
|
||||
|
||||
|
||||
- *gitview* (contrib/)
|
||||
|
||||
@ -17,7 +17,7 @@ to the other end over the git protocol.
|
||||
|
||||
This command is usually not invoked directly by the end user.
|
||||
The UI for the protocol is on the 'git-tar-tree' side, and the
|
||||
program pair is meant to be used to get a tar achive from a
|
||||
program pair is meant to be used to get a tar archive from a
|
||||
remote repository.
|
||||
|
||||
|
||||
|
||||
@ -8,7 +8,8 @@ git - the stupid content tracker
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git' [--version] [--exec-path[=GIT_EXEC_PATH]] [--help] COMMAND [ARGS]
|
||||
'git' [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate]
|
||||
[--bare] [--git-dir=GIT_DIR] [--help] COMMAND [ARGS]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@ -41,6 +42,15 @@ OPTIONS
|
||||
environment variable. If no path is given 'git' will print
|
||||
the current setting and then exit.
|
||||
|
||||
-p|--paginate::
|
||||
Pipe all output into 'less' (or if set, $PAGER).
|
||||
|
||||
--git-dir=<path>::
|
||||
Set the path to the repository. This can also be controlled by
|
||||
setting the GIT_DIR environment variable.
|
||||
|
||||
--bare::
|
||||
Same as --git-dir=`pwd`.
|
||||
|
||||
FURTHER DOCUMENTATION
|
||||
---------------------
|
||||
@ -387,6 +397,9 @@ gitlink:git-quiltimport[1]::
|
||||
gitlink:git-relink[1]::
|
||||
Hardlink common objects in local repositories.
|
||||
|
||||
gitlink:git-svn[1]::
|
||||
Bidirectional operation between a single Subversion branch and git.
|
||||
|
||||
gitlink:git-svnimport[1]::
|
||||
Import a SVN repository into git.
|
||||
|
||||
@ -432,6 +445,9 @@ gitlink:git-get-tar-commit-id[1]::
|
||||
gitlink:git-imap-send[1]::
|
||||
Dump a mailbox from stdin into an imap folder.
|
||||
|
||||
gitlink:git-instaweb[1]::
|
||||
Instantly browse your working repository in gitweb.
|
||||
|
||||
gitlink:git-mailinfo[1]::
|
||||
Extracts patch and authorship information from a single
|
||||
e-mail message, optionally transliterating the commit
|
||||
@ -478,7 +494,7 @@ Configuration Mechanism
|
||||
|
||||
Starting from 0.99.9 (actually mid 0.99.8.GIT), `.git/config` file
|
||||
is used to hold per-repository configuration options. It is a
|
||||
simple text file modelled after `.ini` format familiar to some
|
||||
simple text file modeled after `.ini` format familiar to some
|
||||
people. Here is an example:
|
||||
|
||||
------------
|
||||
@ -615,6 +631,13 @@ git Diffs
|
||||
gitlink:git-diff-files[1];
|
||||
gitlink:git-diff-tree[1]
|
||||
|
||||
other
|
||||
~~~~~
|
||||
'GIT_TRACE'::
|
||||
If this variable is set git will print `trace:` messages on
|
||||
stderr telling about alias expansion, built-in command
|
||||
execution and external command execution.
|
||||
|
||||
Discussion[[Discussion]]
|
||||
------------------------
|
||||
include::README[]
|
||||
|
||||
@ -86,7 +86,7 @@ directory::
|
||||
ent::
|
||||
Favorite synonym to "tree-ish" by some total geeks. See
|
||||
`http://en.wikipedia.org/wiki/Ent_(Middle-earth)` for an in-depth
|
||||
explanation.
|
||||
explanation. Avoid this term, not to confuse people.
|
||||
|
||||
fast forward::
|
||||
A fast-forward is a special type of merge where you have
|
||||
|
||||
@ -28,7 +28,7 @@ Then do
|
||||
|
||||
and at this point "git bisect" will churn for a while, and tell you what
|
||||
the mid-point between those two commits are, and check that state out as
|
||||
the head of the bew "bisect" branch.
|
||||
the head of the new "bisect" branch.
|
||||
|
||||
Compile and reboot.
|
||||
|
||||
|
||||
@ -124,7 +124,7 @@ up your changes, along with other changes.
|
||||
|
||||
The two commits #2' and #3' in the above picture record the same
|
||||
changes your e-mail submission for #2 and #3 contained, but
|
||||
probably with the new sign-off line added by the upsteam
|
||||
probably with the new sign-off line added by the upstream
|
||||
maintainer and definitely with different committer and ancestry
|
||||
information, they are different objects from #2 and #3 commits.
|
||||
|
||||
|
||||
@ -120,9 +120,11 @@ info/grafts::
|
||||
|
||||
info/exclude::
|
||||
This file, by convention among Porcelains, stores the
|
||||
exclude pattern list. `git status` looks at it, but
|
||||
otherwise it is not looked at by any of the core git
|
||||
commands.
|
||||
exclude pattern list. `.gitignore` is the per-directory
|
||||
ignore file. `git status`, `git add`, `git rm` and `git
|
||||
clean` look at it but the core git commands do not look
|
||||
at it. See also: gitlink:git-ls-files[1] `--exclude-from`
|
||||
and `--exclude-per-directory`.
|
||||
|
||||
remotes::
|
||||
Stores shorthands to be used to give URL and default
|
||||
|
||||
@ -73,7 +73,7 @@ The traditional insight:
|
||||
|
||||
<pasky> yes
|
||||
|
||||
And Bable-like confusion flowed.
|
||||
And Babel-like confusion flowed.
|
||||
|
||||
<njs`> oh, hmm, and I'm not sure what this sliding window means either
|
||||
|
||||
@ -257,7 +257,7 @@ proclaim it a non-issue. Good style too!
|
||||
(type, basename, size)).
|
||||
|
||||
Then we walk through this list, and calculate a delta of
|
||||
each object against the last n (tunable paramater) objects,
|
||||
each object against the last n (tunable parameter) objects,
|
||||
and pick the smallest of these deltas.
|
||||
|
||||
Vastly simplified, but the essence is there!
|
||||
@ -395,7 +395,7 @@ used as setup for a later optimization, which is a real word:
|
||||
do "object name->location in packfile" translation.
|
||||
|
||||
<njs`> I'm assuming the real win for delta-ing large->small is
|
||||
more homogenous statistics for gzip to run over?
|
||||
more homogeneous statistics for gzip to run over?
|
||||
|
||||
(You have to put the bytes in one place or another, but
|
||||
putting them in a larger blob wins on compression)
|
||||
@ -448,7 +448,7 @@ design options, etc.
|
||||
|
||||
Bugs happen, but they are "simple" bugs. And bugs that
|
||||
actually get some object store detail wrong are almost always
|
||||
so obious that they never go anywhere.
|
||||
so obvious that they never go anywhere.
|
||||
|
||||
<njs`> Yeah.
|
||||
|
||||
|
||||
@ -10,20 +10,21 @@ to name the remote repository:
|
||||
- https://host.xz/path/to/repo.git/
|
||||
- git://host.xz/path/to/repo.git/
|
||||
- git://host.xz/~user/path/to/repo.git/
|
||||
- ssh://host.xz/path/to/repo.git/
|
||||
- ssh://host.xz/~user/path/to/repo.git/
|
||||
- ssh://host.xz/~/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
|
||||
===============================================================
|
||||
|
||||
SSH Is the default transport protocol and also supports an
|
||||
scp-like syntax. Both syntaxes support username expansion,
|
||||
SSH is the default transport protocol. 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 three are
|
||||
identical to the last three above, respectively:
|
||||
|
||||
===============================================================
|
||||
- host.xz:/path/to/repo.git/
|
||||
- host.xz:~user/path/to/repo.git/
|
||||
- host.xz:path/to/repo.git
|
||||
- {startsb}user@{endsb}host.xz:/path/to/repo.git/
|
||||
- {startsb}user@{endsb}host.xz:~user/path/to/repo.git/
|
||||
- {startsb}user@{endsb}host.xz:path/to/repo.git
|
||||
===============================================================
|
||||
|
||||
To sync with a local directory, use:
|
||||
@ -47,7 +48,7 @@ Then such a short-hand is specified in place of
|
||||
<repository> without <refspec> parameters on the command
|
||||
line, <refspec> specified on `Push:` lines or `Pull:`
|
||||
lines are used for `git-push` and `git-fetch`/`git-pull`,
|
||||
respectively. Multiple `Push:` and and `Pull:` lines may
|
||||
respectively. Multiple `Push:` and `Pull:` lines may
|
||||
be specified for additional branch mappings.
|
||||
|
||||
The name of a file in `$GIT_DIR/branches` directory can be
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
GVF=GIT-VERSION-FILE
|
||||
DEF_VER=v1.4.GIT
|
||||
DEF_VER=v1.4.2.GIT
|
||||
|
||||
# First try git-describe, then see if there is a version file
|
||||
# (included in release tarballs), then default
|
||||
|
||||
13
INSTALL
13
INSTALL
@ -13,6 +13,15 @@ that uses $prefix, the built results have some paths encoded,
|
||||
which are derived from $prefix, so "make all; make prefix=/usr
|
||||
install" would not work.
|
||||
|
||||
Alternatively you can use autoconf generated ./configure script to
|
||||
set up install paths (via config.mak.autogen), so you can write instead
|
||||
|
||||
$ autoconf ;# as yourself if ./configure doesn't exist yet
|
||||
$ ./configure --prefix=/usr ;# as yourself
|
||||
$ make all doc ;# as yourself
|
||||
# make install install-doc ;# as root
|
||||
|
||||
|
||||
Issues of note:
|
||||
|
||||
- git normally installs a helper script wrapper called "git", which
|
||||
@ -57,7 +66,7 @@ Issues of note:
|
||||
|
||||
- "libcurl" and "curl" executable. git-http-fetch and
|
||||
git-fetch use them. If you do not use http
|
||||
transfer, you are probabaly OK if you do not have
|
||||
transfer, you are probably OK if you do not have
|
||||
them.
|
||||
|
||||
- expat library; git-http-push uses it for remote lock
|
||||
@ -82,7 +91,7 @@ Issues of note:
|
||||
git, and if you only use git to track other peoples work you'll
|
||||
never notice the lack of it.
|
||||
|
||||
- "wish", the TCL/Tk windowing shell is used in gitk to show the
|
||||
- "wish", the Tcl/Tk windowing shell is used in gitk to show the
|
||||
history graphically
|
||||
|
||||
- "ssh" is used to push and pull over the net
|
||||
|
||||
115
Makefile
115
Makefile
@ -19,6 +19,11 @@ all:
|
||||
# Define NO_D_TYPE_IN_DIRENT if your platform defines DT_UNKNOWN but lacks
|
||||
# d_type in struct dirent (latest Cygwin -- will be fixed soonish).
|
||||
#
|
||||
# Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.)
|
||||
# do not support the 'size specifiers' introduced by C99, namely ll, hh,
|
||||
# j, z, t. (representing long long int, char, intmax_t, size_t, ptrdiff_t).
|
||||
# some c compilers supported these specifiers prior to C99 as an extension.
|
||||
#
|
||||
# Define NO_STRCASESTR if you don't have strcasestr.
|
||||
#
|
||||
# Define NO_STRLCPY if you don't have strlcpy.
|
||||
@ -28,6 +33,22 @@ all:
|
||||
# Define NO_SYMLINK_HEAD if you never want .git/HEAD to be a symbolic link.
|
||||
# Enable it on Windows. By default, symrefs are still used.
|
||||
#
|
||||
# Define NO_SVN_TESTS if you want to skip time-consuming SVN interoperability
|
||||
# tests. These tests take up a significant amount of the total test time
|
||||
# but are not needed unless you plan to talk to SVN repos.
|
||||
#
|
||||
# Define NO_FINK if you are building on Darwin/Mac OS X, have Fink
|
||||
# installed in /sw, but don't want GIT to link against any libraries
|
||||
# installed there. If defined you may specify your own (or Fink's)
|
||||
# include directories and library directories by defining CFLAGS
|
||||
# and LDFLAGS appropriately.
|
||||
#
|
||||
# Define NO_DARWIN_PORTS if you are building on Darwin/Mac OS X,
|
||||
# have DarwinPorts installed in /opt/local, but don't want GIT to
|
||||
# link against any libraries installed there. If defined you may
|
||||
# specify your own (or DarwinPort's) include directories and
|
||||
# library directories by defining CFLAGS and LDFLAGS appropriately.
|
||||
#
|
||||
# Define PPC_SHA1 environment variable when running make to make use of
|
||||
# a bundled SHA1 routine optimized for PowerPC.
|
||||
#
|
||||
@ -63,7 +84,7 @@ all:
|
||||
# Define NO_ACCURATE_DIFF if your diff program at least sometimes misses
|
||||
# a missing newline at the end of the file.
|
||||
#
|
||||
# Define NO_PYTHON if you want to loose all benefits of the recursive merge.
|
||||
# Define NO_PYTHON if you want to lose all benefits of the recursive merge.
|
||||
#
|
||||
# Define COLLISION_CHECK below if you believe that SHA1's
|
||||
# 1461501637330902918203684832716283019655932542976 hashes do not give you
|
||||
@ -105,6 +126,8 @@ template_dir = $(prefix)/share/git-core/templates/
|
||||
GIT_PYTHON_DIR = $(prefix)/share/git-core/python
|
||||
# DESTDIR=
|
||||
|
||||
export prefix bindir gitexecdir template_dir GIT_PYTHON_DIR
|
||||
|
||||
CC = gcc
|
||||
AR = ar
|
||||
TAR = tar
|
||||
@ -130,7 +153,7 @@ SCRIPT_SH = \
|
||||
git-fetch.sh \
|
||||
git-ls-remote.sh \
|
||||
git-merge-one-file.sh git-parse-remote.sh \
|
||||
git-prune.sh git-pull.sh git-rebase.sh \
|
||||
git-pull.sh git-rebase.sh \
|
||||
git-repack.sh git-request-pull.sh git-reset.sh \
|
||||
git-resolve.sh git-revert.sh git-sh-setup.sh \
|
||||
git-tag.sh git-verify-tag.sh \
|
||||
@ -141,10 +164,10 @@ SCRIPT_SH = \
|
||||
|
||||
SCRIPT_PERL = \
|
||||
git-archimport.perl git-cvsimport.perl git-relink.perl \
|
||||
git-shortlog.perl git-fmt-merge-msg.perl git-rerere.perl \
|
||||
git-shortlog.perl git-rerere.perl \
|
||||
git-annotate.perl git-cvsserver.perl \
|
||||
git-svnimport.perl git-mv.perl git-cvsexportcommit.perl \
|
||||
git-send-email.perl
|
||||
git-svnimport.perl git-cvsexportcommit.perl \
|
||||
git-send-email.perl git-svn.perl
|
||||
|
||||
SCRIPT_PYTHON = \
|
||||
git-merge-recursive.py
|
||||
@ -152,7 +175,7 @@ SCRIPT_PYTHON = \
|
||||
SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
|
||||
$(patsubst %.perl,%,$(SCRIPT_PERL)) \
|
||||
$(patsubst %.py,%,$(SCRIPT_PYTHON)) \
|
||||
git-cherry-pick git-status
|
||||
git-cherry-pick git-status git-instaweb
|
||||
|
||||
# The ones that do not have to link with lcrypto, lz nor xdiff.
|
||||
SIMPLE_PROGRAMS = \
|
||||
@ -165,14 +188,14 @@ PROGRAMS = \
|
||||
git-hash-object$X git-index-pack$X git-local-fetch$X \
|
||||
git-merge-base$X \
|
||||
git-merge-index$X git-mktag$X git-mktree$X git-pack-objects$X git-patch-id$X \
|
||||
git-peek-remote$X git-prune-packed$X git-receive-pack$X \
|
||||
git-peek-remote$X git-receive-pack$X \
|
||||
git-send-pack$X git-shell$X \
|
||||
git-show-index$X git-ssh-fetch$X \
|
||||
git-ssh-upload$X git-unpack-file$X \
|
||||
git-unpack-objects$X git-update-server-info$X \
|
||||
git-upload-pack$X git-verify-pack$X \
|
||||
git-symbolic-ref$X \
|
||||
git-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X \
|
||||
git-name-rev$X git-pack-redundant$X git-var$X \
|
||||
git-describe$X git-merge-tree$X git-blame$X git-imap-send$X
|
||||
|
||||
BUILT_INS = git-log$X git-whatchanged$X git-show$X git-update-ref$X \
|
||||
@ -183,7 +206,9 @@ BUILT_INS = git-log$X git-whatchanged$X git-show$X git-update-ref$X \
|
||||
git-ls-files$X git-ls-tree$X git-get-tar-commit-id$X \
|
||||
git-read-tree$X git-commit-tree$X git-write-tree$X \
|
||||
git-apply$X git-show-branch$X git-diff-files$X git-update-index$X \
|
||||
git-diff-index$X git-diff-stages$X git-diff-tree$X git-cat-file$X
|
||||
git-diff-index$X git-diff-stages$X git-diff-tree$X git-cat-file$X \
|
||||
git-fmt-merge-msg$X git-prune$X git-mv$X git-prune-packed$X \
|
||||
git-repo-config$X
|
||||
|
||||
# what 'all' will build and 'install' will install, in gitexecdir
|
||||
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
|
||||
@ -212,7 +237,7 @@ LIB_H = \
|
||||
blob.h cache.h commit.h csum-file.h delta.h \
|
||||
diff.h object.h pack.h pkt-line.h quote.h refs.h \
|
||||
run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \
|
||||
tree-walk.h log-tree.h dir.h
|
||||
tree-walk.h log-tree.h dir.h path-list.h
|
||||
|
||||
DIFF_OBJS = \
|
||||
diff.o diff-lib.o diffcore-break.o diffcore-order.o \
|
||||
@ -227,7 +252,7 @@ LIB_OBJS = \
|
||||
server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
|
||||
tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
|
||||
fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \
|
||||
alloc.o $(DIFF_OBJS)
|
||||
alloc.o merge-file.o path-list.o $(DIFF_OBJS)
|
||||
|
||||
BUILTIN_OBJS = \
|
||||
builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
|
||||
@ -239,7 +264,8 @@ BUILTIN_OBJS = \
|
||||
builtin-apply.o builtin-show-branch.o builtin-diff-files.o \
|
||||
builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o \
|
||||
builtin-cat-file.o builtin-mailsplit.o builtin-stripspace.o \
|
||||
builtin-update-ref.o
|
||||
builtin-update-ref.o builtin-fmt-merge-msg.o builtin-prune.o \
|
||||
builtin-mv.o builtin-prune-packed.o builtin-repo-config.o
|
||||
|
||||
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
|
||||
EXTLIBS = -lz
|
||||
@ -255,19 +281,24 @@ EXTLIBS = -lz
|
||||
ifeq ($(uname_S),Linux)
|
||||
NO_STRLCPY = YesPlease
|
||||
endif
|
||||
ifeq ($(uname_S),GNU/kFreeBSD)
|
||||
NO_STRLCPY = YesPlease
|
||||
endif
|
||||
ifeq ($(uname_S),Darwin)
|
||||
NEEDS_SSL_WITH_CRYPTO = YesPlease
|
||||
NEEDS_LIBICONV = YesPlease
|
||||
NO_STRLCPY = YesPlease
|
||||
## fink
|
||||
ifeq ($(shell test -d /sw/lib && echo y),y)
|
||||
BASIC_CFLAGS += -I/sw/include
|
||||
BASIC_LDFLAGS += -L/sw/lib
|
||||
ifndef NO_FINK
|
||||
ifeq ($(shell test -d /sw/lib && echo y),y)
|
||||
BASIC_CFLAGS += -I/sw/include
|
||||
BASIC_LDFLAGS += -L/sw/lib
|
||||
endif
|
||||
endif
|
||||
## darwinports
|
||||
ifeq ($(shell test -d /opt/local/lib && echo y),y)
|
||||
BASIC_CFLAGS += -I/opt/local/include
|
||||
BASIC_LDFLAGS += -L/opt/local/lib
|
||||
ifndef NO_DARWIN_PORTS
|
||||
ifeq ($(shell test -d /opt/local/lib && echo y),y)
|
||||
BASIC_CFLAGS += -I/opt/local/include
|
||||
BASIC_LDFLAGS += -L/opt/local/lib
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
ifeq ($(uname_S),SunOS)
|
||||
@ -293,9 +324,9 @@ ifeq ($(uname_O),Cygwin)
|
||||
NO_D_TYPE_IN_DIRENT = YesPlease
|
||||
NO_D_INO_IN_DIRENT = YesPlease
|
||||
NO_STRCASESTR = YesPlease
|
||||
NO_STRLCPY = YesPlease
|
||||
NO_SYMLINK_HEAD = YesPlease
|
||||
NEEDS_LIBICONV = YesPlease
|
||||
NO_C99_FORMAT = YesPlease
|
||||
# There are conflicting reports about this.
|
||||
# On some boxes NO_MMAP is needed, and not so elsewhere.
|
||||
# Try uncommenting this if you see things break -- YMMV.
|
||||
@ -345,6 +376,7 @@ ifeq ($(uname_M),x86_64)
|
||||
USE_PIC = YesPlease
|
||||
endif
|
||||
|
||||
-include config.mak.autogen
|
||||
-include config.mak
|
||||
|
||||
ifdef WITH_OWN_SUBPROCESS_PY
|
||||
@ -420,6 +452,9 @@ endif
|
||||
ifdef NO_D_INO_IN_DIRENT
|
||||
BASIC_CFLAGS += -DNO_D_INO_IN_DIRENT
|
||||
endif
|
||||
ifdef NO_C99_FORMAT
|
||||
ALL_CFLAGS += -DNO_C99_FORMAT
|
||||
endif
|
||||
ifdef NO_SYMLINK_HEAD
|
||||
BASIC_CFLAGS += -DNO_SYMLINK_HEAD
|
||||
endif
|
||||
@ -485,7 +520,7 @@ ifdef NO_ACCURATE_DIFF
|
||||
BASIC_CFLAGS += -DNO_ACCURATE_DIFF
|
||||
endif
|
||||
|
||||
# Shell quote (do not use $(call) to accomodate ancient setups);
|
||||
# Shell quote (do not use $(call) to accommodate ancient setups);
|
||||
|
||||
SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER))
|
||||
|
||||
@ -539,6 +574,7 @@ common-cmds.h: Documentation/git-*.txt
|
||||
$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
|
||||
rm -f $@ $@+
|
||||
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
|
||||
-e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
|
||||
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
|
||||
-e 's/@@NO_CURL@@/$(NO_CURL)/g' \
|
||||
-e 's/@@NO_PYTHON@@/$(NO_PYTHON)/g' \
|
||||
@ -580,6 +616,20 @@ git-status: git-commit
|
||||
cp $< $@+
|
||||
mv $@+ $@
|
||||
|
||||
git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css
|
||||
rm -f $@ $@+
|
||||
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
|
||||
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
|
||||
-e 's/@@NO_CURL@@/$(NO_CURL)/g' \
|
||||
-e 's/@@NO_PYTHON@@/$(NO_PYTHON)/g' \
|
||||
-e '/@@GITWEB_CGI@@/r gitweb/gitweb.cgi' \
|
||||
-e '/@@GITWEB_CGI@@/d' \
|
||||
-e '/@@GITWEB_CSS@@/r gitweb/gitweb.css' \
|
||||
-e '/@@GITWEB_CSS@@/d' \
|
||||
$@.sh | sed "s|/usr/bin/git|$(bindir)/git|" > $@+
|
||||
chmod +x $@+
|
||||
mv $@+ $@
|
||||
|
||||
# These can record GIT_VERSION
|
||||
git$X git.spec \
|
||||
$(patsubst %.sh,%,$(SCRIPT_SH)) \
|
||||
@ -613,6 +663,8 @@ $(SIMPLE_PROGRAMS) : git-%$X : %.o
|
||||
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
|
||||
$(LIB_FILE) $(SIMPLE_LIB)
|
||||
|
||||
ssh-pull.o: ssh-fetch.c
|
||||
ssh-push.o: ssh-upload.c
|
||||
git-local-fetch$X: fetch.o
|
||||
git-ssh-fetch$X: rsh.o fetch.o
|
||||
git-ssh-upload$X: rsh.o
|
||||
@ -622,11 +674,11 @@ git-ssh-push$X: rsh.o
|
||||
git-imap-send$X: imap-send.o $(LIB_FILE)
|
||||
|
||||
http.o http-fetch.o http-push.o: http.h
|
||||
git-http-fetch$X: fetch.o http.o http-fetch.o $(LIB_FILE)
|
||||
git-http-fetch$X: fetch.o http.o http-fetch.o $(GITLIBS)
|
||||
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
|
||||
$(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
|
||||
|
||||
git-http-push$X: revision.o http.o http-push.o $(LIB_FILE)
|
||||
git-http-push$X: revision.o http.o http-push.o $(GITLIBS)
|
||||
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
|
||||
$(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
|
||||
|
||||
@ -682,6 +734,7 @@ GIT-CFLAGS: .FORCE-GIT-CFLAGS
|
||||
# with that.
|
||||
|
||||
export NO_PYTHON
|
||||
export NO_SVN_TESTS
|
||||
|
||||
test: all
|
||||
$(MAKE) -C t/ all
|
||||
@ -695,6 +748,12 @@ test-delta$X: test-delta.c diff-delta.o patch-delta.o
|
||||
test-dump-cache-tree$X: dump-cache-tree.o $(GITLIBS)
|
||||
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
|
||||
|
||||
test-sha1$X: test-sha1.o $(GITLIBS)
|
||||
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
|
||||
|
||||
check-sha1:: test-sha1$X
|
||||
./test-sha1.sh
|
||||
|
||||
check:
|
||||
for i in *.c; do sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; done
|
||||
|
||||
@ -707,7 +766,7 @@ install: all
|
||||
$(INSTALL) -d -m755 '$(DESTDIR_SQ)$(gitexecdir_SQ)'
|
||||
$(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
|
||||
$(INSTALL) git$X gitk '$(DESTDIR_SQ)$(bindir_SQ)'
|
||||
$(MAKE) -C templates install
|
||||
$(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install
|
||||
$(MAKE) -C perl install
|
||||
$(INSTALL) -d -m755 '$(DESTDIR_SQ)$(GIT_PYTHON_DIR_SQ)'
|
||||
$(INSTALL) $(PYMODULES) '$(DESTDIR_SQ)$(GIT_PYTHON_DIR_SQ)'
|
||||
@ -758,8 +817,8 @@ dist-doc:
|
||||
rm -fr .doc-tmp-dir
|
||||
mkdir .doc-tmp-dir .doc-tmp-dir/man1 .doc-tmp-dir/man7
|
||||
$(MAKE) -C Documentation DESTDIR=./ \
|
||||
man1=../.doc-tmp-dir/man1 \
|
||||
man7=../.doc-tmp-dir/man7 \
|
||||
man1dir=../.doc-tmp-dir/man1 \
|
||||
man7dir=../.doc-tmp-dir/man7 \
|
||||
install
|
||||
cd .doc-tmp-dir && $(TAR) cf ../$(manpages).tar .
|
||||
gzip -n -9 -f $(manpages).tar
|
||||
@ -772,6 +831,8 @@ clean:
|
||||
$(LIB_FILE) $(XDIFF_LIB)
|
||||
rm -f $(ALL_PROGRAMS) $(BUILT_INS) git$X
|
||||
rm -f *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags
|
||||
rm -rf autom4te.cache
|
||||
rm -f config.log config.mak.autogen configure config.status config.cache
|
||||
rm -rf $(GIT_TARNAME) .doc-tmp-dir
|
||||
rm -f $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
|
||||
rm -f $(htmldocs).tar.gz $(manpages).tar.gz
|
||||
|
||||
15
alloc.c
15
alloc.c
@ -39,8 +39,21 @@ DEFINE_ALLOCATOR(tree)
|
||||
DEFINE_ALLOCATOR(commit)
|
||||
DEFINE_ALLOCATOR(tag)
|
||||
|
||||
#ifdef NO_C99_FORMAT
|
||||
#define SZ_FMT "%u"
|
||||
#else
|
||||
#define SZ_FMT "%zu"
|
||||
#endif
|
||||
|
||||
static void report(const char* name, unsigned int count, size_t size)
|
||||
{
|
||||
fprintf(stderr, "%10s: %8u (" SZ_FMT " kB)\n", name, count, size);
|
||||
}
|
||||
|
||||
#undef SZ_FMT
|
||||
|
||||
#define REPORT(name) \
|
||||
fprintf(stderr, "%10s: %8u (%zu kB)\n", #name, name##_allocs, name##_allocs*sizeof(struct name) >> 10)
|
||||
report(#name, name##_allocs, name##_allocs*sizeof(struct name) >> 10)
|
||||
|
||||
void alloc_report(void)
|
||||
{
|
||||
|
||||
30
blame.c
30
blame.c
@ -20,12 +20,12 @@
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
static const char blame_usage[] = "[-c] [-l] [-t] [-S <revs-file>] [--] file [commit]\n"
|
||||
" -c, --compability Use the same output mode as git-annotate (Default: off)\n"
|
||||
" -l, --long Show long commit SHA1 (Default: off)\n"
|
||||
" -t, --time Show raw timestamp (Default: off)\n"
|
||||
" -S, --revs-file Use revisions from revs-file instead of calling git-rev-list\n"
|
||||
" -h, --help This message";
|
||||
static const char blame_usage[] = "git-blame [-c] [-l] [-t] [-S <revs-file>] [--] file [commit]\n"
|
||||
" -c, --compatibility Use the same output mode as git-annotate (Default: off)\n"
|
||||
" -l, --long Show long commit SHA1 (Default: off)\n"
|
||||
" -t, --time Show raw timestamp (Default: off)\n"
|
||||
" -S, --revs-file Use revisions from revs-file instead of calling git-rev-list\n"
|
||||
" -h, --help This message";
|
||||
|
||||
static struct commit **blame_lines;
|
||||
static int num_blame_lines;
|
||||
@ -44,8 +44,8 @@ struct util_info {
|
||||
};
|
||||
|
||||
struct chunk {
|
||||
int off1, len1; // ---
|
||||
int off2, len2; // +++
|
||||
int off1, len1; /* --- */
|
||||
int off2, len2; /* +++ */
|
||||
};
|
||||
|
||||
struct patch {
|
||||
@ -255,7 +255,7 @@ static void print_map(struct commit *cmit, struct commit *other)
|
||||
}
|
||||
#endif
|
||||
|
||||
// p is a patch from commit to other.
|
||||
/* p is a patch from commit to other. */
|
||||
static void fill_line_map(struct commit *commit, struct commit *other,
|
||||
struct patch *p)
|
||||
{
|
||||
@ -747,7 +747,7 @@ int main(int argc, const char **argv)
|
||||
const char *filename = NULL, *commit = NULL;
|
||||
char filename_buf[256];
|
||||
int sha1_len = 8;
|
||||
int compability = 0;
|
||||
int compatibility = 0;
|
||||
int show_raw_time = 0;
|
||||
int options = 1;
|
||||
struct commit* start_commit;
|
||||
@ -774,8 +774,8 @@ int main(int argc, const char **argv)
|
||||
sha1_len = 40;
|
||||
continue;
|
||||
} else if(!strcmp(argv[i], "-c") ||
|
||||
!strcmp(argv[i], "--compability")) {
|
||||
compability = 1;
|
||||
!strcmp(argv[i], "--compatibility")) {
|
||||
compatibility = 1;
|
||||
continue;
|
||||
} else if(!strcmp(argv[i], "-t") ||
|
||||
!strcmp(argv[i], "--time")) {
|
||||
@ -784,7 +784,7 @@ int main(int argc, const char **argv)
|
||||
} else if(!strcmp(argv[i], "-S")) {
|
||||
if (i + 1 < argc &&
|
||||
!read_ancestry(argv[i + 1], &sha1_p)) {
|
||||
compability = 1;
|
||||
compatibility = 1;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
@ -834,7 +834,7 @@ int main(int argc, const char **argv)
|
||||
}
|
||||
|
||||
|
||||
init_revisions(&rev);
|
||||
init_revisions(&rev, setup_git_directory());
|
||||
rev.remove_empty_trees = 1;
|
||||
rev.topo_order = 1;
|
||||
rev.prune_fn = simplify_commit;
|
||||
@ -884,7 +884,7 @@ int main(int argc, const char **argv)
|
||||
u = c->util;
|
||||
get_commit_info(c, &ci);
|
||||
fwrite(sha1_to_hex(c->object.sha1), sha1_len, 1, stdout);
|
||||
if(compability) {
|
||||
if(compatibility) {
|
||||
printf("\t(%10s\t%10s\t%d)", ci.author,
|
||||
format_time(ci.author_time, ci.author_tz,
|
||||
show_raw_time),
|
||||
|
||||
6
blob.c
6
blob.c
@ -10,12 +10,12 @@ struct blob *lookup_blob(const unsigned char *sha1)
|
||||
if (!obj) {
|
||||
struct blob *ret = alloc_blob_node();
|
||||
created_object(sha1, &ret->object);
|
||||
ret->object.type = TYPE_BLOB;
|
||||
ret->object.type = OBJ_BLOB;
|
||||
return ret;
|
||||
}
|
||||
if (!obj->type)
|
||||
obj->type = TYPE_BLOB;
|
||||
if (obj->type != TYPE_BLOB) {
|
||||
obj->type = OBJ_BLOB;
|
||||
if (obj->type != OBJ_BLOB) {
|
||||
error("Object %s is a %s, not a blob",
|
||||
sha1_to_hex(sha1), typename(obj->type));
|
||||
return NULL;
|
||||
|
||||
@ -21,8 +21,7 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int p
|
||||
|
||||
for (specs = 0; pathspec[specs]; specs++)
|
||||
/* nothing */;
|
||||
seen = xmalloc(specs);
|
||||
memset(seen, 0, specs);
|
||||
seen = xcalloc(specs, 1);
|
||||
|
||||
src = dst = dir->entries;
|
||||
i = dir->nr;
|
||||
@ -83,52 +82,12 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec)
|
||||
prune_directory(dir, pathspec, baselen);
|
||||
}
|
||||
|
||||
static int add_file_to_index(const char *path, int verbose)
|
||||
{
|
||||
int size, namelen;
|
||||
struct stat st;
|
||||
struct cache_entry *ce;
|
||||
|
||||
if (lstat(path, &st))
|
||||
die("%s: unable to stat (%s)", path, strerror(errno));
|
||||
|
||||
if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))
|
||||
die("%s: can only add regular files or symbolic links", path);
|
||||
|
||||
namelen = strlen(path);
|
||||
size = cache_entry_size(namelen);
|
||||
ce = xcalloc(1, size);
|
||||
memcpy(ce->name, path, namelen);
|
||||
ce->ce_flags = htons(namelen);
|
||||
fill_stat_cache_info(ce, &st);
|
||||
|
||||
ce->ce_mode = create_ce_mode(st.st_mode);
|
||||
if (!trust_executable_bit) {
|
||||
/* If there is an existing entry, pick the mode bits
|
||||
* from it.
|
||||
*/
|
||||
int pos = cache_name_pos(path, namelen);
|
||||
if (pos >= 0)
|
||||
ce->ce_mode = active_cache[pos]->ce_mode;
|
||||
}
|
||||
|
||||
if (index_path(ce->sha1, path, &st, 1))
|
||||
die("unable to index file %s", path);
|
||||
if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD))
|
||||
die("unable to add %s to index",path);
|
||||
if (verbose)
|
||||
printf("add '%s'\n", path);
|
||||
cache_tree_invalidate_path(active_cache_tree, path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct lock_file lock_file;
|
||||
|
||||
int cmd_add(int argc, const char **argv, char **envp)
|
||||
int cmd_add(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i, newfd;
|
||||
int verbose = 0, show_only = 0;
|
||||
const char *prefix = setup_git_directory();
|
||||
const char **pathspec;
|
||||
struct dir_struct dir;
|
||||
|
||||
@ -158,9 +117,8 @@ int cmd_add(int argc, const char **argv, char **envp)
|
||||
verbose = 1;
|
||||
continue;
|
||||
}
|
||||
die(builtin_add_usage);
|
||||
usage(builtin_add_usage);
|
||||
}
|
||||
git_config(git_default_config);
|
||||
pathspec = get_pathspec(prefix, argv + i);
|
||||
|
||||
fill_directory(&dir, pathspec);
|
||||
@ -181,7 +139,7 @@ int cmd_add(int argc, const char **argv, char **envp)
|
||||
|
||||
if (active_cache_changed) {
|
||||
if (write_cache(newfd, active_cache, active_nr) ||
|
||||
commit_lock_file(&lock_file))
|
||||
close(newfd) || commit_lock_file(&lock_file))
|
||||
die("Unable to write new index file");
|
||||
}
|
||||
|
||||
|
||||
172
builtin-apply.c
172
builtin-apply.c
@ -14,14 +14,15 @@
|
||||
#include "delta.h"
|
||||
#include "builtin.h"
|
||||
|
||||
// --check turns on checking that the working tree matches the
|
||||
// files that are being modified, but doesn't apply the patch
|
||||
// --stat does just a diffstat, and doesn't actually apply
|
||||
// --numstat does numeric diffstat, and doesn't actually apply
|
||||
// --index-info shows the old and new index info for paths if available.
|
||||
// --index updates the cache as well.
|
||||
// --cached updates only the cache without ever touching the working tree.
|
||||
//
|
||||
/*
|
||||
* --check turns on checking that the working tree matches the
|
||||
* files that are being modified, but doesn't apply the patch
|
||||
* --stat does just a diffstat, and doesn't actually apply
|
||||
* --numstat does numeric diffstat, and doesn't actually apply
|
||||
* --index-info shows the old and new index info for paths if available.
|
||||
* --index updates the cache as well.
|
||||
* --cached updates only the cache without ever touching the working tree.
|
||||
*/
|
||||
static const char *prefix;
|
||||
static int prefix_length = -1;
|
||||
static int newfd = -1;
|
||||
@ -119,7 +120,7 @@ struct fragment {
|
||||
struct patch {
|
||||
char *new_name, *old_name, *def_name;
|
||||
unsigned int old_mode, new_mode;
|
||||
int is_rename, is_copy, is_new, is_delete, is_binary;
|
||||
int is_rename, is_copy, is_new, is_delete, is_binary, is_reverse;
|
||||
#define BINARY_DELTA_DEFLATED 1
|
||||
#define BINARY_LITERAL_DEFLATED 2
|
||||
unsigned long deflate_origlen;
|
||||
@ -284,8 +285,8 @@ static void parse_traditional_patch(const char *first, const char *second, struc
|
||||
{
|
||||
char *name;
|
||||
|
||||
first += 4; // skip "--- "
|
||||
second += 4; // skip "+++ "
|
||||
first += 4; /* skip "--- " */
|
||||
second += 4; /* skip "+++ " */
|
||||
if (is_dev_null(first)) {
|
||||
patch->is_new = 1;
|
||||
patch->is_delete = 0;
|
||||
@ -765,7 +766,7 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Make sure we don't find any unconnected patch fragmants.
|
||||
* Make sure we don't find any unconnected patch fragments.
|
||||
* That's a sign that we didn't find a header, and that a
|
||||
* patch has become corrupted/broken up.
|
||||
*/
|
||||
@ -990,7 +991,7 @@ static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
|
||||
* so one line can fit up to 13 groups that would decode
|
||||
* to 52 bytes max. The length byte 'A'-'Z' corresponds
|
||||
* to 1-26 bytes, and 'a'-'z' corresponds to 27-52 bytes.
|
||||
* The end of binary is signalled with an empty line.
|
||||
* The end of binary is signaled with an empty line.
|
||||
*/
|
||||
int llen, used;
|
||||
struct fragment *fragment;
|
||||
@ -1118,6 +1119,34 @@ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
|
||||
return offset + hdrsize + patchsize;
|
||||
}
|
||||
|
||||
#define swap(a,b) myswap((a),(b),sizeof(a))
|
||||
|
||||
#define myswap(a, b, size) do { \
|
||||
unsigned char mytmp[size]; \
|
||||
memcpy(mytmp, &a, size); \
|
||||
memcpy(&a, &b, size); \
|
||||
memcpy(&b, mytmp, size); \
|
||||
} while (0)
|
||||
|
||||
static void reverse_patches(struct patch *p)
|
||||
{
|
||||
for (; p; p = p->next) {
|
||||
struct fragment *frag = p->fragments;
|
||||
|
||||
swap(p->new_name, p->old_name);
|
||||
swap(p->new_mode, p->old_mode);
|
||||
swap(p->is_new, p->is_delete);
|
||||
swap(p->lines_added, p->lines_deleted);
|
||||
swap(p->old_sha1_prefix, p->new_sha1_prefix);
|
||||
|
||||
for (; frag; frag = frag->next) {
|
||||
swap(frag->newpos, frag->oldpos);
|
||||
swap(frag->newlines, frag->oldlines);
|
||||
}
|
||||
p->is_reverse = !p->is_reverse;
|
||||
}
|
||||
}
|
||||
|
||||
static const char pluses[] = "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++";
|
||||
static const char minuses[]= "----------------------------------------------------------------------";
|
||||
|
||||
@ -1335,7 +1364,7 @@ static int apply_line(char *output, const char *patch, int plen)
|
||||
}
|
||||
|
||||
static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag,
|
||||
int inaccurate_eof)
|
||||
int reverse, int inaccurate_eof)
|
||||
{
|
||||
int match_beginning, match_end;
|
||||
char *buf = desc->buffer;
|
||||
@ -1349,6 +1378,7 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag,
|
||||
int pos, lines;
|
||||
|
||||
while (size > 0) {
|
||||
char first;
|
||||
int len = linelen(patch, size);
|
||||
int plen;
|
||||
|
||||
@ -1365,16 +1395,23 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag,
|
||||
plen = len-1;
|
||||
if (len < size && patch[len] == '\\')
|
||||
plen--;
|
||||
switch (*patch) {
|
||||
first = *patch;
|
||||
if (reverse) {
|
||||
if (first == '-')
|
||||
first = '+';
|
||||
else if (first == '+')
|
||||
first = '-';
|
||||
}
|
||||
switch (first) {
|
||||
case ' ':
|
||||
case '-':
|
||||
memcpy(old + oldsize, patch + 1, plen);
|
||||
oldsize += plen;
|
||||
if (*patch == '-')
|
||||
if (first == '-')
|
||||
break;
|
||||
/* Fall-through for ' ' */
|
||||
case '+':
|
||||
if (*patch != '+' || !no_add)
|
||||
if (first != '+' || !no_add)
|
||||
newsize += apply_line(new + newsize, patch,
|
||||
plen);
|
||||
break;
|
||||
@ -1498,6 +1535,12 @@ static int apply_binary_fragment(struct buffer_desc *desc, struct patch *patch)
|
||||
void *data;
|
||||
void *result;
|
||||
|
||||
/* Binary patch is irreversible */
|
||||
if (patch->is_reverse)
|
||||
return error("cannot reverse-apply a binary patch to '%s'",
|
||||
patch->new_name
|
||||
? patch->new_name : patch->old_name);
|
||||
|
||||
data = inflate_it(fragment->patch, fragment->size,
|
||||
patch->deflate_origlen);
|
||||
if (!data)
|
||||
@ -1614,7 +1657,8 @@ static int apply_fragments(struct buffer_desc *desc, struct patch *patch)
|
||||
return apply_binary(desc, patch);
|
||||
|
||||
while (frag) {
|
||||
if (apply_one_fragment(desc, frag, patch->inaccurate_eof) < 0)
|
||||
if (apply_one_fragment(desc, frag, patch->is_reverse,
|
||||
patch->inaccurate_eof) < 0)
|
||||
return error("patch failed: %s:%ld",
|
||||
name, frag->oldpos);
|
||||
frag = frag->next;
|
||||
@ -1663,13 +1707,14 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_patch(struct patch *patch)
|
||||
static int check_patch(struct patch *patch, struct patch *prev_patch)
|
||||
{
|
||||
struct stat st;
|
||||
const char *old_name = patch->old_name;
|
||||
const char *new_name = patch->new_name;
|
||||
const char *name = old_name ? old_name : new_name;
|
||||
struct cache_entry *ce = NULL;
|
||||
int ok_if_exists;
|
||||
|
||||
if (old_name) {
|
||||
int changed = 0;
|
||||
@ -1727,13 +1772,33 @@ static int check_patch(struct patch *patch)
|
||||
old_name, st_mode, patch->old_mode);
|
||||
}
|
||||
|
||||
if (new_name && prev_patch && prev_patch->is_delete &&
|
||||
!strcmp(prev_patch->old_name, new_name))
|
||||
/* A type-change diff is always split into a patch to
|
||||
* delete old, immediately followed by a patch to
|
||||
* create new (see diff.c::run_diff()); in such a case
|
||||
* it is Ok that the entry to be deleted by the
|
||||
* previous patch is still in the working tree and in
|
||||
* the index.
|
||||
*/
|
||||
ok_if_exists = 1;
|
||||
else
|
||||
ok_if_exists = 0;
|
||||
|
||||
if (new_name && (patch->is_new | patch->is_rename | patch->is_copy)) {
|
||||
if (check_index && cache_name_pos(new_name, strlen(new_name)) >= 0)
|
||||
if (check_index &&
|
||||
cache_name_pos(new_name, strlen(new_name)) >= 0 &&
|
||||
!ok_if_exists)
|
||||
return error("%s: already exists in index", new_name);
|
||||
if (!cached) {
|
||||
if (!lstat(new_name, &st))
|
||||
return error("%s: already exists in working directory", new_name);
|
||||
if (errno != ENOENT)
|
||||
struct stat nst;
|
||||
if (!lstat(new_name, &nst)) {
|
||||
if (S_ISDIR(nst.st_mode) || ok_if_exists)
|
||||
; /* ok */
|
||||
else
|
||||
return error("%s: already exists in working directory", new_name);
|
||||
}
|
||||
else if ((errno != ENOENT) && (errno != ENOTDIR))
|
||||
return error("%s: %s", new_name, strerror(errno));
|
||||
}
|
||||
if (!patch->new_mode) {
|
||||
@ -1761,10 +1826,13 @@ static int check_patch(struct patch *patch)
|
||||
|
||||
static int check_patch_list(struct patch *patch)
|
||||
{
|
||||
struct patch *prev_patch = NULL;
|
||||
int error = 0;
|
||||
|
||||
for (;patch ; patch = patch->next)
|
||||
error |= check_patch(patch);
|
||||
for (prev_patch = NULL; patch ; patch = patch->next) {
|
||||
error |= check_patch(patch, prev_patch);
|
||||
prev_patch = patch;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -2009,6 +2077,16 @@ static void create_one_file(char *path, unsigned mode, const char *buf, unsigned
|
||||
return;
|
||||
}
|
||||
|
||||
if (errno == EEXIST || errno == EACCES) {
|
||||
/* We may be trying to create a file where a directory
|
||||
* used to be.
|
||||
*/
|
||||
struct stat st;
|
||||
errno = 0;
|
||||
if (!lstat(path, &st) && S_ISDIR(st.st_mode) && !rmdir(path))
|
||||
errno = EEXIST;
|
||||
}
|
||||
|
||||
if (errno == EEXIST) {
|
||||
unsigned int nr = getpid();
|
||||
|
||||
@ -2043,32 +2121,42 @@ static void create_file(struct patch *patch)
|
||||
cache_tree_invalidate_path(active_cache_tree, path);
|
||||
}
|
||||
|
||||
static void write_out_one_result(struct patch *patch)
|
||||
/* phase zero is to remove, phase one is to create */
|
||||
static void write_out_one_result(struct patch *patch, int phase)
|
||||
{
|
||||
if (patch->is_delete > 0) {
|
||||
remove_file(patch);
|
||||
if (phase == 0)
|
||||
remove_file(patch);
|
||||
return;
|
||||
}
|
||||
if (patch->is_new > 0 || patch->is_copy) {
|
||||
create_file(patch);
|
||||
if (phase == 1)
|
||||
create_file(patch);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Rename or modification boils down to the same
|
||||
* thing: remove the old, write the new
|
||||
*/
|
||||
remove_file(patch);
|
||||
if (phase == 0)
|
||||
remove_file(patch);
|
||||
if (phase == 1)
|
||||
create_file(patch);
|
||||
}
|
||||
|
||||
static void write_out_results(struct patch *list, int skipped_patch)
|
||||
{
|
||||
int phase;
|
||||
|
||||
if (!list && !skipped_patch)
|
||||
die("No changes");
|
||||
|
||||
while (list) {
|
||||
write_out_one_result(list);
|
||||
list = list->next;
|
||||
for (phase = 0; phase < 2; phase++) {
|
||||
struct patch *l = list;
|
||||
while (l) {
|
||||
write_out_one_result(l, phase);
|
||||
l = l->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2097,7 +2185,8 @@ static int use_patch(struct patch *p)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int apply_patch(int fd, const char *filename, int inaccurate_eof)
|
||||
static int apply_patch(int fd, const char *filename,
|
||||
int reverse, int inaccurate_eof)
|
||||
{
|
||||
unsigned long offset, size;
|
||||
char *buffer = read_patch_file(fd, &size);
|
||||
@ -2117,6 +2206,8 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)
|
||||
nr = parse_chunk(buffer + offset, size, patch);
|
||||
if (nr < 0)
|
||||
break;
|
||||
if (reverse)
|
||||
reverse_patches(patch);
|
||||
if (use_patch(patch)) {
|
||||
patch_stats(patch);
|
||||
*listp = patch;
|
||||
@ -2177,10 +2268,11 @@ static int git_apply_config(const char *var, const char *value)
|
||||
}
|
||||
|
||||
|
||||
int cmd_apply(int argc, const char **argv, char **envp)
|
||||
int cmd_apply(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
int read_stdin = 1;
|
||||
int reverse = 0;
|
||||
int inaccurate_eof = 0;
|
||||
|
||||
const char *whitespace_option = NULL;
|
||||
@ -2191,7 +2283,7 @@ int cmd_apply(int argc, const char **argv, char **envp)
|
||||
int fd;
|
||||
|
||||
if (!strcmp(arg, "-")) {
|
||||
apply_patch(0, "<stdin>", inaccurate_eof);
|
||||
apply_patch(0, "<stdin>", reverse, inaccurate_eof);
|
||||
read_stdin = 0;
|
||||
continue;
|
||||
}
|
||||
@ -2268,6 +2360,10 @@ int cmd_apply(int argc, const char **argv, char **envp)
|
||||
parse_whitespace_option(arg + 13);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-R") || !strcmp(arg, "--reverse")) {
|
||||
reverse = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--inaccurate-eof")) {
|
||||
inaccurate_eof = 1;
|
||||
continue;
|
||||
@ -2288,12 +2384,12 @@ int cmd_apply(int argc, const char **argv, char **envp)
|
||||
usage(apply_usage);
|
||||
read_stdin = 0;
|
||||
set_default_whitespace_mode(whitespace_option);
|
||||
apply_patch(fd, arg, inaccurate_eof);
|
||||
apply_patch(fd, arg, reverse, inaccurate_eof);
|
||||
close(fd);
|
||||
}
|
||||
set_default_whitespace_mode(whitespace_option);
|
||||
if (read_stdin)
|
||||
apply_patch(0, "<stdin>", inaccurate_eof);
|
||||
apply_patch(0, "<stdin>", reverse, inaccurate_eof);
|
||||
if (whitespace_error) {
|
||||
if (squelch_whitespace_errors &&
|
||||
squelch_whitespace_errors < whitespace_error) {
|
||||
@ -2323,7 +2419,7 @@ int cmd_apply(int argc, const char **argv, char **envp)
|
||||
|
||||
if (write_index) {
|
||||
if (write_cache(newfd, active_cache, active_nr) ||
|
||||
commit_lock_file(&lock_file))
|
||||
close(newfd) || commit_lock_file(&lock_file))
|
||||
die("Unable to write new index file");
|
||||
}
|
||||
|
||||
|
||||
@ -94,7 +94,7 @@ static int pprint_tag(const unsigned char *sha1, const char *buf, unsigned long
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_cat_file(int argc, const char **argv, char **envp)
|
||||
int cmd_cat_file(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
char type[20];
|
||||
@ -102,7 +102,6 @@ int cmd_cat_file(int argc, const char **argv, char **envp)
|
||||
unsigned long size;
|
||||
int opt;
|
||||
|
||||
setup_git_directory();
|
||||
git_config(git_default_config);
|
||||
if (argc != 3)
|
||||
usage("git-cat-file [-t|-s|-e|-p|<type>] <sha1>");
|
||||
|
||||
@ -6,9 +6,9 @@
|
||||
#include "refs.h"
|
||||
#include "builtin.h"
|
||||
|
||||
int cmd_check_ref_format(int argc, const char **argv, char **envp)
|
||||
int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
if (argc != 2)
|
||||
usage("git check-ref-format refname");
|
||||
usage("git-check-ref-format refname");
|
||||
return !!check_ref_format(argv[1]);
|
||||
}
|
||||
|
||||
@ -77,7 +77,7 @@ static int new_parent(int idx)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cmd_commit_tree(int argc, const char **argv, char **envp)
|
||||
int cmd_commit_tree(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
int parents = 0;
|
||||
@ -88,8 +88,6 @@ int cmd_commit_tree(int argc, const char **argv, char **envp)
|
||||
unsigned int size;
|
||||
|
||||
setup_ident();
|
||||
setup_git_directory();
|
||||
|
||||
git_config(git_default_config);
|
||||
|
||||
if (argc < 2)
|
||||
|
||||
@ -67,7 +67,7 @@ static void count_objects(DIR *d, char *path, int len, int verbose,
|
||||
}
|
||||
}
|
||||
|
||||
int cmd_count_objects(int ac, const char **av, char **ep)
|
||||
int cmd_count_objects(int ac, const char **av, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
int verbose = 0;
|
||||
|
||||
@ -13,13 +13,13 @@ static const char diff_files_usage[] =
|
||||
"git-diff-files [-q] [-0/-1/2/3 |-c|--cc] [<common diff options>] [<path>...]"
|
||||
COMMON_DIFF_OPTIONS_HELP;
|
||||
|
||||
int cmd_diff_files(int argc, const char **argv, char **envp)
|
||||
int cmd_diff_files(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct rev_info rev;
|
||||
int silent = 0;
|
||||
|
||||
git_config(git_diff_config);
|
||||
init_revisions(&rev);
|
||||
init_revisions(&rev, prefix);
|
||||
git_config(git_default_config); /* no "diff" UI options */
|
||||
rev.abbrev = 0;
|
||||
|
||||
argc = setup_revisions(argc, argv, &rev, NULL);
|
||||
@ -36,6 +36,9 @@ int cmd_diff_files(int argc, const char **argv, char **envp)
|
||||
usage(diff_files_usage);
|
||||
argv++; argc--;
|
||||
}
|
||||
if (!rev.diffopt.output_format)
|
||||
rev.diffopt.output_format = DIFF_FORMAT_RAW;
|
||||
|
||||
/*
|
||||
* Make sure there are NO revision (i.e. pending object) parameter,
|
||||
* rev.max_count is reasonable (0 <= n <= 3),
|
||||
|
||||
@ -9,14 +9,14 @@ static const char diff_cache_usage[] =
|
||||
"[<common diff options>] <tree-ish> [<path>...]"
|
||||
COMMON_DIFF_OPTIONS_HELP;
|
||||
|
||||
int cmd_diff_index(int argc, const char **argv, char **envp)
|
||||
int cmd_diff_index(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct rev_info rev;
|
||||
int cached = 0;
|
||||
int i;
|
||||
|
||||
git_config(git_diff_config);
|
||||
init_revisions(&rev);
|
||||
init_revisions(&rev, prefix);
|
||||
git_config(git_default_config); /* no "diff" UI options */
|
||||
rev.abbrev = 0;
|
||||
|
||||
argc = setup_revisions(argc, argv, &rev, NULL);
|
||||
@ -28,6 +28,9 @@ int cmd_diff_index(int argc, const char **argv, char **envp)
|
||||
else
|
||||
usage(diff_cache_usage);
|
||||
}
|
||||
if (!rev.diffopt.output_format)
|
||||
rev.diffopt.output_format = DIFF_FORMAT_RAW;
|
||||
|
||||
/*
|
||||
* Make sure there is one revision (i.e. pending object),
|
||||
* and there is no revision filtering parameters.
|
||||
|
||||
@ -55,13 +55,12 @@ static void diff_stages(int stage1, int stage2, const char **pathspec)
|
||||
}
|
||||
}
|
||||
|
||||
int cmd_diff_stages(int ac, const char **av, char **envp)
|
||||
int cmd_diff_stages(int ac, const char **av, const char *prefix)
|
||||
{
|
||||
int stage1, stage2;
|
||||
const char *prefix = setup_git_directory();
|
||||
const char **pathspec = NULL;
|
||||
|
||||
git_config(git_diff_config);
|
||||
git_config(git_default_config); /* no "diff" UI options */
|
||||
read_cache();
|
||||
diff_setup(&diff_options);
|
||||
while (1 < ac && av[1][0] == '-') {
|
||||
@ -85,6 +84,9 @@ int cmd_diff_stages(int ac, const char **av, char **envp)
|
||||
ac--; av++;
|
||||
}
|
||||
|
||||
if (!diff_options.output_format)
|
||||
diff_options.output_format = DIFF_FORMAT_RAW;
|
||||
|
||||
if (ac < 3 ||
|
||||
sscanf(av[1], "%d", &stage1) != 1 ||
|
||||
! (0 <= stage1 && stage1 <= 3) ||
|
||||
|
||||
@ -59,7 +59,7 @@ static const char diff_tree_usage[] =
|
||||
" --root include the initial commit as diff against /dev/null\n"
|
||||
COMMON_DIFF_OPTIONS_HELP;
|
||||
|
||||
int cmd_diff_tree(int argc, const char **argv, char **envp)
|
||||
int cmd_diff_tree(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int nr_sha1;
|
||||
char line[1000];
|
||||
@ -67,9 +67,9 @@ int cmd_diff_tree(int argc, const char **argv, char **envp)
|
||||
static struct rev_info *opt = &log_tree_opt;
|
||||
int read_stdin = 0;
|
||||
|
||||
git_config(git_diff_config);
|
||||
init_revisions(opt, prefix);
|
||||
git_config(git_default_config); /* no "diff" UI options */
|
||||
nr_sha1 = 0;
|
||||
init_revisions(opt);
|
||||
opt->abbrev = 0;
|
||||
opt->diff = 1;
|
||||
argc = setup_revisions(argc, argv, opt, NULL);
|
||||
@ -84,6 +84,9 @@ int cmd_diff_tree(int argc, const char **argv, char **envp)
|
||||
usage(diff_tree_usage);
|
||||
}
|
||||
|
||||
if (!opt->diffopt.output_format)
|
||||
opt->diffopt.output_format = DIFF_FORMAT_RAW;
|
||||
|
||||
/*
|
||||
* NOTE! We expect "a ^b" to be equal to "a..b", so we
|
||||
* reverse the order of the objects if the second one
|
||||
|
||||
@ -23,7 +23,7 @@ struct blobinfo {
|
||||
};
|
||||
|
||||
static const char builtin_diff_usage[] =
|
||||
"diff <options> <rev>{0,2} -- <path>*";
|
||||
"git-diff <options> <rev>{0,2} -- <path>*";
|
||||
|
||||
static int builtin_diff_files(struct rev_info *revs,
|
||||
int argc, const char **argv)
|
||||
@ -39,8 +39,6 @@ static int builtin_diff_files(struct rev_info *revs,
|
||||
revs->max_count = 3;
|
||||
else if (!strcmp(arg, "-q"))
|
||||
silent = 1;
|
||||
else if (!strcmp(arg, "--raw"))
|
||||
revs->diffopt.output_format = DIFF_FORMAT_RAW;
|
||||
else
|
||||
usage(builtin_diff_usage);
|
||||
argv++; argc--;
|
||||
@ -56,7 +54,7 @@ static int builtin_diff_files(struct rev_info *revs,
|
||||
3 < revs->max_count)
|
||||
usage(builtin_diff_usage);
|
||||
if (revs->max_count < 0 &&
|
||||
(revs->diffopt.output_format == DIFF_FORMAT_PATCH))
|
||||
(revs->diffopt.output_format & DIFF_FORMAT_PATCH))
|
||||
revs->combine_merges = revs->dense_combined_merges = 1;
|
||||
/*
|
||||
* Backward compatibility wart - "diff-files -s" used to
|
||||
@ -107,14 +105,9 @@ static int builtin_diff_b_f(struct rev_info *revs,
|
||||
/* Blob vs file in the working tree*/
|
||||
struct stat st;
|
||||
|
||||
while (1 < argc) {
|
||||
const char *arg = argv[1];
|
||||
if (!strcmp(arg, "--raw"))
|
||||
revs->diffopt.output_format = DIFF_FORMAT_RAW;
|
||||
else
|
||||
usage(builtin_diff_usage);
|
||||
argv++; argc--;
|
||||
}
|
||||
if (argc > 1)
|
||||
usage(builtin_diff_usage);
|
||||
|
||||
if (lstat(path, &st))
|
||||
die("'%s': %s", path, strerror(errno));
|
||||
if (!(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)))
|
||||
@ -132,23 +125,15 @@ static int builtin_diff_blobs(struct rev_info *revs,
|
||||
int argc, const char **argv,
|
||||
struct blobinfo *blob)
|
||||
{
|
||||
/* Blobs: the arguments are reversed when setup_revisions()
|
||||
* picked them up.
|
||||
*/
|
||||
unsigned mode = canon_mode(S_IFREG | 0644);
|
||||
|
||||
while (1 < argc) {
|
||||
const char *arg = argv[1];
|
||||
if (!strcmp(arg, "--raw"))
|
||||
revs->diffopt.output_format = DIFF_FORMAT_RAW;
|
||||
else
|
||||
usage(builtin_diff_usage);
|
||||
argv++; argc--;
|
||||
}
|
||||
if (argc > 1)
|
||||
usage(builtin_diff_usage);
|
||||
|
||||
stuff_change(&revs->diffopt,
|
||||
mode, mode,
|
||||
blob[1].sha1, blob[0].sha1,
|
||||
blob[0].name, blob[0].name);
|
||||
blob[0].sha1, blob[1].sha1,
|
||||
blob[0].name, blob[1].name);
|
||||
diffcore_std(&revs->diffopt);
|
||||
diff_flush(&revs->diffopt);
|
||||
return 0;
|
||||
@ -162,8 +147,6 @@ static int builtin_diff_index(struct rev_info *revs,
|
||||
const char *arg = argv[1];
|
||||
if (!strcmp(arg, "--cached"))
|
||||
cached = 1;
|
||||
else if (!strcmp(arg, "--raw"))
|
||||
revs->diffopt.output_format = DIFF_FORMAT_RAW;
|
||||
else
|
||||
usage(builtin_diff_usage);
|
||||
argv++; argc--;
|
||||
@ -185,17 +168,12 @@ static int builtin_diff_tree(struct rev_info *revs,
|
||||
{
|
||||
const unsigned char *(sha1[2]);
|
||||
int swap = 0;
|
||||
while (1 < argc) {
|
||||
const char *arg = argv[1];
|
||||
if (!strcmp(arg, "--raw"))
|
||||
revs->diffopt.output_format = DIFF_FORMAT_RAW;
|
||||
else
|
||||
usage(builtin_diff_usage);
|
||||
argv++; argc--;
|
||||
}
|
||||
|
||||
if (argc > 1)
|
||||
usage(builtin_diff_usage);
|
||||
|
||||
/* We saw two trees, ent[0] and ent[1].
|
||||
* if ent[1] is unintesting, they are swapped
|
||||
* if ent[1] is uninteresting, they are swapped
|
||||
*/
|
||||
if (ent[1].item->flags & UNINTERESTING)
|
||||
swap = 1;
|
||||
@ -214,14 +192,9 @@ static int builtin_diff_combined(struct rev_info *revs,
|
||||
const unsigned char (*parent)[20];
|
||||
int i;
|
||||
|
||||
while (1 < argc) {
|
||||
const char *arg = argv[1];
|
||||
if (!strcmp(arg, "--raw"))
|
||||
revs->diffopt.output_format = DIFF_FORMAT_RAW;
|
||||
else
|
||||
usage(builtin_diff_usage);
|
||||
argv++; argc--;
|
||||
}
|
||||
if (argc > 1)
|
||||
usage(builtin_diff_usage);
|
||||
|
||||
if (!revs->dense_combined_merges && !revs->combine_merges)
|
||||
revs->dense_combined_merges = revs->combine_merges = 1;
|
||||
parent = xmalloc(ents * sizeof(*parent));
|
||||
@ -245,7 +218,7 @@ void add_head(struct rev_info *revs)
|
||||
add_pending_object(revs, obj, "HEAD");
|
||||
}
|
||||
|
||||
int cmd_diff(int argc, const char **argv, char **envp)
|
||||
int cmd_diff(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
struct rev_info rev;
|
||||
@ -274,11 +247,15 @@ int cmd_diff(int argc, const char **argv, char **envp)
|
||||
* Other cases are errors.
|
||||
*/
|
||||
|
||||
git_config(git_diff_config);
|
||||
init_revisions(&rev);
|
||||
rev.diffopt.output_format = DIFF_FORMAT_PATCH;
|
||||
git_config(git_diff_ui_config);
|
||||
init_revisions(&rev, prefix);
|
||||
|
||||
argc = setup_revisions(argc, argv, &rev, NULL);
|
||||
if (!rev.diffopt.output_format) {
|
||||
rev.diffopt.output_format = DIFF_FORMAT_PATCH;
|
||||
diff_setup_done(&rev.diffopt);
|
||||
}
|
||||
|
||||
/* Do we have --cached and not have a pending object, then
|
||||
* default to HEAD by hand. Eek.
|
||||
*/
|
||||
@ -305,9 +282,9 @@ int cmd_diff(int argc, const char **argv, char **envp)
|
||||
obj = deref_tag(obj, NULL, 0);
|
||||
if (!obj)
|
||||
die("invalid object '%s' given.", name);
|
||||
if (obj->type == TYPE_COMMIT)
|
||||
if (obj->type == OBJ_COMMIT)
|
||||
obj = &((struct commit *)obj)->tree->object;
|
||||
if (obj->type == TYPE_TREE) {
|
||||
if (obj->type == OBJ_TREE) {
|
||||
if (ARRAY_SIZE(ent) <= ents)
|
||||
die("more than %d trees given: '%s'",
|
||||
(int) ARRAY_SIZE(ent), name);
|
||||
@ -317,7 +294,7 @@ int cmd_diff(int argc, const char **argv, char **envp)
|
||||
ents++;
|
||||
continue;
|
||||
}
|
||||
if (obj->type == TYPE_BLOB) {
|
||||
if (obj->type == OBJ_BLOB) {
|
||||
if (2 <= blobs)
|
||||
die("more than two blobs given: '%s'", name);
|
||||
memcpy(blob[blobs].sha1, obj->sha1, 20);
|
||||
@ -366,7 +343,15 @@ int cmd_diff(int argc, const char **argv, char **envp)
|
||||
return builtin_diff_index(&rev, argc, argv);
|
||||
else if (ents == 2)
|
||||
return builtin_diff_tree(&rev, argc, argv, ent);
|
||||
else if ((ents == 3) && (ent[0].item->flags & UNINTERESTING)) {
|
||||
/* diff A...B where there is one sane merge base between
|
||||
* A and B. We have ent[0] == merge-base, ent[1] == A,
|
||||
* and ent[2] == B. Show diff between the base and B.
|
||||
*/
|
||||
return builtin_diff_tree(&rev, argc, argv, ent);
|
||||
}
|
||||
else
|
||||
return builtin_diff_combined(&rev, argc, argv, ent, ents);
|
||||
return builtin_diff_combined(&rev, argc, argv,
|
||||
ent, ents);
|
||||
usage(builtin_diff_usage);
|
||||
}
|
||||
|
||||
360
builtin-fmt-merge-msg.c
Normal file
360
builtin-fmt-merge-msg.c
Normal file
@ -0,0 +1,360 @@
|
||||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
#include "commit.h"
|
||||
#include "diff.h"
|
||||
#include "revision.h"
|
||||
#include "tag.h"
|
||||
|
||||
static const char *fmt_merge_msg_usage =
|
||||
"git-fmt-merge-msg [--summary] [--no-summary] [--file <file>]";
|
||||
|
||||
static int merge_summary = 0;
|
||||
|
||||
static int fmt_merge_msg_config(const char *key, const char *value)
|
||||
{
|
||||
if (!strcmp("merge.summary", key))
|
||||
merge_summary = git_config_bool(key, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct list {
|
||||
char **list;
|
||||
void **payload;
|
||||
unsigned nr, alloc;
|
||||
};
|
||||
|
||||
static void append_to_list(struct list *list, char *value, void *payload)
|
||||
{
|
||||
if (list->nr == list->alloc) {
|
||||
list->alloc += 32;
|
||||
list->list = realloc(list->list, sizeof(char *) * list->alloc);
|
||||
list->payload = realloc(list->payload,
|
||||
sizeof(char *) * list->alloc);
|
||||
}
|
||||
list->payload[list->nr] = payload;
|
||||
list->list[list->nr++] = value;
|
||||
}
|
||||
|
||||
static int find_in_list(struct list *list, char *value)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < list->nr; i++)
|
||||
if (!strcmp(list->list[i], value))
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void free_list(struct list *list)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (list->alloc == 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < list->nr; i++) {
|
||||
free(list->list[i]);
|
||||
if (list->payload[i])
|
||||
free(list->payload[i]);
|
||||
}
|
||||
free(list->list);
|
||||
free(list->payload);
|
||||
list->nr = list->alloc = 0;
|
||||
}
|
||||
|
||||
struct src_data {
|
||||
struct list branch, tag, r_branch, generic;
|
||||
int head_status;
|
||||
};
|
||||
|
||||
static struct list srcs = { NULL, NULL, 0, 0};
|
||||
static struct list origins = { NULL, NULL, 0, 0};
|
||||
|
||||
static int handle_line(char *line)
|
||||
{
|
||||
int i, len = strlen(line);
|
||||
unsigned char *sha1;
|
||||
char *src, *origin;
|
||||
struct src_data *src_data;
|
||||
int pulling_head = 0;
|
||||
|
||||
if (len < 43 || line[40] != '\t')
|
||||
return 1;
|
||||
|
||||
if (!strncmp(line + 41, "not-for-merge", 13))
|
||||
return 0;
|
||||
|
||||
if (line[41] != '\t')
|
||||
return 2;
|
||||
|
||||
line[40] = 0;
|
||||
sha1 = xmalloc(20);
|
||||
i = get_sha1(line, sha1);
|
||||
line[40] = '\t';
|
||||
if (i)
|
||||
return 3;
|
||||
|
||||
if (line[len - 1] == '\n')
|
||||
line[len - 1] = 0;
|
||||
line += 42;
|
||||
|
||||
src = strstr(line, " of ");
|
||||
if (src) {
|
||||
*src = 0;
|
||||
src += 4;
|
||||
pulling_head = 0;
|
||||
} else {
|
||||
src = line;
|
||||
pulling_head = 1;
|
||||
}
|
||||
|
||||
i = find_in_list(&srcs, src);
|
||||
if (i < 0) {
|
||||
i = srcs.nr;
|
||||
append_to_list(&srcs, strdup(src),
|
||||
xcalloc(1, sizeof(struct src_data)));
|
||||
}
|
||||
src_data = srcs.payload[i];
|
||||
|
||||
if (pulling_head) {
|
||||
origin = strdup(src);
|
||||
src_data->head_status |= 1;
|
||||
} else if (!strncmp(line, "branch ", 7)) {
|
||||
origin = strdup(line + 7);
|
||||
append_to_list(&src_data->branch, origin, NULL);
|
||||
src_data->head_status |= 2;
|
||||
} else if (!strncmp(line, "tag ", 4)) {
|
||||
origin = line;
|
||||
append_to_list(&src_data->tag, strdup(origin + 4), NULL);
|
||||
src_data->head_status |= 2;
|
||||
} else if (!strncmp(line, "remote branch ", 14)) {
|
||||
origin = strdup(line + 14);
|
||||
append_to_list(&src_data->r_branch, origin, NULL);
|
||||
src_data->head_status |= 2;
|
||||
} else {
|
||||
origin = strdup(src);
|
||||
append_to_list(&src_data->generic, strdup(line), NULL);
|
||||
src_data->head_status |= 2;
|
||||
}
|
||||
|
||||
if (!strcmp(".", src) || !strcmp(src, origin)) {
|
||||
int len = strlen(origin);
|
||||
if (origin[0] == '\'' && origin[len - 1] == '\'') {
|
||||
char *new_origin = malloc(len - 1);
|
||||
memcpy(new_origin, origin + 1, len - 2);
|
||||
new_origin[len - 1] = 0;
|
||||
origin = new_origin;
|
||||
} else
|
||||
origin = strdup(origin);
|
||||
} else {
|
||||
char *new_origin = malloc(strlen(origin) + strlen(src) + 5);
|
||||
sprintf(new_origin, "%s of %s", origin, src);
|
||||
origin = new_origin;
|
||||
}
|
||||
append_to_list(&origins, origin, sha1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_joined(const char *singular, const char *plural,
|
||||
struct list *list)
|
||||
{
|
||||
if (list->nr == 0)
|
||||
return;
|
||||
if (list->nr == 1) {
|
||||
printf("%s%s", singular, list->list[0]);
|
||||
} else {
|
||||
int i;
|
||||
printf("%s", plural);
|
||||
for (i = 0; i < list->nr - 1; i++)
|
||||
printf("%s%s", i > 0 ? ", " : "", list->list[i]);
|
||||
printf(" and %s", list->list[list->nr - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
static void shortlog(const char *name, unsigned char *sha1,
|
||||
struct commit *head, struct rev_info *rev, int limit)
|
||||
{
|
||||
int i, count = 0;
|
||||
struct commit *commit;
|
||||
struct object *branch;
|
||||
struct list subjects = { NULL, NULL, 0, 0 };
|
||||
int flags = UNINTERESTING | TREECHANGE | SEEN | SHOWN | ADDED;
|
||||
|
||||
branch = deref_tag(parse_object(sha1), sha1_to_hex(sha1), 40);
|
||||
if (!branch || branch->type != OBJ_COMMIT)
|
||||
return;
|
||||
|
||||
setup_revisions(0, NULL, rev, NULL);
|
||||
rev->ignore_merges = 1;
|
||||
add_pending_object(rev, branch, name);
|
||||
add_pending_object(rev, &head->object, "^HEAD");
|
||||
head->object.flags |= UNINTERESTING;
|
||||
prepare_revision_walk(rev);
|
||||
while ((commit = get_revision(rev)) != NULL) {
|
||||
char *oneline, *bol, *eol;
|
||||
|
||||
/* ignore merges */
|
||||
if (commit->parents && commit->parents->next)
|
||||
continue;
|
||||
|
||||
count++;
|
||||
if (subjects.nr > limit)
|
||||
continue;
|
||||
|
||||
bol = strstr(commit->buffer, "\n\n");
|
||||
if (!bol) {
|
||||
append_to_list(&subjects, strdup(sha1_to_hex(
|
||||
commit->object.sha1)),
|
||||
NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
bol += 2;
|
||||
eol = strchr(bol, '\n');
|
||||
|
||||
if (eol) {
|
||||
int len = eol - bol;
|
||||
oneline = malloc(len + 1);
|
||||
memcpy(oneline, bol, len);
|
||||
oneline[len] = 0;
|
||||
} else
|
||||
oneline = strdup(bol);
|
||||
append_to_list(&subjects, oneline, NULL);
|
||||
}
|
||||
|
||||
if (count > limit)
|
||||
printf("\n* %s: (%d commits)\n", name, count);
|
||||
else
|
||||
printf("\n* %s:\n", name);
|
||||
|
||||
for (i = 0; i < subjects.nr; i++)
|
||||
if (i >= limit)
|
||||
printf(" ...\n");
|
||||
else
|
||||
printf(" %s\n", subjects.list[i]);
|
||||
|
||||
clear_commit_marks((struct commit *)branch, flags);
|
||||
clear_commit_marks(head, flags);
|
||||
free_commit_list(rev->commits);
|
||||
rev->commits = NULL;
|
||||
rev->pending.nr = 0;
|
||||
|
||||
free_list(&subjects);
|
||||
}
|
||||
|
||||
int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int limit = 20, i = 0;
|
||||
char line[1024];
|
||||
FILE *in = stdin;
|
||||
const char *sep = "";
|
||||
unsigned char head_sha1[20];
|
||||
const char *head, *current_branch;
|
||||
|
||||
git_config(fmt_merge_msg_config);
|
||||
|
||||
while (argc > 1) {
|
||||
if (!strcmp(argv[1], "--summary"))
|
||||
merge_summary = 1;
|
||||
else if (!strcmp(argv[1], "--no-summary"))
|
||||
merge_summary = 0;
|
||||
else if (!strcmp(argv[1], "-F") || !strcmp(argv[1], "--file")) {
|
||||
if (argc < 2)
|
||||
die ("Which file?");
|
||||
if (!strcmp(argv[2], "-"))
|
||||
in = stdin;
|
||||
else {
|
||||
fclose(in);
|
||||
in = fopen(argv[2], "r");
|
||||
}
|
||||
argc--; argv++;
|
||||
} else
|
||||
break;
|
||||
argc--; argv++;
|
||||
}
|
||||
|
||||
if (argc > 1)
|
||||
usage(fmt_merge_msg_usage);
|
||||
|
||||
/* get current branch */
|
||||
head = strdup(git_path("HEAD"));
|
||||
current_branch = resolve_ref(head, head_sha1, 1);
|
||||
current_branch += strlen(head) - 4;
|
||||
free((char *)head);
|
||||
if (!strncmp(current_branch, "refs/heads/", 11))
|
||||
current_branch += 11;
|
||||
|
||||
while (fgets(line, sizeof(line), in)) {
|
||||
i++;
|
||||
if (line[0] == 0)
|
||||
continue;
|
||||
if (handle_line(line))
|
||||
die ("Error in line %d: %s", i, line);
|
||||
}
|
||||
|
||||
printf("Merge ");
|
||||
for (i = 0; i < srcs.nr; i++) {
|
||||
struct src_data *src_data = srcs.payload[i];
|
||||
const char *subsep = "";
|
||||
|
||||
printf(sep);
|
||||
sep = "; ";
|
||||
|
||||
if (src_data->head_status == 1) {
|
||||
printf(srcs.list[i]);
|
||||
continue;
|
||||
}
|
||||
if (src_data->head_status == 3) {
|
||||
subsep = ", ";
|
||||
printf("HEAD");
|
||||
}
|
||||
if (src_data->branch.nr) {
|
||||
printf(subsep);
|
||||
subsep = ", ";
|
||||
print_joined("branch ", "branches ", &src_data->branch);
|
||||
}
|
||||
if (src_data->r_branch.nr) {
|
||||
printf(subsep);
|
||||
subsep = ", ";
|
||||
print_joined("remote branch ", "remote branches ",
|
||||
&src_data->r_branch);
|
||||
}
|
||||
if (src_data->tag.nr) {
|
||||
printf(subsep);
|
||||
subsep = ", ";
|
||||
print_joined("tag ", "tags ", &src_data->tag);
|
||||
}
|
||||
if (src_data->generic.nr) {
|
||||
printf(subsep);
|
||||
print_joined("commit ", "commits ", &src_data->generic);
|
||||
}
|
||||
if (strcmp(".", srcs.list[i]))
|
||||
printf(" of %s", srcs.list[i]);
|
||||
}
|
||||
|
||||
if (!strcmp("master", current_branch))
|
||||
putchar('\n');
|
||||
else
|
||||
printf(" into %s\n", current_branch);
|
||||
|
||||
if (merge_summary) {
|
||||
struct commit *head;
|
||||
struct rev_info rev;
|
||||
|
||||
head = lookup_commit(head_sha1);
|
||||
init_revisions(&rev, prefix);
|
||||
rev.commit_format = CMIT_FMT_ONELINE;
|
||||
rev.ignore_merges = 1;
|
||||
rev.limited = 1;
|
||||
|
||||
for (i = 0; i < origins.nr; i++)
|
||||
shortlog(origins.list[i], origins.payload[i],
|
||||
head, &rev, limit);
|
||||
}
|
||||
|
||||
/* No cleanup yet; is standalone anyway */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
438
builtin-grep.c
438
builtin-grep.c
@ -82,17 +82,47 @@ static int pathspec_matches(const char **paths, const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum grep_pat_token {
|
||||
GREP_PATTERN,
|
||||
GREP_AND,
|
||||
GREP_OPEN_PAREN,
|
||||
GREP_CLOSE_PAREN,
|
||||
GREP_NOT,
|
||||
GREP_OR,
|
||||
};
|
||||
|
||||
struct grep_pat {
|
||||
struct grep_pat *next;
|
||||
const char *origin;
|
||||
int no;
|
||||
enum grep_pat_token token;
|
||||
const char *pattern;
|
||||
regex_t regexp;
|
||||
};
|
||||
|
||||
enum grep_expr_node {
|
||||
GREP_NODE_ATOM,
|
||||
GREP_NODE_NOT,
|
||||
GREP_NODE_AND,
|
||||
GREP_NODE_OR,
|
||||
};
|
||||
|
||||
struct grep_expr {
|
||||
enum grep_expr_node node;
|
||||
union {
|
||||
struct grep_pat *atom;
|
||||
struct grep_expr *unary;
|
||||
struct {
|
||||
struct grep_expr *left;
|
||||
struct grep_expr *right;
|
||||
} binary;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct grep_opt {
|
||||
struct grep_pat *pattern_list;
|
||||
struct grep_pat **pattern_tail;
|
||||
struct grep_expr *pattern_expression;
|
||||
regex_t regexp;
|
||||
unsigned linenum:1;
|
||||
unsigned invert:1;
|
||||
@ -105,43 +135,224 @@ struct grep_opt {
|
||||
#define GREP_BINARY_NOMATCH 1
|
||||
#define GREP_BINARY_TEXT 2
|
||||
unsigned binary:2;
|
||||
unsigned extended:1;
|
||||
int regflags;
|
||||
unsigned pre_context;
|
||||
unsigned post_context;
|
||||
};
|
||||
|
||||
static void add_pattern(struct grep_opt *opt, const char *pat,
|
||||
const char *origin, int no)
|
||||
const char *origin, int no, enum grep_pat_token t)
|
||||
{
|
||||
struct grep_pat *p = xcalloc(1, sizeof(*p));
|
||||
p->pattern = pat;
|
||||
p->origin = origin;
|
||||
p->no = no;
|
||||
p->token = t;
|
||||
*opt->pattern_tail = p;
|
||||
opt->pattern_tail = &p->next;
|
||||
p->next = NULL;
|
||||
}
|
||||
|
||||
static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)
|
||||
{
|
||||
int err = regcomp(&p->regexp, p->pattern, opt->regflags);
|
||||
if (err) {
|
||||
char errbuf[1024];
|
||||
char where[1024];
|
||||
if (p->no)
|
||||
sprintf(where, "In '%s' at %d, ",
|
||||
p->origin, p->no);
|
||||
else if (p->origin)
|
||||
sprintf(where, "%s, ", p->origin);
|
||||
else
|
||||
where[0] = 0;
|
||||
regerror(err, &p->regexp, errbuf, 1024);
|
||||
regfree(&p->regexp);
|
||||
die("%s'%s': %s", where, p->pattern, errbuf);
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
static inline void indent(int in)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < in; i++) putchar(' ');
|
||||
}
|
||||
|
||||
static void dump_pattern_exp(struct grep_expr *x, int in)
|
||||
{
|
||||
switch (x->node) {
|
||||
case GREP_NODE_ATOM:
|
||||
indent(in);
|
||||
puts(x->u.atom->pattern);
|
||||
break;
|
||||
case GREP_NODE_NOT:
|
||||
indent(in);
|
||||
puts("--not");
|
||||
dump_pattern_exp(x->u.unary, in+1);
|
||||
break;
|
||||
case GREP_NODE_AND:
|
||||
dump_pattern_exp(x->u.binary.left, in+1);
|
||||
indent(in);
|
||||
puts("--and");
|
||||
dump_pattern_exp(x->u.binary.right, in+1);
|
||||
break;
|
||||
case GREP_NODE_OR:
|
||||
dump_pattern_exp(x->u.binary.left, in+1);
|
||||
indent(in);
|
||||
puts("--or");
|
||||
dump_pattern_exp(x->u.binary.right, in+1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void looking_at(const char *msg, struct grep_pat **list)
|
||||
{
|
||||
struct grep_pat *p = *list;
|
||||
fprintf(stderr, "%s: looking at ", msg);
|
||||
if (!p)
|
||||
fprintf(stderr, "empty\n");
|
||||
else
|
||||
fprintf(stderr, "<%s>\n", p->pattern);
|
||||
}
|
||||
#else
|
||||
#define looking_at(a,b) do {} while(0)
|
||||
#endif
|
||||
|
||||
static struct grep_expr *compile_pattern_expr(struct grep_pat **);
|
||||
static struct grep_expr *compile_pattern_atom(struct grep_pat **list)
|
||||
{
|
||||
struct grep_pat *p;
|
||||
struct grep_expr *x;
|
||||
|
||||
looking_at("atom", list);
|
||||
|
||||
p = *list;
|
||||
switch (p->token) {
|
||||
case GREP_PATTERN: /* atom */
|
||||
x = xcalloc(1, sizeof (struct grep_expr));
|
||||
x->node = GREP_NODE_ATOM;
|
||||
x->u.atom = p;
|
||||
*list = p->next;
|
||||
return x;
|
||||
case GREP_OPEN_PAREN:
|
||||
*list = p->next;
|
||||
x = compile_pattern_expr(list);
|
||||
if (!x)
|
||||
return NULL;
|
||||
if (!*list || (*list)->token != GREP_CLOSE_PAREN)
|
||||
die("unmatched parenthesis");
|
||||
*list = (*list)->next;
|
||||
return x;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static struct grep_expr *compile_pattern_not(struct grep_pat **list)
|
||||
{
|
||||
struct grep_pat *p;
|
||||
struct grep_expr *x;
|
||||
|
||||
looking_at("not", list);
|
||||
|
||||
p = *list;
|
||||
switch (p->token) {
|
||||
case GREP_NOT:
|
||||
if (!p->next)
|
||||
die("--not not followed by pattern expression");
|
||||
*list = p->next;
|
||||
x = xcalloc(1, sizeof (struct grep_expr));
|
||||
x->node = GREP_NODE_NOT;
|
||||
x->u.unary = compile_pattern_not(list);
|
||||
if (!x->u.unary)
|
||||
die("--not followed by non pattern expression");
|
||||
return x;
|
||||
default:
|
||||
return compile_pattern_atom(list);
|
||||
}
|
||||
}
|
||||
|
||||
static struct grep_expr *compile_pattern_and(struct grep_pat **list)
|
||||
{
|
||||
struct grep_pat *p;
|
||||
struct grep_expr *x, *y, *z;
|
||||
|
||||
looking_at("and", list);
|
||||
|
||||
x = compile_pattern_not(list);
|
||||
p = *list;
|
||||
if (p && p->token == GREP_AND) {
|
||||
if (!p->next)
|
||||
die("--and not followed by pattern expression");
|
||||
*list = p->next;
|
||||
y = compile_pattern_and(list);
|
||||
if (!y)
|
||||
die("--and not followed by pattern expression");
|
||||
z = xcalloc(1, sizeof (struct grep_expr));
|
||||
z->node = GREP_NODE_AND;
|
||||
z->u.binary.left = x;
|
||||
z->u.binary.right = y;
|
||||
return z;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
static struct grep_expr *compile_pattern_or(struct grep_pat **list)
|
||||
{
|
||||
struct grep_pat *p;
|
||||
struct grep_expr *x, *y, *z;
|
||||
|
||||
looking_at("or", list);
|
||||
|
||||
x = compile_pattern_and(list);
|
||||
p = *list;
|
||||
if (x && p && p->token != GREP_CLOSE_PAREN) {
|
||||
y = compile_pattern_or(list);
|
||||
if (!y)
|
||||
die("not a pattern expression %s", p->pattern);
|
||||
z = xcalloc(1, sizeof (struct grep_expr));
|
||||
z->node = GREP_NODE_OR;
|
||||
z->u.binary.left = x;
|
||||
z->u.binary.right = y;
|
||||
return z;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
static struct grep_expr *compile_pattern_expr(struct grep_pat **list)
|
||||
{
|
||||
looking_at("expr", list);
|
||||
|
||||
return compile_pattern_or(list);
|
||||
}
|
||||
|
||||
static void compile_patterns(struct grep_opt *opt)
|
||||
{
|
||||
struct grep_pat *p;
|
||||
|
||||
/* First compile regexps */
|
||||
for (p = opt->pattern_list; p; p = p->next) {
|
||||
int err = regcomp(&p->regexp, p->pattern, opt->regflags);
|
||||
if (err) {
|
||||
char errbuf[1024];
|
||||
char where[1024];
|
||||
if (p->no)
|
||||
sprintf(where, "In '%s' at %d, ",
|
||||
p->origin, p->no);
|
||||
else if (p->origin)
|
||||
sprintf(where, "%s, ", p->origin);
|
||||
else
|
||||
where[0] = 0;
|
||||
regerror(err, &p->regexp, errbuf, 1024);
|
||||
regfree(&p->regexp);
|
||||
die("%s'%s': %s", where, p->pattern, errbuf);
|
||||
}
|
||||
if (p->token == GREP_PATTERN)
|
||||
compile_regexp(p, opt);
|
||||
else
|
||||
opt->extended = 1;
|
||||
}
|
||||
|
||||
if (!opt->extended)
|
||||
return;
|
||||
|
||||
/* Then bundle them up in an expression.
|
||||
* A classic recursive descent parser would do.
|
||||
*/
|
||||
p = opt->pattern_list;
|
||||
opt->pattern_expression = compile_pattern_expr(&p);
|
||||
#if DEBUG
|
||||
dump_pattern_exp(opt->pattern_expression, 0);
|
||||
#endif
|
||||
if (p)
|
||||
die("incomplete pattern expression: %s", p->pattern);
|
||||
}
|
||||
|
||||
static char *end_of_line(char *cp, unsigned long *left)
|
||||
@ -196,6 +407,94 @@ static int fixmatch(const char *pattern, char *line, regmatch_t *match)
|
||||
}
|
||||
}
|
||||
|
||||
static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol, char *eol)
|
||||
{
|
||||
int hit = 0;
|
||||
int at_true_bol = 1;
|
||||
regmatch_t pmatch[10];
|
||||
|
||||
again:
|
||||
if (!opt->fixed) {
|
||||
regex_t *exp = &p->regexp;
|
||||
hit = !regexec(exp, bol, ARRAY_SIZE(pmatch),
|
||||
pmatch, 0);
|
||||
}
|
||||
else {
|
||||
hit = !fixmatch(p->pattern, bol, pmatch);
|
||||
}
|
||||
|
||||
if (hit && opt->word_regexp) {
|
||||
if ((pmatch[0].rm_so < 0) ||
|
||||
(eol - bol) <= pmatch[0].rm_so ||
|
||||
(pmatch[0].rm_eo < 0) ||
|
||||
(eol - bol) < pmatch[0].rm_eo)
|
||||
die("regexp returned nonsense");
|
||||
|
||||
/* Match beginning must be either beginning of the
|
||||
* line, or at word boundary (i.e. the last char must
|
||||
* not be a word char). Similarly, match end must be
|
||||
* either end of the line, or at word boundary
|
||||
* (i.e. the next char must not be a word char).
|
||||
*/
|
||||
if ( ((pmatch[0].rm_so == 0 && at_true_bol) ||
|
||||
!word_char(bol[pmatch[0].rm_so-1])) &&
|
||||
((pmatch[0].rm_eo == (eol-bol)) ||
|
||||
!word_char(bol[pmatch[0].rm_eo])) )
|
||||
;
|
||||
else
|
||||
hit = 0;
|
||||
|
||||
if (!hit && pmatch[0].rm_so + bol + 1 < eol) {
|
||||
/* There could be more than one match on the
|
||||
* line, and the first match might not be
|
||||
* strict word match. But later ones could be!
|
||||
*/
|
||||
bol = pmatch[0].rm_so + bol + 1;
|
||||
at_true_bol = 0;
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
|
||||
static int match_expr_eval(struct grep_opt *opt,
|
||||
struct grep_expr *x,
|
||||
char *bol, char *eol)
|
||||
{
|
||||
switch (x->node) {
|
||||
case GREP_NODE_ATOM:
|
||||
return match_one_pattern(opt, x->u.atom, bol, eol);
|
||||
break;
|
||||
case GREP_NODE_NOT:
|
||||
return !match_expr_eval(opt, x->u.unary, bol, eol);
|
||||
case GREP_NODE_AND:
|
||||
return (match_expr_eval(opt, x->u.binary.left, bol, eol) &&
|
||||
match_expr_eval(opt, x->u.binary.right, bol, eol));
|
||||
case GREP_NODE_OR:
|
||||
return (match_expr_eval(opt, x->u.binary.left, bol, eol) ||
|
||||
match_expr_eval(opt, x->u.binary.right, bol, eol));
|
||||
}
|
||||
die("Unexpected node type (internal error) %d\n", x->node);
|
||||
}
|
||||
|
||||
static int match_expr(struct grep_opt *opt, char *bol, char *eol)
|
||||
{
|
||||
struct grep_expr *x = opt->pattern_expression;
|
||||
return match_expr_eval(opt, x, bol, eol);
|
||||
}
|
||||
|
||||
static int match_line(struct grep_opt *opt, char *bol, char *eol)
|
||||
{
|
||||
struct grep_pat *p;
|
||||
if (opt->extended)
|
||||
return match_expr(opt, bol, eol);
|
||||
for (p = opt->pattern_list; p; p = p->next) {
|
||||
if (match_one_pattern(opt, p, bol, eol))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int grep_buffer(struct grep_opt *opt, const char *name,
|
||||
char *buf, unsigned long size)
|
||||
{
|
||||
@ -231,46 +530,15 @@ static int grep_buffer(struct grep_opt *opt, const char *name,
|
||||
hunk_mark = "--\n";
|
||||
|
||||
while (left) {
|
||||
regmatch_t pmatch[10];
|
||||
char *eol, ch;
|
||||
int hit = 0;
|
||||
struct grep_pat *p;
|
||||
|
||||
eol = end_of_line(bol, &left);
|
||||
ch = *eol;
|
||||
*eol = 0;
|
||||
|
||||
for (p = opt->pattern_list; p; p = p->next) {
|
||||
if (!opt->fixed) {
|
||||
regex_t *exp = &p->regexp;
|
||||
hit = !regexec(exp, bol, ARRAY_SIZE(pmatch),
|
||||
pmatch, 0);
|
||||
}
|
||||
else {
|
||||
hit = !fixmatch(p->pattern, bol, pmatch);
|
||||
}
|
||||
hit = match_line(opt, bol, eol);
|
||||
|
||||
if (hit && opt->word_regexp) {
|
||||
/* Match beginning must be either
|
||||
* beginning of the line, or at word
|
||||
* boundary (i.e. the last char must
|
||||
* not be alnum or underscore).
|
||||
*/
|
||||
if ((pmatch[0].rm_so < 0) ||
|
||||
(eol - bol) <= pmatch[0].rm_so ||
|
||||
(pmatch[0].rm_eo < 0) ||
|
||||
(eol - bol) < pmatch[0].rm_eo)
|
||||
die("regexp returned nonsense");
|
||||
if (pmatch[0].rm_so != 0 &&
|
||||
word_char(bol[pmatch[0].rm_so-1]))
|
||||
hit = 0;
|
||||
if (pmatch[0].rm_eo != (eol-bol) &&
|
||||
word_char(bol[pmatch[0].rm_eo]))
|
||||
hit = 0;
|
||||
}
|
||||
if (hit)
|
||||
break;
|
||||
}
|
||||
/* "grep -v -e foo -e bla" should list lines
|
||||
* that do not have either, so inversion should
|
||||
* be done outside.
|
||||
@ -446,12 +714,14 @@ static int exec_grep(int argc, const char **argv)
|
||||
|
||||
static int external_grep(struct grep_opt *opt, const char **paths, int cached)
|
||||
{
|
||||
int i, nr, argc, hit, len;
|
||||
int i, nr, argc, hit, len, status;
|
||||
const char *argv[MAXARGS+1];
|
||||
char randarg[ARGBUF];
|
||||
char *argptr = randarg;
|
||||
struct grep_pat *p;
|
||||
|
||||
if (opt->extended)
|
||||
return -1;
|
||||
len = nr = 0;
|
||||
push_arg("grep");
|
||||
if (opt->fixed)
|
||||
@ -536,12 +806,17 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
|
||||
argv[argc++] = name;
|
||||
if (argc < MAXARGS)
|
||||
continue;
|
||||
hit += exec_grep(argc, argv);
|
||||
status = exec_grep(argc, argv);
|
||||
if (0 < status)
|
||||
hit = 1;
|
||||
argc = nr;
|
||||
}
|
||||
if (argc > nr)
|
||||
hit += exec_grep(argc, argv);
|
||||
return 0;
|
||||
if (argc > nr) {
|
||||
status = exec_grep(argc, argv);
|
||||
if (0 < status)
|
||||
hit = 1;
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
|
||||
static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
|
||||
@ -631,9 +906,9 @@ static int grep_tree(struct grep_opt *opt, const char **paths,
|
||||
static int grep_object(struct grep_opt *opt, const char **paths,
|
||||
struct object *obj, const char *name)
|
||||
{
|
||||
if (obj->type == TYPE_BLOB)
|
||||
if (obj->type == OBJ_BLOB)
|
||||
return grep_sha1(opt, obj->sha1, name);
|
||||
if (obj->type == TYPE_COMMIT || obj->type == TYPE_TREE) {
|
||||
if (obj->type == OBJ_COMMIT || obj->type == OBJ_TREE) {
|
||||
struct tree_desc tree;
|
||||
void *data;
|
||||
int hit;
|
||||
@ -652,14 +927,20 @@ static int grep_object(struct grep_opt *opt, const char **paths,
|
||||
static const char builtin_grep_usage[] =
|
||||
"git-grep <option>* <rev>* [-e] <pattern> [<path>...]";
|
||||
|
||||
int cmd_grep(int argc, const char **argv, char **envp)
|
||||
static const char emsg_invalid_context_len[] =
|
||||
"%s: invalid context length argument";
|
||||
static const char emsg_missing_context_len[] =
|
||||
"missing context length argument";
|
||||
static const char emsg_missing_argument[] =
|
||||
"option requires an argument -%s";
|
||||
|
||||
int cmd_grep(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int hit = 0;
|
||||
int cached = 0;
|
||||
int seen_dashdash = 0;
|
||||
struct grep_opt opt;
|
||||
struct object_array list = { 0, 0, NULL };
|
||||
const char *prefix = setup_git_directory();
|
||||
const char **paths = NULL;
|
||||
int i;
|
||||
|
||||
@ -674,7 +955,7 @@ int cmd_grep(int argc, const char **argv, char **envp)
|
||||
* pattern, but then what follows it must be zero or more
|
||||
* valid refs up to the -- (if exists), and then existing
|
||||
* paths. If there is an explicit pattern, then the first
|
||||
* unrecocnized non option is the beginning of the refs list
|
||||
* unrecognized non option is the beginning of the refs list
|
||||
* that continues up to the -- (if exists), and then paths.
|
||||
*/
|
||||
|
||||
@ -759,7 +1040,7 @@ int cmd_grep(int argc, const char **argv, char **envp)
|
||||
case 'A': case 'B': case 'C':
|
||||
if (!arg[2]) {
|
||||
if (argc <= 1)
|
||||
usage(builtin_grep_usage);
|
||||
die(emsg_missing_context_len);
|
||||
scan = *++argv;
|
||||
argc--;
|
||||
}
|
||||
@ -771,7 +1052,7 @@ int cmd_grep(int argc, const char **argv, char **envp)
|
||||
break;
|
||||
}
|
||||
if (sscanf(scan, "%u", &num) != 1)
|
||||
usage(builtin_grep_usage);
|
||||
die(emsg_invalid_context_len, scan);
|
||||
switch (arg[1]) {
|
||||
case 'A':
|
||||
opt.post_context = num;
|
||||
@ -790,7 +1071,7 @@ int cmd_grep(int argc, const char **argv, char **envp)
|
||||
int lno = 0;
|
||||
char buf[1024];
|
||||
if (argc <= 1)
|
||||
usage(builtin_grep_usage);
|
||||
die(emsg_missing_argument, arg);
|
||||
patterns = fopen(argv[1], "r");
|
||||
if (!patterns)
|
||||
die("'%s': %s", argv[1], strerror(errno));
|
||||
@ -801,30 +1082,55 @@ int cmd_grep(int argc, const char **argv, char **envp)
|
||||
/* ignore empty line like grep does */
|
||||
if (!buf[0])
|
||||
continue;
|
||||
add_pattern(&opt, strdup(buf), argv[1], ++lno);
|
||||
add_pattern(&opt, strdup(buf), argv[1], ++lno,
|
||||
GREP_PATTERN);
|
||||
}
|
||||
fclose(patterns);
|
||||
argv++;
|
||||
argc--;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("--not", arg)) {
|
||||
add_pattern(&opt, arg, "command line", 0, GREP_NOT);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("--and", arg)) {
|
||||
add_pattern(&opt, arg, "command line", 0, GREP_AND);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("--or", arg))
|
||||
continue; /* no-op */
|
||||
if (!strcmp("(", arg)) {
|
||||
add_pattern(&opt, arg, "command line", 0, GREP_OPEN_PAREN);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(")", arg)) {
|
||||
add_pattern(&opt, arg, "command line", 0, GREP_CLOSE_PAREN);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("-e", arg)) {
|
||||
if (1 < argc) {
|
||||
add_pattern(&opt, argv[1], "-e option", 0);
|
||||
add_pattern(&opt, argv[1], "-e option", 0,
|
||||
GREP_PATTERN);
|
||||
argv++;
|
||||
argc--;
|
||||
continue;
|
||||
}
|
||||
usage(builtin_grep_usage);
|
||||
die(emsg_missing_argument, arg);
|
||||
}
|
||||
if (!strcmp("--", arg))
|
||||
if (!strcmp("--", arg)) {
|
||||
/* later processing wants to have this at argv[1] */
|
||||
argv--;
|
||||
argc++;
|
||||
break;
|
||||
}
|
||||
if (*arg == '-')
|
||||
usage(builtin_grep_usage);
|
||||
|
||||
/* First unrecognized non-option token */
|
||||
if (!opt.pattern_list) {
|
||||
add_pattern(&opt, arg, "command line", 0);
|
||||
add_pattern(&opt, arg, "command line", 0,
|
||||
GREP_PATTERN);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
|
||||
@ -9,10 +9,8 @@
|
||||
#include "exec_cmd.h"
|
||||
#include "common-cmds.h"
|
||||
|
||||
static const char git_usage[] =
|
||||
"Usage: git [--version] [--exec-path[=GIT_EXEC_PATH]] [--help] COMMAND [ ARGS ]";
|
||||
|
||||
/* most gui terms set COLUMNS (although some don't export it) */
|
||||
/* most GUI terminals set COLUMNS (although some don't export it) */
|
||||
static int term_columns(void)
|
||||
{
|
||||
char *col_string = getenv("COLUMNS");
|
||||
@ -178,31 +176,6 @@ static void list_common_cmds_help(void)
|
||||
puts("(use 'git help -a' to get a list of all installed git commands)");
|
||||
}
|
||||
|
||||
void cmd_usage(int show_all, const char *exec_path, const char *fmt, ...)
|
||||
{
|
||||
if (fmt) {
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
printf("git: ");
|
||||
vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
putchar('\n');
|
||||
}
|
||||
else
|
||||
puts(git_usage);
|
||||
|
||||
if (exec_path) {
|
||||
putchar('\n');
|
||||
if (show_all)
|
||||
list_commands(exec_path, "git-*");
|
||||
else
|
||||
list_common_cmds_help();
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void show_man_page(const char *git_cmd)
|
||||
{
|
||||
const char *page;
|
||||
@ -221,21 +194,40 @@ static void show_man_page(const char *git_cmd)
|
||||
execlp("man", "man", page, NULL);
|
||||
}
|
||||
|
||||
int cmd_version(int argc, const char **argv, char **envp)
|
||||
void help_unknown_cmd(const char *cmd)
|
||||
{
|
||||
printf("git: '%s' is not a git-command\n\n", cmd);
|
||||
list_common_cmds_help();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int cmd_version(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
printf("git version %s\n", git_version_string);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_help(int argc, const char **argv, char **envp)
|
||||
int cmd_help(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
const char *help_cmd = argv[1];
|
||||
if (!help_cmd)
|
||||
cmd_usage(0, git_exec_path(), NULL);
|
||||
else if (!strcmp(help_cmd, "--all") || !strcmp(help_cmd, "-a"))
|
||||
cmd_usage(1, git_exec_path(), NULL);
|
||||
const char *help_cmd = argc > 1 ? argv[1] : NULL;
|
||||
const char *exec_path = git_exec_path();
|
||||
|
||||
if (!help_cmd) {
|
||||
printf("usage: %s\n\n", git_usage_string);
|
||||
list_common_cmds_help();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
else if (!strcmp(help_cmd, "--all") || !strcmp(help_cmd, "-a")) {
|
||||
printf("usage: %s\n\n", git_usage_string);
|
||||
if(exec_path)
|
||||
list_commands(exec_path, "git-*");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
else
|
||||
show_man_page(help_cmd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -250,7 +250,7 @@ static const char init_db_usage[] =
|
||||
* On the other hand, it might just make lookup slower and messier. You
|
||||
* be the judge. The default case is to have one DB per managed directory.
|
||||
*/
|
||||
int cmd_init_db(int argc, const char **argv, char **envp)
|
||||
int cmd_init_db(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
const char *git_dir;
|
||||
const char *sha1_dir;
|
||||
@ -267,7 +267,7 @@ int cmd_init_db(int argc, const char **argv, char **envp)
|
||||
else if (!strncmp(arg, "--shared=", 9))
|
||||
shared_repository = git_config_perm("arg", arg+9);
|
||||
else
|
||||
die(init_db_usage);
|
||||
usage(init_db_usage);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
115
builtin-log.c
115
builtin-log.c
@ -10,32 +10,30 @@
|
||||
#include "revision.h"
|
||||
#include "log-tree.h"
|
||||
#include "builtin.h"
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
/* this is in builtin-diff.c */
|
||||
void add_head(struct rev_info *revs);
|
||||
|
||||
static int cmd_log_wc(int argc, const char **argv, char **envp,
|
||||
static void cmd_log_init(int argc, const char **argv, const char *prefix,
|
||||
struct rev_info *rev)
|
||||
{
|
||||
struct commit *commit;
|
||||
|
||||
rev->abbrev = DEFAULT_ABBREV;
|
||||
rev->commit_format = CMIT_FMT_DEFAULT;
|
||||
rev->verbose_header = 1;
|
||||
argc = setup_revisions(argc, argv, rev, "HEAD");
|
||||
if (rev->always_show_header) {
|
||||
if (rev->diffopt.pickaxe || rev->diffopt.filter) {
|
||||
rev->always_show_header = 0;
|
||||
if (rev->diffopt.output_format == DIFF_FORMAT_RAW)
|
||||
rev->diffopt.output_format = DIFF_FORMAT_NO_OUTPUT;
|
||||
}
|
||||
}
|
||||
|
||||
if (rev->diffopt.pickaxe || rev->diffopt.filter)
|
||||
rev->always_show_header = 0;
|
||||
if (argc > 1)
|
||||
die("unrecognized argument: %s", argv[1]);
|
||||
}
|
||||
|
||||
static int cmd_log_walk(struct rev_info *rev)
|
||||
{
|
||||
struct commit *commit;
|
||||
|
||||
prepare_revision_walk(rev);
|
||||
setup_pager();
|
||||
while ((commit = get_revision(rev)) != NULL) {
|
||||
log_tree_commit(rev, commit);
|
||||
free(commit->buffer);
|
||||
@ -46,22 +44,27 @@ static int cmd_log_wc(int argc, const char **argv, char **envp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_whatchanged(int argc, const char **argv, char **envp)
|
||||
int cmd_whatchanged(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct rev_info rev;
|
||||
|
||||
init_revisions(&rev);
|
||||
git_config(git_diff_ui_config);
|
||||
init_revisions(&rev, prefix);
|
||||
rev.diff = 1;
|
||||
rev.diffopt.recursive = 1;
|
||||
rev.simplify_history = 0;
|
||||
return cmd_log_wc(argc, argv, envp, &rev);
|
||||
cmd_log_init(argc, argv, prefix, &rev);
|
||||
if (!rev.diffopt.output_format)
|
||||
rev.diffopt.output_format = DIFF_FORMAT_RAW;
|
||||
return cmd_log_walk(&rev);
|
||||
}
|
||||
|
||||
int cmd_show(int argc, const char **argv, char **envp)
|
||||
int cmd_show(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct rev_info rev;
|
||||
|
||||
init_revisions(&rev);
|
||||
git_config(git_diff_ui_config);
|
||||
init_revisions(&rev, prefix);
|
||||
rev.diff = 1;
|
||||
rev.diffopt.recursive = 1;
|
||||
rev.combine_merges = 1;
|
||||
@ -69,17 +72,19 @@ int cmd_show(int argc, const char **argv, char **envp)
|
||||
rev.always_show_header = 1;
|
||||
rev.ignore_merges = 0;
|
||||
rev.no_walk = 1;
|
||||
return cmd_log_wc(argc, argv, envp, &rev);
|
||||
cmd_log_init(argc, argv, prefix, &rev);
|
||||
return cmd_log_walk(&rev);
|
||||
}
|
||||
|
||||
int cmd_log(int argc, const char **argv, char **envp)
|
||||
int cmd_log(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct rev_info rev;
|
||||
|
||||
init_revisions(&rev);
|
||||
git_config(git_diff_ui_config);
|
||||
init_revisions(&rev, prefix);
|
||||
rev.always_show_header = 1;
|
||||
rev.diffopt.recursive = 1;
|
||||
return cmd_log_wc(argc, argv, envp, &rev);
|
||||
cmd_log_init(argc, argv, prefix, &rev);
|
||||
return cmd_log_walk(&rev);
|
||||
}
|
||||
|
||||
static int istitlechar(char c)
|
||||
@ -101,7 +106,10 @@ static int git_format_config(const char *var, const char *value)
|
||||
strcat(extra_headers, value);
|
||||
return 0;
|
||||
}
|
||||
return git_default_config(var, value);
|
||||
if (!strcmp(var, "diff.color")) {
|
||||
return 0;
|
||||
}
|
||||
return git_diff_ui_config(var, value);
|
||||
}
|
||||
|
||||
|
||||
@ -169,7 +177,7 @@ static int get_patch_id(struct commit *commit, struct diff_options *options,
|
||||
return diff_flush_patch_id(options, sha1);
|
||||
}
|
||||
|
||||
static void get_patch_ids(struct rev_info *rev, struct diff_options *options)
|
||||
static void get_patch_ids(struct rev_info *rev, struct diff_options *options, const char *prefix)
|
||||
{
|
||||
struct rev_info check_rev;
|
||||
struct commit *commit;
|
||||
@ -194,7 +202,7 @@ static void get_patch_ids(struct rev_info *rev, struct diff_options *options)
|
||||
die("diff_setup_done failed");
|
||||
|
||||
/* given a range a..b get all patch ids for b..a */
|
||||
init_revisions(&check_rev);
|
||||
init_revisions(&check_rev, prefix);
|
||||
o1->flags ^= UNINTERESTING;
|
||||
o2->flags ^= UNINTERESTING;
|
||||
add_pending_object(&check_rev, o1, "o1");
|
||||
@ -219,7 +227,19 @@ static void get_patch_ids(struct rev_info *rev, struct diff_options *options)
|
||||
o2->flags = flags2;
|
||||
}
|
||||
|
||||
int cmd_format_patch(int argc, const char **argv, char **envp)
|
||||
static void gen_message_id(char *dest, unsigned int length, char *base)
|
||||
{
|
||||
const char *committer = git_committer_info(1);
|
||||
const char *email_start = strrchr(committer, '<');
|
||||
const char *email_end = strrchr(committer, '>');
|
||||
if(!email_start || !email_end || email_start > email_end - 1)
|
||||
die("Could not extract email from committer identity.");
|
||||
snprintf(dest, length, "%s.%lu.git.%.*s", base,
|
||||
(unsigned long) time(NULL),
|
||||
(int)(email_end - email_start - 1), email_start + 1);
|
||||
}
|
||||
|
||||
int cmd_format_patch(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct commit *commit;
|
||||
struct commit **list = NULL;
|
||||
@ -230,20 +250,24 @@ int cmd_format_patch(int argc, const char **argv, char **envp)
|
||||
int start_number = -1;
|
||||
int keep_subject = 0;
|
||||
int ignore_if_in_upstream = 0;
|
||||
int thread = 0;
|
||||
const char *in_reply_to = NULL;
|
||||
struct diff_options patch_id_opts;
|
||||
char *add_signoff = NULL;
|
||||
char message_id[1024];
|
||||
char ref_message_id[1024];
|
||||
|
||||
init_revisions(&rev);
|
||||
setup_ident();
|
||||
git_config(git_format_config);
|
||||
init_revisions(&rev, prefix);
|
||||
rev.commit_format = CMIT_FMT_EMAIL;
|
||||
rev.verbose_header = 1;
|
||||
rev.diff = 1;
|
||||
rev.diffopt.with_raw = 0;
|
||||
rev.diffopt.with_stat = 1;
|
||||
rev.combine_merges = 0;
|
||||
rev.ignore_merges = 1;
|
||||
rev.diffopt.output_format = DIFF_FORMAT_PATCH;
|
||||
rev.diffopt.msg_sep = "";
|
||||
rev.diffopt.recursive = 1;
|
||||
|
||||
git_config(git_format_config);
|
||||
rev.extra_headers = extra_headers;
|
||||
|
||||
/*
|
||||
@ -283,7 +307,6 @@ int cmd_format_patch(int argc, const char **argv, char **envp)
|
||||
!strcmp(argv[i], "-s")) {
|
||||
const char *committer;
|
||||
const char *endpos;
|
||||
setup_ident();
|
||||
committer = git_committer_info(1);
|
||||
endpos = strchr(committer, '>');
|
||||
if (!endpos)
|
||||
@ -298,6 +321,16 @@ int cmd_format_patch(int argc, const char **argv, char **envp)
|
||||
rev.mime_boundary = argv[i] + 9;
|
||||
else if (!strcmp(argv[i], "--ignore-if-in-upstream"))
|
||||
ignore_if_in_upstream = 1;
|
||||
else if (!strcmp(argv[i], "--thread"))
|
||||
thread = 1;
|
||||
else if (!strncmp(argv[i], "--in-reply-to=", 14))
|
||||
in_reply_to = argv[i] + 14;
|
||||
else if (!strcmp(argv[i], "--in-reply-to")) {
|
||||
i++;
|
||||
if (i == argc)
|
||||
die("Need a Message-Id for --in-reply-to");
|
||||
in_reply_to = argv[i];
|
||||
}
|
||||
else
|
||||
argv[j++] = argv[i];
|
||||
}
|
||||
@ -312,6 +345,9 @@ int cmd_format_patch(int argc, const char **argv, char **envp)
|
||||
if (argc > 1)
|
||||
die ("unrecognized argument: %s", argv[1]);
|
||||
|
||||
if (!rev.diffopt.output_format)
|
||||
rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_PATCH;
|
||||
|
||||
if (output_directory) {
|
||||
if (use_stdout)
|
||||
die("standard output, or directory, which one?");
|
||||
@ -326,7 +362,7 @@ int cmd_format_patch(int argc, const char **argv, char **envp)
|
||||
}
|
||||
|
||||
if (ignore_if_in_upstream)
|
||||
get_patch_ids(&rev, &patch_id_opts);
|
||||
get_patch_ids(&rev, &patch_id_opts, prefix);
|
||||
|
||||
if (!use_stdout)
|
||||
realstdout = fdopen(dup(1), "w");
|
||||
@ -352,10 +388,23 @@ int cmd_format_patch(int argc, const char **argv, char **envp)
|
||||
if (numbered)
|
||||
rev.total = total + start_number - 1;
|
||||
rev.add_signoff = add_signoff;
|
||||
rev.ref_message_id = in_reply_to;
|
||||
while (0 <= --nr) {
|
||||
int shown;
|
||||
commit = list[nr];
|
||||
rev.nr = total - nr + (start_number - 1);
|
||||
/* Make the second and subsequent mails replies to the first */
|
||||
if (thread) {
|
||||
if (nr == (total - 2)) {
|
||||
strncpy(ref_message_id, message_id,
|
||||
sizeof(ref_message_id));
|
||||
ref_message_id[sizeof(ref_message_id)-1]='\0';
|
||||
rev.ref_message_id = ref_message_id;
|
||||
}
|
||||
gen_message_id(message_id, sizeof(message_id),
|
||||
sha1_to_hex(commit->object.sha1));
|
||||
rev.message_id = message_id;
|
||||
}
|
||||
if (!use_stdout)
|
||||
reopen_stdout(commit, rev.nr, keep_subject);
|
||||
shown = log_tree_commit(&rev, commit);
|
||||
|
||||
@ -24,7 +24,6 @@ static int show_valid_bit = 0;
|
||||
static int line_terminator = '\n';
|
||||
|
||||
static int prefix_len = 0, prefix_offset = 0;
|
||||
static const char *prefix = NULL;
|
||||
static const char **pathspec = NULL;
|
||||
static int error_unmatch = 0;
|
||||
static char *ps_matched = NULL;
|
||||
@ -207,7 +206,7 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce)
|
||||
}
|
||||
}
|
||||
|
||||
static void show_files(struct dir_struct *dir)
|
||||
static void show_files(struct dir_struct *dir, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -253,7 +252,7 @@ static void show_files(struct dir_struct *dir)
|
||||
/*
|
||||
* Prune the index to only contain stuff starting with "prefix"
|
||||
*/
|
||||
static void prune_cache(void)
|
||||
static void prune_cache(const char *prefix)
|
||||
{
|
||||
int pos = cache_name_pos(prefix, prefix_len);
|
||||
unsigned int first, last;
|
||||
@ -276,7 +275,7 @@ static void prune_cache(void)
|
||||
active_nr = last;
|
||||
}
|
||||
|
||||
static void verify_pathspec(void)
|
||||
static const char *verify_pathspec(const char *prefix)
|
||||
{
|
||||
const char **p, *n, *prev;
|
||||
char *real_prefix;
|
||||
@ -313,7 +312,7 @@ static void verify_pathspec(void)
|
||||
memcpy(real_prefix, prev, max);
|
||||
real_prefix[max] = 0;
|
||||
}
|
||||
prefix = real_prefix;
|
||||
return real_prefix;
|
||||
}
|
||||
|
||||
static const char ls_files_usage[] =
|
||||
@ -322,14 +321,13 @@ static const char ls_files_usage[] =
|
||||
"[ --exclude-per-directory=<filename> ] [--full-name] [--abbrev] "
|
||||
"[--] [<file>]*";
|
||||
|
||||
int cmd_ls_files(int argc, const char **argv, char** envp)
|
||||
int cmd_ls_files(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
int exc_given = 0;
|
||||
struct dir_struct dir;
|
||||
|
||||
memset(&dir, 0, sizeof(dir));
|
||||
prefix = setup_git_directory();
|
||||
if (prefix)
|
||||
prefix_offset = strlen(prefix);
|
||||
git_config(git_default_config);
|
||||
@ -454,7 +452,7 @@ int cmd_ls_files(int argc, const char **argv, char** envp)
|
||||
|
||||
/* Verify that the pathspec matches the prefix */
|
||||
if (pathspec)
|
||||
verify_pathspec();
|
||||
prefix = verify_pathspec(prefix);
|
||||
|
||||
/* Treat unmatching pathspec elements as errors */
|
||||
if (pathspec && error_unmatch) {
|
||||
@ -477,8 +475,8 @@ int cmd_ls_files(int argc, const char **argv, char** envp)
|
||||
|
||||
read_cache();
|
||||
if (prefix)
|
||||
prune_cache();
|
||||
show_files(&dir);
|
||||
prune_cache(prefix);
|
||||
show_files(&dir, prefix);
|
||||
|
||||
if (ps_matched) {
|
||||
/* We need to make sure all pathspec matched otherwise
|
||||
|
||||
@ -18,7 +18,7 @@ static int abbrev = 0;
|
||||
static int ls_options = 0;
|
||||
static const char **pathspec;
|
||||
static int chomp_prefix = 0;
|
||||
static const char *prefix;
|
||||
static const char *ls_tree_prefix;
|
||||
|
||||
static const char ls_tree_usage[] =
|
||||
"git-ls-tree [-d] [-r] [-t] [-z] [--name-only] [--name-status] [--full-name] [--abbrev[=<n>]] <tree-ish> [path...]";
|
||||
@ -71,7 +71,7 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,
|
||||
return 0;
|
||||
|
||||
if (chomp_prefix &&
|
||||
(baselen < chomp_prefix || memcmp(prefix, base, chomp_prefix)))
|
||||
(baselen < chomp_prefix || memcmp(ls_tree_prefix, base, chomp_prefix)))
|
||||
return 0;
|
||||
|
||||
if (!(ls_options & LS_NAME_ONLY))
|
||||
@ -85,13 +85,13 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,
|
||||
return retval;
|
||||
}
|
||||
|
||||
int cmd_ls_tree(int argc, const char **argv, char **envp)
|
||||
int cmd_ls_tree(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
struct tree *tree;
|
||||
|
||||
prefix = setup_git_directory();
|
||||
git_config(git_default_config);
|
||||
ls_tree_prefix = prefix;
|
||||
if (prefix && *prefix)
|
||||
chomp_prefix = strlen(prefix);
|
||||
while (1 < argc && argv[1][0] == '-') {
|
||||
|
||||
@ -348,7 +348,7 @@ static void cleanup_space(char *buf)
|
||||
}
|
||||
}
|
||||
|
||||
static void decode_header_bq(char *it);
|
||||
static void decode_header(char *it);
|
||||
typedef int (*header_fn_t)(char *);
|
||||
struct header_def {
|
||||
const char *name;
|
||||
@ -371,7 +371,7 @@ static void check_header(char *line, struct header_def *header)
|
||||
/* Unwrap inline B and Q encoding, and optionally
|
||||
* normalize the meta information to utf8.
|
||||
*/
|
||||
decode_header_bq(line + len + 2);
|
||||
decode_header(line + len + 2);
|
||||
header[i].func(line + len + 2);
|
||||
break;
|
||||
}
|
||||
@ -446,7 +446,7 @@ static int read_one_header_line(char *line, int sz, FILE *in)
|
||||
break;
|
||||
}
|
||||
/* Count mbox From headers as headers */
|
||||
if (!ofs && !memcmp(line, "From ", 5))
|
||||
if (!ofs && (!memcmp(line, "From ", 5) || !memcmp(line, ">From ", 6)))
|
||||
ofs = 1;
|
||||
return ofs;
|
||||
}
|
||||
@ -566,16 +566,19 @@ static void convert_to_utf8(char *line, char *charset)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void decode_header_bq(char *it)
|
||||
static int decode_header_bq(char *it)
|
||||
{
|
||||
char *in, *out, *ep, *cp, *sp;
|
||||
char outbuf[1000];
|
||||
int rfc2047 = 0;
|
||||
|
||||
in = it;
|
||||
out = outbuf;
|
||||
while ((ep = strstr(in, "=?")) != NULL) {
|
||||
int sz, encoding;
|
||||
char charset_q[256], piecebuf[256];
|
||||
rfc2047 = 1;
|
||||
|
||||
if (in != ep) {
|
||||
sz = ep - in;
|
||||
memcpy(out, in, sz);
|
||||
@ -589,19 +592,19 @@ static void decode_header_bq(char *it)
|
||||
ep += 2;
|
||||
cp = strchr(ep, '?');
|
||||
if (!cp)
|
||||
return; /* no munging */
|
||||
return rfc2047; /* no munging */
|
||||
for (sp = ep; sp < cp; sp++)
|
||||
charset_q[sp - ep] = tolower(*sp);
|
||||
charset_q[cp - ep] = 0;
|
||||
encoding = cp[1];
|
||||
if (!encoding || cp[2] != '?')
|
||||
return; /* no munging */
|
||||
return rfc2047; /* no munging */
|
||||
ep = strstr(cp + 3, "?=");
|
||||
if (!ep)
|
||||
return; /* no munging */
|
||||
return rfc2047; /* no munging */
|
||||
switch (tolower(encoding)) {
|
||||
default:
|
||||
return; /* no munging */
|
||||
return rfc2047; /* no munging */
|
||||
case 'b':
|
||||
sz = decode_b_segment(cp + 3, piecebuf, ep);
|
||||
break;
|
||||
@ -610,7 +613,7 @@ static void decode_header_bq(char *it)
|
||||
break;
|
||||
}
|
||||
if (sz < 0)
|
||||
return;
|
||||
return rfc2047;
|
||||
if (metainfo_charset)
|
||||
convert_to_utf8(piecebuf, charset_q);
|
||||
strcpy(out, piecebuf);
|
||||
@ -619,6 +622,19 @@ static void decode_header_bq(char *it)
|
||||
}
|
||||
strcpy(out, in);
|
||||
strcpy(it, outbuf);
|
||||
return rfc2047;
|
||||
}
|
||||
|
||||
static void decode_header(char *it)
|
||||
{
|
||||
|
||||
if (decode_header_bq(it))
|
||||
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, "");
|
||||
}
|
||||
|
||||
static void decode_transfer_encoding(char *line)
|
||||
@ -820,7 +836,7 @@ int mailinfo(FILE *in, FILE *out, int ks, const char *encoding,
|
||||
static const char mailinfo_usage[] =
|
||||
"git-mailinfo [-k] [-u | --encoding=<encoding>] msg patch <mail >info";
|
||||
|
||||
int cmd_mailinfo(int argc, const char **argv, char **envp)
|
||||
int cmd_mailinfo(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
/* NEEDSWORK: might want to do the optional .git/ directory
|
||||
* discovery
|
||||
|
||||
@ -138,7 +138,7 @@ out:
|
||||
free(name);
|
||||
return ret;
|
||||
}
|
||||
int cmd_mailsplit(int argc, const char **argv, char **envp)
|
||||
int cmd_mailsplit(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int nr = 0, nr_prec = 4, ret;
|
||||
int allow_bare = 0;
|
||||
|
||||
297
builtin-mv.c
Normal file
297
builtin-mv.c
Normal file
@ -0,0 +1,297 @@
|
||||
/*
|
||||
* "git mv" builtin command
|
||||
*
|
||||
* Copyright (C) 2006 Johannes Schindelin
|
||||
*/
|
||||
#include <fnmatch.h>
|
||||
|
||||
#include "cache.h"
|
||||
#include "builtin.h"
|
||||
#include "dir.h"
|
||||
#include "cache-tree.h"
|
||||
#include "path-list.h"
|
||||
|
||||
static const char builtin_mv_usage[] =
|
||||
"git-mv [-n] [-f] (<source> <destination> | [-k] <source>... <destination>)";
|
||||
|
||||
static const char **copy_pathspec(const char *prefix, const char **pathspec,
|
||||
int count, int base_name)
|
||||
{
|
||||
const char **result = xmalloc((count + 1) * sizeof(const char *));
|
||||
memcpy(result, pathspec, count * sizeof(const char *));
|
||||
result[count] = NULL;
|
||||
if (base_name) {
|
||||
int i;
|
||||
for (i = 0; i < count; i++) {
|
||||
const char *last_slash = strrchr(result[i], '/');
|
||||
if (last_slash)
|
||||
result[i] = last_slash + 1;
|
||||
}
|
||||
}
|
||||
return get_pathspec(prefix, result);
|
||||
}
|
||||
|
||||
static void show_list(const char *label, struct path_list *list)
|
||||
{
|
||||
if (list->nr > 0) {
|
||||
int i;
|
||||
printf("%s", label);
|
||||
for (i = 0; i < list->nr; i++)
|
||||
printf("%s%s", i > 0 ? ", " : "", list->items[i].path);
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
static const char *add_slash(const char *path)
|
||||
{
|
||||
int len = strlen(path);
|
||||
if (path[len - 1] != '/') {
|
||||
char *with_slash = xmalloc(len + 2);
|
||||
memcpy(with_slash, path, len);
|
||||
strcat(with_slash + len, "/");
|
||||
return with_slash;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
static struct lock_file lock_file;
|
||||
|
||||
int cmd_mv(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i, newfd, count;
|
||||
int verbose = 0, show_only = 0, force = 0, ignore_errors = 0;
|
||||
const char **source, **destination, **dest_path;
|
||||
enum update_mode { BOTH = 0, WORKING_DIRECTORY, INDEX } *modes;
|
||||
struct stat st;
|
||||
struct path_list overwritten = {NULL, 0, 0, 0};
|
||||
struct path_list src_for_dst = {NULL, 0, 0, 0};
|
||||
struct path_list added = {NULL, 0, 0, 0};
|
||||
struct path_list deleted = {NULL, 0, 0, 0};
|
||||
struct path_list changed = {NULL, 0, 0, 0};
|
||||
|
||||
git_config(git_default_config);
|
||||
|
||||
newfd = hold_lock_file_for_update(&lock_file, get_index_file());
|
||||
if (newfd < 0)
|
||||
die("unable to create new index file");
|
||||
|
||||
if (read_cache() < 0)
|
||||
die("index file corrupt");
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
|
||||
if (arg[0] != '-')
|
||||
break;
|
||||
if (!strcmp(arg, "--")) {
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
if (!strcmp(arg, "-n")) {
|
||||
show_only = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-f")) {
|
||||
force = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-k")) {
|
||||
ignore_errors = 1;
|
||||
continue;
|
||||
}
|
||||
usage(builtin_mv_usage);
|
||||
}
|
||||
count = argc - i - 1;
|
||||
if (count < 1)
|
||||
usage(builtin_mv_usage);
|
||||
|
||||
source = copy_pathspec(prefix, argv + i, count, 0);
|
||||
modes = xcalloc(count, sizeof(enum update_mode));
|
||||
dest_path = copy_pathspec(prefix, argv + argc - 1, 1, 0);
|
||||
|
||||
if (!lstat(dest_path[0], &st) &&
|
||||
S_ISDIR(st.st_mode)) {
|
||||
dest_path[0] = add_slash(dest_path[0]);
|
||||
destination = copy_pathspec(dest_path[0], argv + i, count, 1);
|
||||
} else {
|
||||
if (count != 1)
|
||||
usage(builtin_mv_usage);
|
||||
destination = dest_path;
|
||||
}
|
||||
|
||||
/* Checking */
|
||||
for (i = 0; i < count; i++) {
|
||||
const char *bad = NULL;
|
||||
|
||||
if (show_only)
|
||||
printf("Checking rename of '%s' to '%s'\n",
|
||||
source[i], destination[i]);
|
||||
|
||||
if (lstat(source[i], &st) < 0)
|
||||
bad = "bad source";
|
||||
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
const char *dir = source[i], *dest_dir = destination[i];
|
||||
int first, last, len = strlen(dir);
|
||||
|
||||
if (lstat(dest_dir, &st) == 0) {
|
||||
bad = "cannot move directory over file";
|
||||
goto next;
|
||||
}
|
||||
|
||||
modes[i] = WORKING_DIRECTORY;
|
||||
|
||||
first = cache_name_pos(source[i], len);
|
||||
if (first >= 0)
|
||||
die ("Huh? %s/ is in index?", dir);
|
||||
|
||||
first = -1 - first;
|
||||
for (last = first; last < active_nr; last++) {
|
||||
const char *path = active_cache[last]->name;
|
||||
if (strncmp(path, dir, len) || path[len] != '/')
|
||||
break;
|
||||
}
|
||||
|
||||
if (last - first < 1)
|
||||
bad = "source directory is empty";
|
||||
else if (!bad) {
|
||||
int j, dst_len = strlen(dest_dir);
|
||||
|
||||
if (last - first > 0) {
|
||||
source = realloc(source,
|
||||
(count + last - first)
|
||||
* sizeof(char *));
|
||||
destination = realloc(destination,
|
||||
(count + last - first)
|
||||
* sizeof(char *));
|
||||
modes = realloc(modes,
|
||||
(count + last - first)
|
||||
* sizeof(enum update_mode));
|
||||
}
|
||||
|
||||
dest_dir = add_slash(dest_dir);
|
||||
|
||||
for (j = 0; j < last - first; j++) {
|
||||
const char *path =
|
||||
active_cache[first + j]->name;
|
||||
source[count + j] = path;
|
||||
destination[count + j] =
|
||||
prefix_path(dest_dir, dst_len,
|
||||
path + len);
|
||||
modes[count + j] = INDEX;
|
||||
}
|
||||
count += last - first;
|
||||
}
|
||||
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (!bad && lstat(destination[i], &st) == 0) {
|
||||
bad = "destination exists";
|
||||
if (force) {
|
||||
/*
|
||||
* only files can overwrite each other:
|
||||
* check both source and destination
|
||||
*/
|
||||
if (S_ISREG(st.st_mode)) {
|
||||
fprintf(stderr, "Warning: %s;"
|
||||
" will overwrite!\n",
|
||||
bad);
|
||||
bad = NULL;
|
||||
path_list_insert(destination[i],
|
||||
&overwritten);
|
||||
} else
|
||||
bad = "Cannot overwrite";
|
||||
}
|
||||
}
|
||||
|
||||
if (!bad &&
|
||||
!strncmp(destination[i], source[i], strlen(source[i])))
|
||||
bad = "can not move directory into itself";
|
||||
|
||||
if (!bad && cache_name_pos(source[i], strlen(source[i])) < 0)
|
||||
bad = "not under version control";
|
||||
|
||||
if (!bad) {
|
||||
if (path_list_has_path(&src_for_dst, destination[i]))
|
||||
bad = "multiple sources for the same target";
|
||||
else
|
||||
path_list_insert(destination[i], &src_for_dst);
|
||||
}
|
||||
|
||||
next:
|
||||
if (bad) {
|
||||
if (ignore_errors) {
|
||||
if (--count > 0) {
|
||||
memmove(source + i, source + i + 1,
|
||||
(count - i) * sizeof(char *));
|
||||
memmove(destination + i,
|
||||
destination + i + 1,
|
||||
(count - i) * sizeof(char *));
|
||||
}
|
||||
} else
|
||||
die ("%s, source=%s, destination=%s",
|
||||
bad, source[i], destination[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (show_only || verbose)
|
||||
printf("Renaming %s to %s\n",
|
||||
source[i], destination[i]);
|
||||
if (!show_only && modes[i] != INDEX &&
|
||||
rename(source[i], destination[i]) < 0 &&
|
||||
!ignore_errors)
|
||||
die ("renaming %s failed: %s",
|
||||
source[i], strerror(errno));
|
||||
|
||||
if (modes[i] == WORKING_DIRECTORY)
|
||||
continue;
|
||||
|
||||
if (cache_name_pos(source[i], strlen(source[i])) >= 0) {
|
||||
path_list_insert(source[i], &deleted);
|
||||
|
||||
/* destination can be a directory with 1 file inside */
|
||||
if (path_list_has_path(&overwritten, destination[i]))
|
||||
path_list_insert(destination[i], &changed);
|
||||
else
|
||||
path_list_insert(destination[i], &added);
|
||||
} else
|
||||
path_list_insert(destination[i], &added);
|
||||
}
|
||||
|
||||
if (show_only) {
|
||||
show_list("Changed : ", &changed);
|
||||
show_list("Adding : ", &added);
|
||||
show_list("Deleting : ", &deleted);
|
||||
} else {
|
||||
for (i = 0; i < changed.nr; i++) {
|
||||
const char *path = changed.items[i].path;
|
||||
int i = cache_name_pos(path, strlen(path));
|
||||
struct cache_entry *ce = active_cache[i];
|
||||
|
||||
if (i < 0)
|
||||
die ("Huh? Cache entry for %s unknown?", path);
|
||||
refresh_cache_entry(ce, 0);
|
||||
}
|
||||
|
||||
for (i = 0; i < added.nr; i++) {
|
||||
const char *path = added.items[i].path;
|
||||
add_file_to_index(path, verbose);
|
||||
}
|
||||
|
||||
for (i = 0; i < deleted.nr; i++) {
|
||||
const char *path = deleted.items[i].path;
|
||||
remove_file_from_cache(path);
|
||||
}
|
||||
|
||||
if (active_cache_changed) {
|
||||
if (write_cache(newfd, active_cache, active_nr) ||
|
||||
close(newfd) ||
|
||||
commit_lock_file(&lock_file))
|
||||
die("Unable to write new index file");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
|
||||
static const char prune_packed_usage[] =
|
||||
@ -54,12 +55,10 @@ static void prune_packed_objects(void)
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
int cmd_prune_packed(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
|
||||
setup_git_directory();
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
|
||||
259
builtin-prune.c
Normal file
259
builtin-prune.c
Normal file
@ -0,0 +1,259 @@
|
||||
#include "cache.h"
|
||||
#include "refs.h"
|
||||
#include "tag.h"
|
||||
#include "commit.h"
|
||||
#include "tree.h"
|
||||
#include "blob.h"
|
||||
#include "tree-walk.h"
|
||||
#include "diff.h"
|
||||
#include "revision.h"
|
||||
#include "builtin.h"
|
||||
#include "cache-tree.h"
|
||||
|
||||
static const char prune_usage[] = "git-prune [-n]";
|
||||
static int show_only = 0;
|
||||
static struct rev_info revs;
|
||||
|
||||
static int prune_object(char *path, const char *filename, const unsigned char *sha1)
|
||||
{
|
||||
if (show_only) {
|
||||
printf("would prune %s/%s\n", path, filename);
|
||||
return 0;
|
||||
}
|
||||
unlink(mkpath("%s/%s", path, filename));
|
||||
rmdir(path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int prune_dir(int i, char *path)
|
||||
{
|
||||
DIR *dir = opendir(path);
|
||||
struct dirent *de;
|
||||
|
||||
if (!dir)
|
||||
return 0;
|
||||
|
||||
while ((de = readdir(dir)) != NULL) {
|
||||
char name[100];
|
||||
unsigned char sha1[20];
|
||||
int len = strlen(de->d_name);
|
||||
|
||||
switch (len) {
|
||||
case 2:
|
||||
if (de->d_name[1] != '.')
|
||||
break;
|
||||
case 1:
|
||||
if (de->d_name[0] != '.')
|
||||
break;
|
||||
continue;
|
||||
case 38:
|
||||
sprintf(name, "%02x", i);
|
||||
memcpy(name+2, de->d_name, len+1);
|
||||
if (get_sha1_hex(name, sha1) < 0)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Do we know about this object?
|
||||
* It must have been reachable
|
||||
*/
|
||||
if (lookup_object(sha1))
|
||||
continue;
|
||||
|
||||
prune_object(path, de->d_name, sha1);
|
||||
continue;
|
||||
}
|
||||
fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
|
||||
}
|
||||
closedir(dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void prune_object_dir(const char *path)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 256; i++) {
|
||||
static char dir[4096];
|
||||
sprintf(dir, "%s/%02x", path, i);
|
||||
prune_dir(i, dir);
|
||||
}
|
||||
}
|
||||
|
||||
static void process_blob(struct blob *blob,
|
||||
struct object_array *p,
|
||||
struct name_path *path,
|
||||
const char *name)
|
||||
{
|
||||
struct object *obj = &blob->object;
|
||||
|
||||
if (obj->flags & SEEN)
|
||||
return;
|
||||
obj->flags |= SEEN;
|
||||
/* Nothing to do, really .. The blob lookup was the important part */
|
||||
}
|
||||
|
||||
static void process_tree(struct tree *tree,
|
||||
struct object_array *p,
|
||||
struct name_path *path,
|
||||
const char *name)
|
||||
{
|
||||
struct object *obj = &tree->object;
|
||||
struct tree_desc desc;
|
||||
struct name_entry entry;
|
||||
struct name_path me;
|
||||
|
||||
if (obj->flags & SEEN)
|
||||
return;
|
||||
obj->flags |= SEEN;
|
||||
if (parse_tree(tree) < 0)
|
||||
die("bad tree object %s", sha1_to_hex(obj->sha1));
|
||||
name = strdup(name);
|
||||
add_object(obj, p, path, name);
|
||||
me.up = path;
|
||||
me.elem = name;
|
||||
me.elem_len = strlen(name);
|
||||
|
||||
desc.buf = tree->buffer;
|
||||
desc.size = tree->size;
|
||||
|
||||
while (tree_entry(&desc, &entry)) {
|
||||
if (S_ISDIR(entry.mode))
|
||||
process_tree(lookup_tree(entry.sha1), p, &me, entry.path);
|
||||
else
|
||||
process_blob(lookup_blob(entry.sha1), p, &me, entry.path);
|
||||
}
|
||||
free(tree->buffer);
|
||||
tree->buffer = NULL;
|
||||
}
|
||||
|
||||
static void process_tag(struct tag *tag, struct object_array *p, const char *name)
|
||||
{
|
||||
struct object *obj = &tag->object;
|
||||
struct name_path me;
|
||||
|
||||
if (obj->flags & SEEN)
|
||||
return;
|
||||
obj->flags |= SEEN;
|
||||
|
||||
me.up = NULL;
|
||||
me.elem = "tag:/";
|
||||
me.elem_len = 5;
|
||||
|
||||
if (parse_tag(tag) < 0)
|
||||
die("bad tag object %s", sha1_to_hex(obj->sha1));
|
||||
add_object(tag->tagged, p, NULL, name);
|
||||
}
|
||||
|
||||
static void walk_commit_list(struct rev_info *revs)
|
||||
{
|
||||
int i;
|
||||
struct commit *commit;
|
||||
struct object_array objects = { 0, 0, NULL };
|
||||
|
||||
/* Walk all commits, process their trees */
|
||||
while ((commit = get_revision(revs)) != NULL)
|
||||
process_tree(commit->tree, &objects, NULL, "");
|
||||
|
||||
/* Then walk all the pending objects, recursively processing them too */
|
||||
for (i = 0; i < revs->pending.nr; i++) {
|
||||
struct object_array_entry *pending = revs->pending.objects + i;
|
||||
struct object *obj = pending->item;
|
||||
const char *name = pending->name;
|
||||
if (obj->type == OBJ_TAG) {
|
||||
process_tag((struct tag *) obj, &objects, name);
|
||||
continue;
|
||||
}
|
||||
if (obj->type == OBJ_TREE) {
|
||||
process_tree((struct tree *)obj, &objects, NULL, name);
|
||||
continue;
|
||||
}
|
||||
if (obj->type == OBJ_BLOB) {
|
||||
process_blob((struct blob *)obj, &objects, NULL, name);
|
||||
continue;
|
||||
}
|
||||
die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name);
|
||||
}
|
||||
}
|
||||
|
||||
static int add_one_ref(const char *path, const unsigned char *sha1)
|
||||
{
|
||||
struct object *object = parse_object(sha1);
|
||||
if (!object)
|
||||
die("bad object ref: %s:%s", path, sha1_to_hex(sha1));
|
||||
add_pending_object(&revs, object, "");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void add_one_tree(const unsigned char *sha1)
|
||||
{
|
||||
struct tree *tree = lookup_tree(sha1);
|
||||
add_pending_object(&revs, &tree->object, "");
|
||||
}
|
||||
|
||||
static void add_cache_tree(struct cache_tree *it)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (it->entry_count >= 0)
|
||||
add_one_tree(it->sha1);
|
||||
for (i = 0; i < it->subtree_nr; i++)
|
||||
add_cache_tree(it->down[i]->cache_tree);
|
||||
}
|
||||
|
||||
static void add_cache_refs(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
read_cache();
|
||||
for (i = 0; i < active_nr; i++) {
|
||||
lookup_blob(active_cache[i]->sha1);
|
||||
/*
|
||||
* We could add the blobs to the pending list, but quite
|
||||
* frankly, we don't care. Once we've looked them up, and
|
||||
* added them as objects, we've really done everything
|
||||
* there is to do for a blob
|
||||
*/
|
||||
}
|
||||
if (active_cache_tree)
|
||||
add_cache_tree(active_cache_tree);
|
||||
}
|
||||
|
||||
int cmd_prune(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
if (!strcmp(arg, "-n")) {
|
||||
show_only = 1;
|
||||
continue;
|
||||
}
|
||||
usage(prune_usage);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up revision parsing, and mark us as being interested
|
||||
* in all object types, not just commits.
|
||||
*/
|
||||
init_revisions(&revs, prefix);
|
||||
revs.tag_objects = 1;
|
||||
revs.blob_objects = 1;
|
||||
revs.tree_objects = 1;
|
||||
|
||||
/* Add all external refs */
|
||||
for_each_ref(add_one_ref);
|
||||
|
||||
/* Add all refs from the index file */
|
||||
add_cache_refs();
|
||||
|
||||
/*
|
||||
* Set up the revision walk - this will move all commits
|
||||
* from the pending list to the commit walking list.
|
||||
*/
|
||||
prepare_revision_walk(&revs);
|
||||
|
||||
walk_commit_list(&revs);
|
||||
|
||||
prune_object_dir(get_object_directory());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -8,7 +8,7 @@
|
||||
|
||||
#define MAX_URI (16)
|
||||
|
||||
static const char push_usage[] = "git push [--all] [--tags] [--force] <repository> [<refspec>...]";
|
||||
static const char push_usage[] = "git-push [--all] [--tags] [-f | --force] <repository> [<refspec>...]";
|
||||
|
||||
static int all = 0, tags = 0, force = 0, thin = 1;
|
||||
static const char *execute = NULL;
|
||||
@ -104,7 +104,7 @@ static int get_remotes_uri(const char *repo, const char *uri[MAX_URI])
|
||||
if (n < MAX_URI)
|
||||
uri[n++] = strdup(s);
|
||||
else
|
||||
error("more than %d URL's specified, ignoreing the rest", MAX_URI);
|
||||
error("more than %d URL's specified, ignoring the rest", MAX_URI);
|
||||
}
|
||||
else if (is_refspec && !has_explicit_refspec)
|
||||
add_refspec(strdup(s));
|
||||
@ -270,10 +270,10 @@ static int do_push(const char *repo)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_push(int argc, const char **argv, char **envp)
|
||||
int cmd_push(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
const char *repo = "origin"; // default repository
|
||||
const char *repo = "origin"; /* default repository */
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
@ -291,7 +291,7 @@ int cmd_push(int argc, const char **argv, char **envp)
|
||||
tags = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--force")) {
|
||||
if (!strcmp(arg, "--force") || !strcmp(arg, "-f")) {
|
||||
force = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -43,10 +43,7 @@ struct tree_entry_list {
|
||||
const unsigned char *sha1;
|
||||
};
|
||||
|
||||
static struct tree_entry_list df_conflict_list = {
|
||||
.name = NULL,
|
||||
.next = &df_conflict_list
|
||||
};
|
||||
static struct tree_entry_list df_conflict_list;
|
||||
|
||||
typedef int (*merge_fn_t)(struct cache_entry **src);
|
||||
|
||||
@ -333,14 +330,9 @@ static void setup_progress_signal(void)
|
||||
setitimer(ITIMER_REAL, &v, NULL);
|
||||
}
|
||||
|
||||
static struct checkout state;
|
||||
static void check_updates(struct cache_entry **src, int nr)
|
||||
{
|
||||
static struct checkout state = {
|
||||
.base_dir = "",
|
||||
.force = 1,
|
||||
.quiet = 1,
|
||||
.refresh_cache = 1,
|
||||
};
|
||||
unsigned short mask = htons(CE_UPDATE);
|
||||
unsigned last_percent = 200, cnt = 0, total = 0;
|
||||
|
||||
@ -515,7 +507,7 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old)
|
||||
}
|
||||
|
||||
merge->ce_flags &= ~htons(CE_STAGEMASK);
|
||||
add_cache_entry(merge, ADD_CACHE_OK_TO_ADD);
|
||||
add_cache_entry(merge, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -526,7 +518,7 @@ static int deleted_entry(struct cache_entry *ce, struct cache_entry *old)
|
||||
else
|
||||
verify_absent(ce->name, "removed");
|
||||
ce->ce_mode = 0;
|
||||
add_cache_entry(ce, ADD_CACHE_OK_TO_ADD);
|
||||
add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
|
||||
invalidate_ce_path(ce);
|
||||
return 1;
|
||||
}
|
||||
@ -878,13 +870,18 @@ static const char read_tree_usage[] = "git-read-tree (<sha> | [[-m [--aggressive
|
||||
|
||||
static struct lock_file lock_file;
|
||||
|
||||
int cmd_read_tree(int argc, const char **argv, char **envp)
|
||||
int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
|
||||
{
|
||||
int i, newfd, stage = 0;
|
||||
unsigned char sha1[20];
|
||||
merge_fn_t fn = NULL;
|
||||
|
||||
setup_git_directory();
|
||||
df_conflict_list.next = &df_conflict_list;
|
||||
state.base_dir = "";
|
||||
state.force = 1;
|
||||
state.quiet = 1;
|
||||
state.refresh_cache = 1;
|
||||
|
||||
git_config(git_default_config);
|
||||
|
||||
newfd = hold_lock_file_for_update(&lock_file, get_index_file());
|
||||
@ -1038,7 +1035,7 @@ int cmd_read_tree(int argc, const char **argv, char **envp)
|
||||
}
|
||||
|
||||
if (write_cache(newfd, active_cache, active_nr) ||
|
||||
commit_lock_file(&lock_file))
|
||||
close(newfd) || commit_lock_file(&lock_file))
|
||||
die("unable to write new index file");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
#include <regex.h>
|
||||
|
||||
@ -128,7 +129,7 @@ free_strings:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
int cmd_repo_config(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int nongit = 0;
|
||||
setup_git_directory_gently(&nongit);
|
||||
@ -167,16 +167,16 @@ static void show_commit_list(struct rev_info *revs)
|
||||
const char *name = pending->name;
|
||||
if (obj->flags & (UNINTERESTING | SEEN))
|
||||
continue;
|
||||
if (obj->type == TYPE_TAG) {
|
||||
if (obj->type == OBJ_TAG) {
|
||||
obj->flags |= SEEN;
|
||||
add_object_array(obj, name, &objects);
|
||||
continue;
|
||||
}
|
||||
if (obj->type == TYPE_TREE) {
|
||||
if (obj->type == OBJ_TREE) {
|
||||
process_tree((struct tree *)obj, &objects, NULL, name);
|
||||
continue;
|
||||
}
|
||||
if (obj->type == TYPE_BLOB) {
|
||||
if (obj->type == OBJ_BLOB) {
|
||||
process_blob((struct blob *)obj, &objects, NULL, name);
|
||||
continue;
|
||||
}
|
||||
@ -306,12 +306,12 @@ static void mark_edges_uninteresting(struct commit_list *list)
|
||||
}
|
||||
}
|
||||
|
||||
int cmd_rev_list(int argc, const char **argv, char **envp)
|
||||
int cmd_rev_list(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct commit_list *list;
|
||||
int i;
|
||||
|
||||
init_revisions(&revs);
|
||||
init_revisions(&revs, prefix);
|
||||
revs.abbrev = 0;
|
||||
revs.commit_format = CMIT_FMT_UNSPECIFIED;
|
||||
argc = setup_revisions(argc, argv, &revs, NULL);
|
||||
|
||||
@ -164,17 +164,60 @@ static int show_file(const char *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_rev_parse(int argc, const char **argv, char **envp)
|
||||
static int try_difference(const char *arg)
|
||||
{
|
||||
char *dotdot;
|
||||
unsigned char sha1[20];
|
||||
unsigned char end[20];
|
||||
const char *next;
|
||||
const char *this;
|
||||
int symmetric;
|
||||
|
||||
if (!(dotdot = strstr(arg, "..")))
|
||||
return 0;
|
||||
next = dotdot + 2;
|
||||
this = arg;
|
||||
symmetric = (*next == '.');
|
||||
|
||||
*dotdot = 0;
|
||||
next += symmetric;
|
||||
|
||||
if (!*next)
|
||||
next = "HEAD";
|
||||
if (dotdot == arg)
|
||||
this = "HEAD";
|
||||
if (!get_sha1(this, sha1) && !get_sha1(next, end)) {
|
||||
show_rev(NORMAL, end, next);
|
||||
show_rev(symmetric ? NORMAL : REVERSED, sha1, this);
|
||||
if (symmetric) {
|
||||
struct commit_list *exclude;
|
||||
struct commit *a, *b;
|
||||
a = lookup_commit_reference(sha1);
|
||||
b = lookup_commit_reference(end);
|
||||
exclude = get_merge_bases(a, b, 1);
|
||||
while (exclude) {
|
||||
struct commit_list *n = exclude->next;
|
||||
show_rev(REVERSED,
|
||||
exclude->item->object.sha1,NULL);
|
||||
free(exclude);
|
||||
exclude = n;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
*dotdot = '.';
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i, as_is = 0, verify = 0;
|
||||
unsigned char sha1[20];
|
||||
const char *prefix = setup_git_directory();
|
||||
|
||||
git_config(git_default_config);
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
char *dotdot;
|
||||
|
||||
if (as_is) {
|
||||
if (show_file(arg) && as_is < 2)
|
||||
@ -326,23 +369,8 @@ int cmd_rev_parse(int argc, const char **argv, char **envp)
|
||||
}
|
||||
|
||||
/* Not a flag argument */
|
||||
dotdot = strstr(arg, "..");
|
||||
if (dotdot) {
|
||||
unsigned char end[20];
|
||||
const char *next = dotdot + 2;
|
||||
const char *this = arg;
|
||||
*dotdot = 0;
|
||||
if (!*next)
|
||||
next = "HEAD";
|
||||
if (dotdot == arg)
|
||||
this = "HEAD";
|
||||
if (!get_sha1(this, sha1) && !get_sha1(next, end)) {
|
||||
show_rev(NORMAL, end, next);
|
||||
show_rev(REVERSED, sha1, this);
|
||||
continue;
|
||||
}
|
||||
*dotdot = '.';
|
||||
}
|
||||
if (try_difference(arg))
|
||||
continue;
|
||||
if (!get_sha1(arg, sha1)) {
|
||||
show_rev(NORMAL, sha1, arg);
|
||||
continue;
|
||||
|
||||
16
builtin-rm.c
16
builtin-rm.c
@ -43,11 +43,10 @@ static int remove_file(const char *name)
|
||||
|
||||
static struct lock_file lock_file;
|
||||
|
||||
int cmd_rm(int argc, const char **argv, char **envp)
|
||||
int cmd_rm(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i, newfd;
|
||||
int verbose = 0, show_only = 0, force = 0;
|
||||
const char *prefix = setup_git_directory();
|
||||
const char **pathspec;
|
||||
char *seen;
|
||||
|
||||
@ -81,7 +80,7 @@ int cmd_rm(int argc, const char **argv, char **envp)
|
||||
force = 1;
|
||||
continue;
|
||||
}
|
||||
die(builtin_rm_usage);
|
||||
usage(builtin_rm_usage);
|
||||
}
|
||||
if (argc <= i)
|
||||
usage(builtin_rm_usage);
|
||||
@ -90,8 +89,7 @@ int cmd_rm(int argc, const char **argv, char **envp)
|
||||
seen = NULL;
|
||||
for (i = 0; pathspec[i] ; i++)
|
||||
/* nothing */;
|
||||
seen = xmalloc(i);
|
||||
memset(seen, 0, i);
|
||||
seen = xcalloc(i, 1);
|
||||
|
||||
for (i = 0; i < active_nr; i++) {
|
||||
struct cache_entry *ce = active_cache[i];
|
||||
@ -117,7 +115,7 @@ int cmd_rm(int argc, const char **argv, char **envp)
|
||||
printf("rm '%s'\n", path);
|
||||
|
||||
if (remove_file_from_cache(path))
|
||||
die("git rm: unable to remove %s", path);
|
||||
die("git-rm: unable to remove %s", path);
|
||||
cache_tree_invalidate_path(active_cache_tree, path);
|
||||
}
|
||||
|
||||
@ -129,7 +127,7 @@ int cmd_rm(int argc, const char **argv, char **envp)
|
||||
* workspace. If we fail to remove the first one, we
|
||||
* abort the "git rm" (but once we've successfully removed
|
||||
* any file at all, we'll go ahead and commit to it all:
|
||||
* by then we've already committed ourself and can't fail
|
||||
* by then we've already committed ourselves and can't fail
|
||||
* in the middle)
|
||||
*/
|
||||
if (force) {
|
||||
@ -141,13 +139,13 @@ int cmd_rm(int argc, const char **argv, char **envp)
|
||||
continue;
|
||||
}
|
||||
if (!removed)
|
||||
die("git rm: %s: %s", path, strerror(errno));
|
||||
die("git-rm: %s: %s", path, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
if (active_cache_changed) {
|
||||
if (write_cache(newfd, active_cache, active_nr) ||
|
||||
commit_lock_file(&lock_file))
|
||||
close(newfd) || commit_lock_file(&lock_file))
|
||||
die("Unable to write new index file");
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
#include "builtin.h"
|
||||
|
||||
static const char show_branch_usage[] =
|
||||
"git-show-branch [--dense] [--current] [--all] [--heads] [--tags] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...]";
|
||||
"git-show-branch [--sparse] [--current] [--all] [--heads] [--tags] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...]";
|
||||
|
||||
static int default_num = 0;
|
||||
static int default_alloc = 0;
|
||||
@ -89,6 +89,8 @@ static int name_first_parent_chain(struct commit *c)
|
||||
name_parent(c, p);
|
||||
i++;
|
||||
}
|
||||
else
|
||||
break;
|
||||
c = p;
|
||||
}
|
||||
return i;
|
||||
@ -172,7 +174,7 @@ static void name_commits(struct commit_list *list,
|
||||
static int mark_seen(struct commit *commit, struct commit_list **seen_p)
|
||||
{
|
||||
if (!commit->object.flags) {
|
||||
insert_by_date(commit, seen_p);
|
||||
commit_list_insert(commit, seen_p);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@ -218,9 +220,8 @@ static void join_revs(struct commit_list **list_p,
|
||||
* Postprocess to complete well-poisoning.
|
||||
*
|
||||
* At this point we have all the commits we have seen in
|
||||
* seen_p list (which happens to be sorted chronologically but
|
||||
* it does not really matter). Mark anything that can be
|
||||
* reached from uninteresting commits not interesting.
|
||||
* seen_p list. Mark anything that can be reached from
|
||||
* uninteresting commits not interesting.
|
||||
*/
|
||||
for (;;) {
|
||||
int changed = 0;
|
||||
@ -549,7 +550,7 @@ static int omit_in_dense(struct commit *commit, struct commit **rev, int n)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_show_branch(int ac, const char **av, char **envp)
|
||||
int cmd_show_branch(int ac, const char **av, const char *prefix)
|
||||
{
|
||||
struct commit *rev[MAX_REVS], *commit;
|
||||
struct commit_list *list = NULL, *seen = NULL;
|
||||
@ -572,7 +573,6 @@ int cmd_show_branch(int ac, const char **av, char **envp)
|
||||
int topics = 0;
|
||||
int dense = 1;
|
||||
|
||||
setup_git_directory();
|
||||
git_config(git_show_branch_config);
|
||||
|
||||
/* If nothing is specified, try the default first */
|
||||
@ -701,6 +701,8 @@ int cmd_show_branch(int ac, const char **av, char **envp)
|
||||
if (0 <= extra)
|
||||
join_revs(&list, &seen, num_rev, extra);
|
||||
|
||||
sort_by_date(&seen);
|
||||
|
||||
if (merge_base)
|
||||
return show_merge_base(seen, num_rev);
|
||||
|
||||
|
||||
@ -54,7 +54,7 @@ void stripspace(FILE *in, FILE *out)
|
||||
fputc('\n', out);
|
||||
}
|
||||
|
||||
int cmd_stripspace(int argc, const char **argv, char **envp)
|
||||
int cmd_stripspace(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
stripspace(stdin, stdout);
|
||||
return 0;
|
||||
|
||||
@ -20,6 +20,7 @@ static char block[BLOCKSIZE];
|
||||
static unsigned long offset;
|
||||
|
||||
static time_t archive_time;
|
||||
static int tar_umask;
|
||||
|
||||
/* tries hard to write, either succeeds or dies in the attempt */
|
||||
static void reliable_write(const void *data, unsigned long size)
|
||||
@ -188,13 +189,13 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,
|
||||
} else {
|
||||
if (S_ISDIR(mode)) {
|
||||
*header.typeflag = TYPEFLAG_DIR;
|
||||
mode |= 0777;
|
||||
mode = (mode | 0777) & ~tar_umask;
|
||||
} else if (S_ISLNK(mode)) {
|
||||
*header.typeflag = TYPEFLAG_LNK;
|
||||
mode |= 0777;
|
||||
} else if (S_ISREG(mode)) {
|
||||
*header.typeflag = TYPEFLAG_REG;
|
||||
mode |= (mode & 0100) ? 0777 : 0666;
|
||||
mode = (mode | ((mode & 0100) ? 0777 : 0666)) & ~tar_umask;
|
||||
} else {
|
||||
error("unsupported file mode: 0%o (SHA1: %s)",
|
||||
mode, sha1_to_hex(sha1));
|
||||
@ -293,19 +294,33 @@ static void traverse_tree(struct tree_desc *tree, struct strbuf *path)
|
||||
}
|
||||
}
|
||||
|
||||
static int generate_tar(int argc, const char **argv, char** envp)
|
||||
int git_tar_config(const char *var, const char *value)
|
||||
{
|
||||
if (!strcmp(var, "tar.umask")) {
|
||||
if (!strcmp(value, "user")) {
|
||||
tar_umask = umask(0);
|
||||
umask(tar_umask);
|
||||
} else {
|
||||
tar_umask = git_config_int(var, value);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return git_default_config(var, value);
|
||||
}
|
||||
|
||||
static int generate_tar(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
unsigned char sha1[20], tree_sha1[20];
|
||||
struct commit *commit;
|
||||
struct tree_desc tree;
|
||||
struct strbuf current_path;
|
||||
void *buffer;
|
||||
|
||||
current_path.buf = xmalloc(PATH_MAX);
|
||||
current_path.alloc = PATH_MAX;
|
||||
current_path.len = current_path.eof = 0;
|
||||
|
||||
setup_git_directory();
|
||||
git_config(git_default_config);
|
||||
git_config(git_tar_config);
|
||||
|
||||
switch (argc) {
|
||||
case 3:
|
||||
@ -327,8 +342,8 @@ static int generate_tar(int argc, const char **argv, char** envp)
|
||||
} else
|
||||
archive_time = time(NULL);
|
||||
|
||||
tree.buf = read_object_with_reference(sha1, tree_type, &tree.size,
|
||||
tree_sha1);
|
||||
tree.buf = buffer = read_object_with_reference(sha1, tree_type,
|
||||
&tree.size, tree_sha1);
|
||||
if (!tree.buf)
|
||||
die("not a reference to a tag, commit or tree object: %s",
|
||||
sha1_to_hex(sha1));
|
||||
@ -337,6 +352,7 @@ static int generate_tar(int argc, const char **argv, char** envp)
|
||||
write_entry(tree_sha1, ¤t_path, 040777, NULL, 0);
|
||||
traverse_tree(&tree, ¤t_path);
|
||||
write_trailer();
|
||||
free(buffer);
|
||||
free(current_path.buf);
|
||||
return 0;
|
||||
}
|
||||
@ -387,19 +403,19 @@ static int remote_tar(int argc, const char **argv)
|
||||
return !!ret;
|
||||
}
|
||||
|
||||
int cmd_tar_tree(int argc, const char **argv, char **envp)
|
||||
int cmd_tar_tree(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
if (argc < 2)
|
||||
usage(tar_tree_usage);
|
||||
if (!strncmp("--remote=", argv[1], 9))
|
||||
return remote_tar(argc, argv);
|
||||
return generate_tar(argc, argv, envp);
|
||||
return generate_tar(argc, argv, prefix);
|
||||
}
|
||||
|
||||
/* ustar header + extended global header content */
|
||||
#define HEADERSIZE (2 * RECORDSIZE)
|
||||
|
||||
int cmd_get_tar_commit_id(int argc, const char **argv, char **envp)
|
||||
int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
char buffer[HEADERSIZE];
|
||||
struct ustar_header *header = (struct ustar_header *)buffer;
|
||||
|
||||
@ -476,12 +476,11 @@ static int do_reupdate(int ac, const char **av,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_update_index(int argc, const char **argv, char **envp)
|
||||
int cmd_update_index(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i, newfd, entries, has_errors = 0, line_termination = '\n';
|
||||
int allow_options = 1;
|
||||
int read_from_stdin = 0;
|
||||
const char *prefix = setup_git_directory();
|
||||
int prefix_length = prefix ? strlen(prefix) : 0;
|
||||
char set_executable_bit = 0;
|
||||
unsigned int refresh_flags = 0;
|
||||
@ -648,7 +647,7 @@ int cmd_update_index(int argc, const char **argv, char **envp)
|
||||
finish:
|
||||
if (active_cache_changed) {
|
||||
if (write_cache(newfd, active_cache, active_nr) ||
|
||||
commit_lock_file(lock_file))
|
||||
close(newfd) || commit_lock_file(lock_file))
|
||||
die("Unable to write new index file");
|
||||
}
|
||||
|
||||
|
||||
@ -5,14 +5,14 @@
|
||||
static const char git_update_ref_usage[] =
|
||||
"git-update-ref <refname> <value> [<oldval>] [-m <reason>]";
|
||||
|
||||
int cmd_update_ref(int argc, const char **argv, char **envp)
|
||||
int cmd_update_ref(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
const char *refname=NULL, *value=NULL, *oldval=NULL, *msg=NULL;
|
||||
struct ref_lock *lock;
|
||||
unsigned char sha1[20], oldsha1[20];
|
||||
int i;
|
||||
|
||||
setup_git_directory();
|
||||
setup_ident();
|
||||
git_config(git_default_config);
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
|
||||
@ -15,7 +15,7 @@ static int nak(const char *reason)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cmd_upload_tar(int argc, const char **argv, char **envp)
|
||||
int cmd_upload_tar(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int len;
|
||||
const char *dir = argv[1];
|
||||
|
||||
@ -35,7 +35,8 @@ int write_tree(unsigned char *sha1, int missing_ok, const char *prefix)
|
||||
missing_ok, 0) < 0)
|
||||
die("git-write-tree: error building trees");
|
||||
if (0 <= newfd) {
|
||||
if (!write_cache(newfd, active_cache, active_nr))
|
||||
if (!write_cache(newfd, active_cache, active_nr)
|
||||
&& !close(newfd))
|
||||
commit_lock_file(lock_file);
|
||||
}
|
||||
/* Not being able to write is fine -- we are only interested
|
||||
@ -59,14 +60,12 @@ int write_tree(unsigned char *sha1, int missing_ok, const char *prefix)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_write_tree(int argc, const char **argv, char **envp)
|
||||
int cmd_write_tree(int argc, const char **argv, const char *unused_prefix)
|
||||
{
|
||||
int missing_ok = 0, ret;
|
||||
const char *prefix = NULL;
|
||||
unsigned char sha1[20];
|
||||
|
||||
setup_git_directory();
|
||||
|
||||
while (1 < argc) {
|
||||
const char *arg = argv[1];
|
||||
if (!strcmp(arg, "--missing-ok"))
|
||||
@ -74,7 +73,7 @@ int cmd_write_tree(int argc, const char **argv, char **envp)
|
||||
else if (!strncmp(arg, "--prefix=", 9))
|
||||
prefix = arg + 9;
|
||||
else
|
||||
die(write_tree_usage);
|
||||
usage(write_tree_usage);
|
||||
argc--; argv++;
|
||||
}
|
||||
|
||||
|
||||
90
builtin.h
90
builtin.h
@ -2,63 +2,63 @@
|
||||
#define BUILTIN_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef PATH_MAX
|
||||
# define PATH_MAX 4096
|
||||
#endif
|
||||
#include <limits.h>
|
||||
|
||||
extern const char git_version_string[];
|
||||
extern const char git_usage_string[];
|
||||
|
||||
void cmd_usage(int show_all, const char *exec_path, const char *fmt, ...)
|
||||
#ifdef __GNUC__
|
||||
__attribute__((__format__(__printf__, 3, 4), __noreturn__))
|
||||
#endif
|
||||
;
|
||||
extern void help_unknown_cmd(const char *cmd);
|
||||
|
||||
extern int cmd_help(int argc, const char **argv, char **envp);
|
||||
extern int cmd_version(int argc, const char **argv, char **envp);
|
||||
extern int cmd_help(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_version(int argc, const char **argv, const char *prefix);
|
||||
|
||||
extern int cmd_whatchanged(int argc, const char **argv, char **envp);
|
||||
extern int cmd_show(int argc, const char **argv, char **envp);
|
||||
extern int cmd_log(int argc, const char **argv, char **envp);
|
||||
extern int cmd_diff(int argc, const char **argv, char **envp);
|
||||
extern int cmd_format_patch(int argc, const char **argv, char **envp);
|
||||
extern int cmd_count_objects(int argc, const char **argv, char **envp);
|
||||
extern int cmd_whatchanged(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_show(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_log(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_diff(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_format_patch(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_count_objects(int argc, const char **argv, const char *prefix);
|
||||
|
||||
extern int cmd_push(int argc, const char **argv, char **envp);
|
||||
extern int cmd_grep(int argc, const char **argv, char **envp);
|
||||
extern int cmd_rm(int argc, const char **argv, char **envp);
|
||||
extern int cmd_add(int argc, const char **argv, char **envp);
|
||||
extern int cmd_rev_list(int argc, const char **argv, char **envp);
|
||||
extern int cmd_check_ref_format(int argc, const char **argv, char **envp);
|
||||
extern int cmd_init_db(int argc, const char **argv, char **envp);
|
||||
extern int cmd_tar_tree(int argc, const char **argv, char **envp);
|
||||
extern int cmd_upload_tar(int argc, const char **argv, char **envp);
|
||||
extern int cmd_get_tar_commit_id(int argc, const char **argv, char **envp);
|
||||
extern int cmd_ls_files(int argc, const char **argv, char **envp);
|
||||
extern int cmd_ls_tree(int argc, const char **argv, char **envp);
|
||||
extern int cmd_read_tree(int argc, const char **argv, char **envp);
|
||||
extern int cmd_commit_tree(int argc, const char **argv, char **envp);
|
||||
extern int cmd_apply(int argc, const char **argv, char **envp);
|
||||
extern int cmd_show_branch(int argc, const char **argv, char **envp);
|
||||
extern int cmd_diff_files(int argc, const char **argv, char **envp);
|
||||
extern int cmd_diff_index(int argc, const char **argv, char **envp);
|
||||
extern int cmd_diff_stages(int argc, const char **argv, char **envp);
|
||||
extern int cmd_diff_tree(int argc, const char **argv, char **envp);
|
||||
extern int cmd_cat_file(int argc, const char **argv, char **envp);
|
||||
extern int cmd_rev_parse(int argc, const char **argv, char **envp);
|
||||
extern int cmd_update_index(int argc, const char **argv, char **envp);
|
||||
extern int cmd_update_ref(int argc, const char **argv, char **envp);
|
||||
extern int cmd_prune(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);
|
||||
|
||||
extern int cmd_write_tree(int argc, const char **argv, char **envp);
|
||||
extern int cmd_push(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_grep(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_rm(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_add(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_rev_list(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_init_db(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_tar_tree(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_upload_tar(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_ls_files(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_ls_tree(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_read_tree(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_apply(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_diff_files(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_diff_index(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_diff_stages(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_diff_tree(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_cat_file(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_update_index(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_update_ref(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_mv(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_repo_config(int argc, const char **argv, const char *prefix);
|
||||
|
||||
extern int cmd_write_tree(int argc, const char **argv, const char *prefix);
|
||||
extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
|
||||
|
||||
extern int cmd_mailsplit(int argc, const char **argv, char **envp);
|
||||
extern int cmd_mailsplit(int argc, const char **argv, const char *prefix);
|
||||
extern int split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip);
|
||||
|
||||
extern int cmd_mailinfo(int argc, const char **argv, char **envp);
|
||||
extern int cmd_mailinfo(int argc, const char **argv, const char *prefix);
|
||||
extern int mailinfo(FILE *in, FILE *out, int ks, const char *encoding, const char *msg, const char *patch);
|
||||
|
||||
extern int cmd_stripspace(int argc, const char **argv, char **envp);
|
||||
extern int cmd_stripspace(int argc, const char **argv, const char *prefix);
|
||||
extern void stripspace(FILE *in, FILE *out);
|
||||
#endif
|
||||
|
||||
16
cache.h
16
cache.h
@ -115,6 +115,7 @@ static inline unsigned int create_ce_mode(unsigned int mode)
|
||||
extern struct cache_entry **active_cache;
|
||||
extern unsigned int active_nr, active_alloc, active_cache_changed;
|
||||
extern struct cache_tree *active_cache_tree;
|
||||
extern int cache_errno;
|
||||
|
||||
extern void setup_git(char *new_git_dir, char *new_git_object_dir,
|
||||
char *new_git_index_file, char *new_git_graft_file);
|
||||
@ -145,6 +146,7 @@ extern void verify_non_filename(const char *prefix, const char *name);
|
||||
|
||||
/* Initialize and use the cache information */
|
||||
extern int read_cache(void);
|
||||
extern int read_cache_from(const char *path);
|
||||
extern int write_cache(int newfd, struct cache_entry **cache, int entries);
|
||||
extern int verify_path(const char *path);
|
||||
extern int cache_name_pos(const char *name, int namelen);
|
||||
@ -152,8 +154,10 @@ extern int cache_name_pos(const char *name, int namelen);
|
||||
#define ADD_CACHE_OK_TO_REPLACE 2 /* Ok to replace file/directory */
|
||||
#define ADD_CACHE_SKIP_DFCHECK 4 /* Ok to skip DF conflict checks */
|
||||
extern int add_cache_entry(struct cache_entry *ce, int option);
|
||||
extern struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);
|
||||
extern int remove_cache_entry_at(int pos);
|
||||
extern int remove_file_from_cache(const char *path);
|
||||
extern int add_file_to_index(const char *path, int verbose);
|
||||
extern int ce_same_name(struct cache_entry *a, struct cache_entry *b);
|
||||
extern int ce_match_stat(struct cache_entry *ce, struct stat *st, int);
|
||||
extern int ce_modified(struct cache_entry *ce, struct stat *st, int);
|
||||
@ -179,6 +183,7 @@ extern int commit_lock_file(struct lock_file *);
|
||||
extern void rollback_lock_file(struct lock_file *);
|
||||
|
||||
/* Environment bits from configuration mechanism */
|
||||
extern int use_legacy_headers;
|
||||
extern int trust_executable_bit;
|
||||
extern int assume_unchanged;
|
||||
extern int prefer_symlink_refs;
|
||||
@ -186,6 +191,7 @@ extern int log_all_ref_updates;
|
||||
extern int warn_ambiguous_refs;
|
||||
extern int shared_repository;
|
||||
extern const char *apply_default_whitespace;
|
||||
extern int zlib_compression_level;
|
||||
|
||||
#define GIT_REPO_VERSION 0
|
||||
extern int repository_format_version;
|
||||
@ -221,8 +227,6 @@ int safe_create_leading_directories(char *path);
|
||||
char *enter_repo(char *path, int strict);
|
||||
|
||||
/* Read and unpack a sha1 file into memory, write memory to a sha1 file */
|
||||
extern int unpack_sha1_header(z_stream *stream, void *map, unsigned long mapsize, void *buffer, unsigned long size);
|
||||
extern int parse_sha1_header(char *hdr, char *type, unsigned long *sizep);
|
||||
extern int sha1_object_info(const unsigned char *, char *, unsigned long *);
|
||||
extern void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size);
|
||||
extern void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size);
|
||||
@ -324,13 +328,17 @@ struct ref {
|
||||
char name[FLEX_ARRAY]; /* more */
|
||||
};
|
||||
|
||||
#define REF_NORMAL (1u << 0)
|
||||
#define REF_HEADS (1u << 1)
|
||||
#define REF_TAGS (1u << 2)
|
||||
|
||||
extern int git_connect(int fd[2], char *url, const char *prog);
|
||||
extern int finish_connect(pid_t pid);
|
||||
extern int path_match(const char *path, int nr, char **match);
|
||||
extern int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
|
||||
int nr_refspec, char **refspec, int all);
|
||||
extern int get_ack(int fd, unsigned char *result_sha1);
|
||||
extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, int ignore_funny);
|
||||
extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, unsigned int flags);
|
||||
extern int server_supports(const char *feature);
|
||||
|
||||
extern struct packed_git *parse_pack_index(unsigned char *sha1);
|
||||
@ -380,6 +388,8 @@ extern int receive_keep_pack(int fd[2], const char *me, int quiet, int);
|
||||
|
||||
/* pager.c */
|
||||
extern void setup_pager(void);
|
||||
extern int pager_in_use;
|
||||
extern int pager_use_color;
|
||||
|
||||
/* base85 */
|
||||
int decode_85(char *dst, char *line, int linelen);
|
||||
|
||||
@ -49,14 +49,7 @@ static int checkout_stage; /* default to checkout stage0 */
|
||||
static int to_tempfile;
|
||||
static char topath[4][MAXPATHLEN+1];
|
||||
|
||||
static struct checkout state = {
|
||||
.base_dir = "",
|
||||
.base_dir_len = 0,
|
||||
.force = 0,
|
||||
.quiet = 0,
|
||||
.not_new = 0,
|
||||
.refresh_cache = 0,
|
||||
};
|
||||
static struct checkout state;
|
||||
|
||||
static void write_tempfile_record (const char *name)
|
||||
{
|
||||
@ -177,6 +170,7 @@ int main(int argc, char **argv)
|
||||
int all = 0;
|
||||
int read_from_stdin = 0;
|
||||
|
||||
state.base_dir = "";
|
||||
prefix = setup_git_directory();
|
||||
git_config(git_default_config);
|
||||
prefix_length = prefix ? strlen(prefix) : 0;
|
||||
@ -311,7 +305,7 @@ int main(int argc, char **argv)
|
||||
|
||||
if (0 <= newfd &&
|
||||
(write_cache(newfd, active_cache, active_nr) ||
|
||||
commit_lock_file(&lock_file)))
|
||||
close(newfd) || commit_lock_file(&lock_file)))
|
||||
die("Unable to write new index file");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -320,7 +320,7 @@ static int give_context(struct sline *sline, unsigned long cnt, int num_parent)
|
||||
unsigned long i;
|
||||
|
||||
/* Two groups of interesting lines may have a short gap of
|
||||
* unintersting lines. Connect such groups to give them a
|
||||
* uninteresting lines. Connect such groups to give them a
|
||||
* bit of context.
|
||||
*
|
||||
* We first start from what the interesting() function says,
|
||||
@ -639,8 +639,7 @@ static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
|
||||
/* deleted file */
|
||||
result_size = 0;
|
||||
elem->mode = 0;
|
||||
result = xmalloc(1);
|
||||
result[0] = 0;
|
||||
result = xcalloc(1, 1);
|
||||
}
|
||||
if (0 <= fd)
|
||||
close(fd);
|
||||
@ -702,7 +701,7 @@ static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
|
||||
const char *abb;
|
||||
|
||||
if (rev->loginfo)
|
||||
show_log(rev, rev->loginfo, "\n");
|
||||
show_log(rev, opt->msg_sep);
|
||||
dump_quoted_path(dense ? "diff --cc " : "diff --combined ", elem->path);
|
||||
printf("index ");
|
||||
for (i = 0; i < num_parent; i++) {
|
||||
@ -770,9 +769,9 @@ static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct re
|
||||
inter_name_termination = 0;
|
||||
|
||||
if (rev->loginfo)
|
||||
show_log(rev, rev->loginfo, "\n");
|
||||
show_log(rev, opt->msg_sep);
|
||||
|
||||
if (opt->output_format == DIFF_FORMAT_RAW) {
|
||||
if (opt->output_format & DIFF_FORMAT_RAW) {
|
||||
offset = strlen(COLONS) - num_parent;
|
||||
if (offset < 0)
|
||||
offset = 0;
|
||||
@ -792,8 +791,7 @@ static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct re
|
||||
printf(" %s ", diff_unique_abbrev(p->sha1, opt->abbrev));
|
||||
}
|
||||
|
||||
if (opt->output_format == DIFF_FORMAT_RAW ||
|
||||
opt->output_format == DIFF_FORMAT_NAME_STATUS) {
|
||||
if (opt->output_format & (DIFF_FORMAT_RAW | DIFF_FORMAT_NAME_STATUS)) {
|
||||
for (i = 0; i < num_parent; i++)
|
||||
putchar(p->parent[i].status);
|
||||
putchar(inter_name_termination);
|
||||
@ -819,17 +817,12 @@ void show_combined_diff(struct combine_diff_path *p,
|
||||
struct diff_options *opt = &rev->diffopt;
|
||||
if (!p->len)
|
||||
return;
|
||||
switch (opt->output_format) {
|
||||
case DIFF_FORMAT_RAW:
|
||||
case DIFF_FORMAT_NAME_STATUS:
|
||||
case DIFF_FORMAT_NAME:
|
||||
if (opt->output_format & (DIFF_FORMAT_RAW |
|
||||
DIFF_FORMAT_NAME |
|
||||
DIFF_FORMAT_NAME_STATUS)) {
|
||||
show_raw_diff(p, num_parent, rev);
|
||||
return;
|
||||
case DIFF_FORMAT_PATCH:
|
||||
} else if (opt->output_format & DIFF_FORMAT_PATCH) {
|
||||
show_patch_diff(p, num_parent, dense, rev);
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -842,22 +835,20 @@ void diff_tree_combined(const unsigned char *sha1,
|
||||
struct diff_options *opt = &rev->diffopt;
|
||||
struct diff_options diffopts;
|
||||
struct combine_diff_path *p, *paths = NULL;
|
||||
int i, num_paths;
|
||||
int do_diffstat;
|
||||
int i, num_paths, needsep, show_log_first;
|
||||
|
||||
do_diffstat = (opt->output_format == DIFF_FORMAT_DIFFSTAT ||
|
||||
opt->with_stat);
|
||||
diffopts = *opt;
|
||||
diffopts.with_raw = 0;
|
||||
diffopts.with_stat = 0;
|
||||
diffopts.output_format = DIFF_FORMAT_NO_OUTPUT;
|
||||
diffopts.recursive = 1;
|
||||
|
||||
show_log_first = !!rev->loginfo;
|
||||
needsep = 0;
|
||||
/* find set of paths that everybody touches */
|
||||
for (i = 0; i < num_parent; i++) {
|
||||
/* show stat against the first parent even
|
||||
* when doing combined diff.
|
||||
*/
|
||||
if (i == 0 && do_diffstat)
|
||||
if (i == 0 && opt->output_format & DIFF_FORMAT_DIFFSTAT)
|
||||
diffopts.output_format = DIFF_FORMAT_DIFFSTAT;
|
||||
else
|
||||
diffopts.output_format = DIFF_FORMAT_NO_OUTPUT;
|
||||
@ -865,12 +856,12 @@ void diff_tree_combined(const unsigned char *sha1,
|
||||
diffcore_std(&diffopts);
|
||||
paths = intersect_paths(paths, i, num_parent);
|
||||
|
||||
if (do_diffstat && rev->loginfo)
|
||||
show_log(rev, rev->loginfo,
|
||||
opt->with_stat ? "---\n" : "\n");
|
||||
if (show_log_first && i == 0) {
|
||||
show_log(rev, opt->msg_sep);
|
||||
if (rev->verbose_header && opt->output_format)
|
||||
putchar(opt->line_termination);
|
||||
}
|
||||
diff_flush(&diffopts);
|
||||
if (opt->with_stat)
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
/* find out surviving paths */
|
||||
@ -879,17 +870,25 @@ void diff_tree_combined(const unsigned char *sha1,
|
||||
num_paths++;
|
||||
}
|
||||
if (num_paths) {
|
||||
if (opt->with_raw) {
|
||||
int saved_format = opt->output_format;
|
||||
opt->output_format = DIFF_FORMAT_RAW;
|
||||
if (opt->output_format & (DIFF_FORMAT_RAW |
|
||||
DIFF_FORMAT_NAME |
|
||||
DIFF_FORMAT_NAME_STATUS)) {
|
||||
for (p = paths; p; p = p->next) {
|
||||
show_combined_diff(p, num_parent, dense, rev);
|
||||
if (p->len)
|
||||
show_raw_diff(p, num_parent, rev);
|
||||
}
|
||||
opt->output_format = saved_format;
|
||||
putchar(opt->line_termination);
|
||||
needsep = 1;
|
||||
}
|
||||
for (p = paths; p; p = p->next) {
|
||||
show_combined_diff(p, num_parent, dense, rev);
|
||||
else if (opt->output_format & DIFF_FORMAT_DIFFSTAT)
|
||||
needsep = 1;
|
||||
if (opt->output_format & DIFF_FORMAT_PATCH) {
|
||||
if (needsep)
|
||||
putchar(opt->line_termination);
|
||||
for (p = paths; p; p = p->next) {
|
||||
if (p->len)
|
||||
show_patch_diff(p, num_parent, dense,
|
||||
rev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
168
commit.c
168
commit.c
@ -56,7 +56,7 @@ static struct commit *check_commit(struct object *obj,
|
||||
const unsigned char *sha1,
|
||||
int quiet)
|
||||
{
|
||||
if (obj->type != TYPE_COMMIT) {
|
||||
if (obj->type != OBJ_COMMIT) {
|
||||
if (!quiet)
|
||||
error("Object %s is a %s, not a commit",
|
||||
sha1_to_hex(sha1), typename(obj->type));
|
||||
@ -86,11 +86,11 @@ struct commit *lookup_commit(const unsigned char *sha1)
|
||||
if (!obj) {
|
||||
struct commit *ret = alloc_commit_node();
|
||||
created_object(sha1, &ret->object);
|
||||
ret->object.type = TYPE_COMMIT;
|
||||
ret->object.type = OBJ_COMMIT;
|
||||
return ret;
|
||||
}
|
||||
if (!obj->type)
|
||||
obj->type = TYPE_COMMIT;
|
||||
obj->type = OBJ_COMMIT;
|
||||
return check_commit(obj, sha1, 0);
|
||||
}
|
||||
|
||||
@ -412,12 +412,13 @@ void clear_commit_marks(struct commit *commit, unsigned int mark)
|
||||
{
|
||||
struct commit_list *parents;
|
||||
|
||||
parents = commit->parents;
|
||||
commit->object.flags &= ~mark;
|
||||
parents = commit->parents;
|
||||
while (parents) {
|
||||
struct commit *parent = parents->item;
|
||||
if (parent && parent->object.parsed &&
|
||||
(parent->object.flags & mark))
|
||||
|
||||
/* Have we already cleared this? */
|
||||
if (mark & parent->object.flags)
|
||||
clear_commit_marks(parent, mark);
|
||||
parents = parents->next;
|
||||
}
|
||||
@ -669,6 +670,9 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!subject)
|
||||
body = 1;
|
||||
|
||||
if (is_empty_line(line, &linelen)) {
|
||||
if (!body)
|
||||
continue;
|
||||
@ -676,8 +680,6 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit
|
||||
continue;
|
||||
if (fmt == CMIT_FMT_SHORT)
|
||||
break;
|
||||
} else {
|
||||
body = 1;
|
||||
}
|
||||
|
||||
if (subject) {
|
||||
@ -716,6 +718,12 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit
|
||||
/* Make sure there is an EOLN for the non-oneline case */
|
||||
if (fmt != CMIT_FMT_ONELINE)
|
||||
buf[offset++] = '\n';
|
||||
/*
|
||||
* make sure there is another EOLN to separate the headers from whatever
|
||||
* body the caller appends if we haven't already written a body
|
||||
*/
|
||||
if (fmt == CMIT_FMT_EMAIL && !body)
|
||||
buf[offset++] = '\n';
|
||||
buf[offset] = '\0';
|
||||
return offset;
|
||||
}
|
||||
@ -861,3 +869,147 @@ void sort_in_topological_order_fn(struct commit_list ** list, int lifo,
|
||||
}
|
||||
free(nodes);
|
||||
}
|
||||
|
||||
/* merge-rebase stuff */
|
||||
|
||||
/* bits #0..7 in revision.h */
|
||||
#define PARENT1 (1u<< 8)
|
||||
#define PARENT2 (1u<< 9)
|
||||
#define STALE (1u<<10)
|
||||
#define RESULT (1u<<11)
|
||||
|
||||
static struct commit *interesting(struct commit_list *list)
|
||||
{
|
||||
while (list) {
|
||||
struct commit *commit = list->item;
|
||||
list = list->next;
|
||||
if (commit->object.flags & STALE)
|
||||
continue;
|
||||
return commit;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct commit_list *merge_bases(struct commit *one, struct commit *two)
|
||||
{
|
||||
struct commit_list *list = NULL;
|
||||
struct commit_list *result = NULL;
|
||||
|
||||
if (one == two)
|
||||
/* We do not mark this even with RESULT so we do not
|
||||
* have to clean it up.
|
||||
*/
|
||||
return commit_list_insert(one, &result);
|
||||
|
||||
parse_commit(one);
|
||||
parse_commit(two);
|
||||
|
||||
one->object.flags |= PARENT1;
|
||||
two->object.flags |= PARENT2;
|
||||
insert_by_date(one, &list);
|
||||
insert_by_date(two, &list);
|
||||
|
||||
while (interesting(list)) {
|
||||
struct commit *commit;
|
||||
struct commit_list *parents;
|
||||
struct commit_list *n;
|
||||
int flags;
|
||||
|
||||
commit = list->item;
|
||||
n = list->next;
|
||||
free(list);
|
||||
list = n;
|
||||
|
||||
flags = commit->object.flags & (PARENT1 | PARENT2 | STALE);
|
||||
if (flags == (PARENT1 | PARENT2)) {
|
||||
if (!(commit->object.flags & RESULT)) {
|
||||
commit->object.flags |= RESULT;
|
||||
insert_by_date(commit, &result);
|
||||
}
|
||||
/* Mark parents of a found merge stale */
|
||||
flags |= STALE;
|
||||
}
|
||||
parents = commit->parents;
|
||||
while (parents) {
|
||||
struct commit *p = parents->item;
|
||||
parents = parents->next;
|
||||
if ((p->object.flags & flags) == flags)
|
||||
continue;
|
||||
parse_commit(p);
|
||||
p->object.flags |= flags;
|
||||
insert_by_date(p, &list);
|
||||
}
|
||||
}
|
||||
|
||||
/* Clean up the result to remove stale ones */
|
||||
list = result; result = NULL;
|
||||
while (list) {
|
||||
struct commit_list *n = list->next;
|
||||
if (!(list->item->object.flags & STALE))
|
||||
insert_by_date(list->item, &result);
|
||||
free(list);
|
||||
list = n;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
struct commit_list *get_merge_bases(struct commit *one,
|
||||
struct commit *two,
|
||||
int cleanup)
|
||||
{
|
||||
const unsigned all_flags = (PARENT1 | PARENT2 | STALE | RESULT);
|
||||
struct commit_list *list;
|
||||
struct commit **rslt;
|
||||
struct commit_list *result;
|
||||
int cnt, i, j;
|
||||
|
||||
result = merge_bases(one, two);
|
||||
if (one == two)
|
||||
return result;
|
||||
if (!result || !result->next) {
|
||||
if (cleanup) {
|
||||
clear_commit_marks(one, all_flags);
|
||||
clear_commit_marks(two, all_flags);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* There are more than one */
|
||||
cnt = 0;
|
||||
list = result;
|
||||
while (list) {
|
||||
list = list->next;
|
||||
cnt++;
|
||||
}
|
||||
rslt = xcalloc(cnt, sizeof(*rslt));
|
||||
for (list = result, i = 0; list; list = list->next)
|
||||
rslt[i++] = list->item;
|
||||
free_commit_list(result);
|
||||
|
||||
clear_commit_marks(one, all_flags);
|
||||
clear_commit_marks(two, all_flags);
|
||||
for (i = 0; i < cnt - 1; i++) {
|
||||
for (j = i+1; j < cnt; j++) {
|
||||
if (!rslt[i] || !rslt[j])
|
||||
continue;
|
||||
result = merge_bases(rslt[i], rslt[j]);
|
||||
clear_commit_marks(rslt[i], all_flags);
|
||||
clear_commit_marks(rslt[j], all_flags);
|
||||
for (list = result; list; list = list->next) {
|
||||
if (rslt[i] == list->item)
|
||||
rslt[i] = NULL;
|
||||
if (rslt[j] == list->item)
|
||||
rslt[j] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Surviving ones in rslt[] are the independent results */
|
||||
result = NULL;
|
||||
for (i = 0; i < cnt; i++) {
|
||||
if (rslt[i])
|
||||
insert_by_date(rslt[i], &result);
|
||||
}
|
||||
free(rslt);
|
||||
return result;
|
||||
}
|
||||
|
||||
2
commit.h
2
commit.h
@ -105,4 +105,6 @@ struct commit_graft *read_graft_line(char *buf, int len);
|
||||
int register_commit_graft(struct commit_graft *, int);
|
||||
int read_graft_file(const char *graft_file);
|
||||
|
||||
extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2, int cleanup);
|
||||
|
||||
#endif /* COMMIT_H */
|
||||
|
||||
@ -568,7 +568,7 @@ class Popen(object):
|
||||
# Windows methods
|
||||
#
|
||||
def _get_handles(self, stdin, stdout, stderr):
|
||||
"""Construct and return tupel with IO objects:
|
||||
"""Construct and return tuple with IO objects:
|
||||
p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite
|
||||
"""
|
||||
if stdin == None and stdout == None and stderr == None:
|
||||
@ -635,7 +635,7 @@ class Popen(object):
|
||||
|
||||
|
||||
def _find_w9xpopen(self):
|
||||
"""Find and return absolut path to w9xpopen.exe"""
|
||||
"""Find and return absolute path to w9xpopen.exe"""
|
||||
w9xpopen = os.path.join(os.path.dirname(GetModuleFileName(0)),
|
||||
"w9xpopen.exe")
|
||||
if not os.path.exists(w9xpopen):
|
||||
@ -812,7 +812,7 @@ class Popen(object):
|
||||
# POSIX methods
|
||||
#
|
||||
def _get_handles(self, stdin, stdout, stderr):
|
||||
"""Construct and return tupel with IO objects:
|
||||
"""Construct and return tuple with IO objects:
|
||||
p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite
|
||||
"""
|
||||
p2cread, p2cwrite = None, None
|
||||
|
||||
24
config.c
24
config.c
@ -244,9 +244,9 @@ int git_config_bool(const char *name, const char *value)
|
||||
return 1;
|
||||
if (!*value)
|
||||
return 0;
|
||||
if (!strcasecmp(value, "true"))
|
||||
if (!strcasecmp(value, "true") || !strcasecmp(value, "yes"))
|
||||
return 1;
|
||||
if (!strcasecmp(value, "false"))
|
||||
if (!strcasecmp(value, "false") || !strcasecmp(value, "no"))
|
||||
return 0;
|
||||
return git_config_int(name, value) != 0;
|
||||
}
|
||||
@ -279,6 +279,21 @@ int git_default_config(const char *var, const char *value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "core.legacyheaders")) {
|
||||
use_legacy_headers = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "core.compression")) {
|
||||
int level = git_config_int(var, value);
|
||||
if (level == -1)
|
||||
level = Z_DEFAULT_COMPRESSION;
|
||||
else if (level < 0 || level > Z_BEST_COMPRESSION)
|
||||
die("bad zlib compression level %d", level);
|
||||
zlib_compression_level = level;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "user.name")) {
|
||||
strlcpy(git_default_name, value, sizeof(git_default_name));
|
||||
return 0;
|
||||
@ -294,6 +309,11 @@ int git_default_config(const char *var, const char *value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "pager.color")) {
|
||||
pager_use_color = git_config_bool(var,value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Add other config variables here and to Documentation/config.txt. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
24
config.mak.in
Normal file
24
config.mak.in
Normal file
@ -0,0 +1,24 @@
|
||||
# git Makefile configuration, included in main Makefile
|
||||
# @configure_input@
|
||||
|
||||
CC = @CC@
|
||||
AR = @AR@
|
||||
TAR = @TAR@
|
||||
#INSTALL = @INSTALL@ # needs install-sh or install.sh in sources
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
bindir = @bindir@
|
||||
#gitexecdir = @libexecdir@/git-core/
|
||||
datarootdir = @datarootdir@
|
||||
template_dir = @datadir@/git-core/templates/
|
||||
GIT_PYTHON_DIR = @datadir@/git-core/python
|
||||
|
||||
mandir=@mandir@
|
||||
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
export exec_prefix mandir
|
||||
export srcdir VPATH
|
||||
|
||||
183
configure.ac
Normal file
183
configure.ac
Normal file
@ -0,0 +1,183 @@
|
||||
# -*- Autoconf -*-
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ(2.59)
|
||||
AC_INIT([git], [1.4.1], [git@vger.kernel.org])
|
||||
|
||||
AC_CONFIG_SRCDIR([git.c])
|
||||
|
||||
config_file=config.mak.autogen
|
||||
config_append=config.mak.append
|
||||
config_in=config.mak.in
|
||||
|
||||
echo "# ${config_append}. Generated by configure." > "${config_append}"
|
||||
|
||||
|
||||
## Definitions of macros
|
||||
# GIT_CONF_APPEND_LINE(LINE)
|
||||
# --------------------------
|
||||
# Append LINE to file ${config_append}
|
||||
AC_DEFUN([GIT_CONF_APPEND_LINE],
|
||||
[echo "$1" >> "${config_append}"])# GIT_CONF_APPEND_LINE
|
||||
|
||||
|
||||
## Checks for programs.
|
||||
AC_MSG_NOTICE([CHECKS for programs])
|
||||
#
|
||||
AC_PROG_CC
|
||||
#AC_PROG_INSTALL # needs install-sh or install.sh in sources
|
||||
AC_CHECK_TOOL(AR, ar, :)
|
||||
AC_CHECK_PROGS(TAR, [gtar tar])
|
||||
#
|
||||
# Define NO_PYTHON if you want to lose all benefits of the recursive merge.
|
||||
|
||||
|
||||
## Checks for libraries.
|
||||
AC_MSG_NOTICE([CHECKS for libraries])
|
||||
#
|
||||
# Define NO_OPENSSL environment variable if you do not have OpenSSL.
|
||||
# Define NEEDS_SSL_WITH_CRYPTO if you need -lcrypto with -lssl (Darwin).
|
||||
AC_CHECK_LIB([ssl], [SHA1_Init],[],
|
||||
[AC_CHECK_LIB([crypto], [SHA1_INIT],
|
||||
[GIT_CONF_APPEND_LINE(NEEDS_SSL_WITH_CRYPTO=YesPlease)],
|
||||
[GIT_CONF_APPEND_LINE(NO_OPENSSL=YesPlease)])])
|
||||
#
|
||||
# Define NO_CURL if you do not have curl installed. git-http-pull and
|
||||
# git-http-push are not built, and you cannot use http:// and https://
|
||||
# transports.
|
||||
AC_CHECK_LIB([curl], [curl_global_init],[],
|
||||
[GIT_CONF_APPEND_LINE(NO_CURL=YesPlease)])
|
||||
#
|
||||
# Define NO_EXPAT if you do not have expat installed. git-http-push is
|
||||
# not built, and you cannot push using http:// and https:// transports.
|
||||
AC_CHECK_LIB([expat], [XML_ParserCreate],[],
|
||||
[GIT_CONF_APPEND_LINE(NO_EXPAT=YesPlease)])
|
||||
#
|
||||
# Define NEEDS_LIBICONV if linking with libc is not enough (Darwin).
|
||||
AC_CHECK_LIB([c], [iconv],[],
|
||||
[AC_CHECK_LIB([iconv],[iconv],
|
||||
[GIT_CONF_APPEND_LINE(NEEDS_LIBICONV=YesPlease)],[])])
|
||||
#
|
||||
# Define NEEDS_SOCKET if linking with libc is not enough (SunOS,
|
||||
# Patrick Mauritz).
|
||||
AC_CHECK_LIB([c], [socket],[],
|
||||
[AC_CHECK_LIB([socket],[socket],
|
||||
[GIT_CONF_APPEND_LINE(NEEDS_SOCKET=YesPlease)],[])])
|
||||
|
||||
|
||||
## Checks for header files.
|
||||
|
||||
|
||||
## Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_MSG_NOTICE([CHECKS for typedefs, structures, and compiler characteristics])
|
||||
#
|
||||
# Define NO_D_INO_IN_DIRENT if you don't have d_ino in your struct dirent.
|
||||
AC_CHECK_MEMBER(struct dirent.d_ino,[],
|
||||
[GIT_CONF_APPEND_LINE(NO_D_INO_IN_DIRENT=YesPlease)],
|
||||
[#include <dirent.h>])
|
||||
#
|
||||
# Define NO_D_TYPE_IN_DIRENT if your platform defines DT_UNKNOWN but lacks
|
||||
# d_type in struct dirent (latest Cygwin -- will be fixed soonish).
|
||||
AC_CHECK_MEMBER(struct dirent.d_type,[],
|
||||
[GIT_CONF_APPEND_LINE(NO_D_TYPE_IN_DIRENT=YesPlease)],
|
||||
[#include <dirent.h>])
|
||||
#
|
||||
# Define NO_SOCKADDR_STORAGE if your platform does not have struct
|
||||
# sockaddr_storage.
|
||||
AC_CHECK_TYPE(struct sockaddr_storage,[],
|
||||
[GIT_CONF_APPEND_LINE(NO_SOCKADDR_STORAGE=YesPlease)],
|
||||
[#include <netinet/in.h>])
|
||||
|
||||
|
||||
## Checks for library functions.
|
||||
## (in default C library and libraries checked by AC_CHECK_LIB)
|
||||
AC_MSG_NOTICE([CHECKS for library functions])
|
||||
#
|
||||
# Define NO_STRCASESTR if you don't have strcasestr.
|
||||
AC_CHECK_FUNC(strcasestr,[],
|
||||
[GIT_CONF_APPEND_LINE(NO_STRCASESTR=YesPlease)])
|
||||
#
|
||||
# Define NO_STRLCPY if you don't have strlcpy.
|
||||
AC_CHECK_FUNC(strlcpy,[],
|
||||
[GIT_CONF_APPEND_LINE(NO_STRLCPY=YesPlease)])
|
||||
#
|
||||
# Define NO_SETENV if you don't have setenv in the C library.
|
||||
AC_CHECK_FUNC(setenv,[],
|
||||
[GIT_CONF_APPEND_LINE(NO_SETENV=YesPlease)])
|
||||
#
|
||||
# Define NO_MMAP if you want to avoid mmap.
|
||||
#
|
||||
# Define NO_IPV6 if you lack IPv6 support and getaddrinfo().
|
||||
#
|
||||
# Define NO_ICONV if your libc does not properly support iconv.
|
||||
|
||||
|
||||
## Other checks.
|
||||
# Define USE_PIC if you need the main git objects to be built with -fPIC
|
||||
# in order to build and link perl/Git.so. x86-64 seems to need this.
|
||||
#
|
||||
# Define NO_SYMLINK_HEAD if you never want .git/HEAD to be a symbolic link.
|
||||
# Enable it on Windows. By default, symrefs are still used.
|
||||
#
|
||||
# Define WITH_OWN_SUBPROCESS_PY if you want to use with python 2.3.
|
||||
#
|
||||
# Define NO_ACCURATE_DIFF if your diff program at least sometimes misses
|
||||
# a missing newline at the end of the file.
|
||||
|
||||
|
||||
## Site configuration
|
||||
## --with-PACKAGE[=ARG] and --without-PACKAGE
|
||||
# Define NO_SVN_TESTS if you want to skip time-consuming SVN interopability
|
||||
# tests. These tests take up a significant amount of the total test time
|
||||
# but are not needed unless you plan to talk to SVN repos.
|
||||
#
|
||||
# Define MOZILLA_SHA1 environment variable when running make to make use of
|
||||
# a bundled SHA1 routine coming from Mozilla. It is GPL'd and should be fast
|
||||
# on non-x86 architectures (e.g. PowerPC), while the OpenSSL version (default
|
||||
# choice) has very fast version optimized for i586.
|
||||
#
|
||||
# Define PPC_SHA1 environment variable when running make to make use of
|
||||
# a bundled SHA1 routine optimized for PowerPC.
|
||||
#
|
||||
# Define ARM_SHA1 environment variable when running make to make use of
|
||||
# a bundled SHA1 routine optimized for ARM.
|
||||
#
|
||||
# Define NO_OPENSSL environment variable if you do not have OpenSSL.
|
||||
# This also implies MOZILLA_SHA1.
|
||||
#
|
||||
# Define NO_CURL if you do not have curl installed. git-http-pull and
|
||||
# git-http-push are not built, and you cannot use http:// and https://
|
||||
# transports.
|
||||
#
|
||||
# Define CURLDIR=/foo/bar if your curl header and library files are in
|
||||
# /foo/bar/include and /foo/bar/lib directories.
|
||||
#
|
||||
# Define NO_EXPAT if you do not have expat installed. git-http-push is
|
||||
# not built, and you cannot push using http:// and https:// transports.
|
||||
#
|
||||
# Define NO_MMAP if you want to avoid mmap.
|
||||
#
|
||||
# Define NO_PYTHON if you want to loose all benefits of the recursive merge.
|
||||
#
|
||||
## --enable-FEATURE[=ARG] and --disable-FEATURE
|
||||
# Define COLLISION_CHECK below if you believe that SHA1's
|
||||
# 1461501637330902918203684832716283019655932542976 hashes do not give you
|
||||
# sufficient guarantee that no collisions between objects will ever happen.
|
||||
#
|
||||
# Define USE_NSEC below if you want git to care about sub-second file mtimes
|
||||
# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and
|
||||
# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely
|
||||
# randomly break unless your underlying filesystem supports those sub-second
|
||||
# times (my ext3 doesn't).
|
||||
#
|
||||
# Define USE_STDEV below if you want git to care about the underlying device
|
||||
# change being considered an inode change from the update-cache perspective.
|
||||
|
||||
|
||||
## Output files
|
||||
AC_CONFIG_FILES(["${config_file}":"${config_in}":"${config_append}"])
|
||||
AC_OUTPUT
|
||||
|
||||
|
||||
## Cleanup
|
||||
rm -f "${config_append}"
|
||||
35
connect.c
35
connect.c
@ -12,11 +12,40 @@
|
||||
|
||||
static char *server_capabilities = NULL;
|
||||
|
||||
static int check_ref(const char *name, int len, unsigned int flags)
|
||||
{
|
||||
if (!flags)
|
||||
return 1;
|
||||
|
||||
if (len > 45 || memcmp(name, "refs/", 5))
|
||||
return 0;
|
||||
|
||||
/* Skip the "refs/" part */
|
||||
name += 5;
|
||||
len -= 5;
|
||||
|
||||
/* REF_NORMAL means that we don't want the magic fake tag refs */
|
||||
if ((flags & REF_NORMAL) && check_ref_format(name) < 0)
|
||||
return 0;
|
||||
|
||||
/* REF_HEADS means that we want regular branch heads */
|
||||
if ((flags & REF_HEADS) && !memcmp(name, "heads/", 6))
|
||||
return 1;
|
||||
|
||||
/* REF_TAGS means that we want tags */
|
||||
if ((flags & REF_TAGS) && !memcmp(name, "tags/", 5))
|
||||
return 1;
|
||||
|
||||
/* All type bits clear means that we are ok with anything */
|
||||
return !(flags & ~REF_NORMAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read all the refs from the other end
|
||||
*/
|
||||
struct ref **get_remote_heads(int in, struct ref **list,
|
||||
int nr_match, char **match, int ignore_funny)
|
||||
int nr_match, char **match,
|
||||
unsigned int flags)
|
||||
{
|
||||
*list = NULL;
|
||||
for (;;) {
|
||||
@ -43,10 +72,8 @@ struct ref **get_remote_heads(int in, struct ref **list,
|
||||
server_capabilities = strdup(name + name_len + 1);
|
||||
}
|
||||
|
||||
if (ignore_funny && 45 < len && !memcmp(name, "refs/", 5) &&
|
||||
check_ref_format(name + 5))
|
||||
if (!check_ref(name, name_len, flags))
|
||||
continue;
|
||||
|
||||
if (nr_match && !path_match(name, nr_match, match))
|
||||
continue;
|
||||
ref = xcalloc(1, sizeof(*ref) + len - 40);
|
||||
|
||||
@ -110,7 +110,7 @@ foreach $config_file (@config_files) {
|
||||
}
|
||||
}
|
||||
|
||||
# colordiff specfic options here. Need to pre-declare if using variables
|
||||
# colordiff specific options here. Need to pre-declare if using variables
|
||||
GetOptions(
|
||||
"no-banner" => sub { $show_banner = 0 },
|
||||
"plain-text=s" => \&set_color,
|
||||
|
||||
@ -3,9 +3,9 @@
|
||||
EMACS = emacs
|
||||
|
||||
ELC = git.elc vc-git.elc
|
||||
INSTALL = install
|
||||
INSTALL ?= install
|
||||
INSTALL_ELC = $(INSTALL) -m 644
|
||||
prefix = $(HOME)
|
||||
prefix ?= $(HOME)
|
||||
emacsdir = $(prefix)/share/emacs/site-lisp
|
||||
|
||||
all: $(ELC)
|
||||
|
||||
@ -55,18 +55,21 @@
|
||||
;;;; ------------------------------------------------------------
|
||||
|
||||
(defgroup git nil
|
||||
"Git user interface")
|
||||
"A user interface for the git versioning system."
|
||||
:group 'tools)
|
||||
|
||||
(defcustom git-committer-name nil
|
||||
"User name to use for commits.
|
||||
The default is to fall back to the repository config, then to `add-log-full-name' and then to `user-full-name'."
|
||||
The default is to fall back to the repository config,
|
||||
then to `add-log-full-name' and then to `user-full-name'."
|
||||
:group 'git
|
||||
:type '(choice (const :tag "Default" nil)
|
||||
(string :tag "Name")))
|
||||
|
||||
(defcustom git-committer-email nil
|
||||
"Email address to use for commits.
|
||||
The default is to fall back to the git repository config, then to `add-log-mailing-address' and then to `user-mail-address'."
|
||||
The default is to fall back to the git repository config,
|
||||
then to `add-log-mailing-address' and then to `user-mail-address'."
|
||||
:group 'git
|
||||
:type '(choice (const :tag "Default" nil)
|
||||
(string :tag "Email")))
|
||||
@ -81,11 +84,18 @@ The default is to fall back to the git repository config, then to `add-log-maili
|
||||
:group 'git
|
||||
:type 'boolean)
|
||||
|
||||
(defcustom git-reuse-status-buffer t
|
||||
"Whether `git-status' should try to reuse an existing buffer
|
||||
if there is already one that displays the same directory."
|
||||
:group 'git
|
||||
:type 'boolean)
|
||||
|
||||
(defcustom git-per-dir-ignore-file ".gitignore"
|
||||
"Name of the per-directory ignore file."
|
||||
:group 'git
|
||||
:type 'string)
|
||||
|
||||
|
||||
(defface git-status-face
|
||||
'((((class color) (background light)) (:foreground "purple")))
|
||||
"Git mode face used to highlight added and modified files."
|
||||
@ -149,7 +159,8 @@ The default is to fall back to the git repository config, then to `add-log-maili
|
||||
(apply #'call-process "git" nil buffer nil args)))
|
||||
|
||||
(defun git-call-process-env-string (env &rest args)
|
||||
"Wrapper for call-process that sets environment strings, and returns the process output as a string."
|
||||
"Wrapper for call-process that sets environment strings,
|
||||
and returns the process output as a string."
|
||||
(with-temp-buffer
|
||||
(and (eq 0 (apply #' git-call-process-env t env args))
|
||||
(buffer-string))))
|
||||
@ -254,7 +265,7 @@ The default is to fall back to the git repository config, then to `add-log-maili
|
||||
(set-buffer (find-file-noselect ignore-name))
|
||||
(goto-char (point-max))
|
||||
(unless (zerop (current-column)) (insert "\n"))
|
||||
(insert name "\n")
|
||||
(insert "/" name "\n")
|
||||
(sort-lines nil (point-min) (point-max))
|
||||
(save-buffer))
|
||||
(when created
|
||||
@ -580,6 +591,8 @@ The default is to fall back to the git repository config, then to `add-log-maili
|
||||
(condition-case nil (delete-file ".git/MERGE_HEAD") (error nil))
|
||||
(with-current-buffer buffer (erase-buffer))
|
||||
(git-set-files-state files 'uptodate)
|
||||
(when (file-directory-p ".git/rr-cache")
|
||||
(git-run-command nil nil "rerere"))
|
||||
(git-refresh-files)
|
||||
(git-refresh-ewoc-hf git-status)
|
||||
(message "Committed %s." commit))
|
||||
@ -939,6 +952,8 @@ The default is to fall back to the git repository config, then to `add-log-maili
|
||||
(let ((map (make-keymap))
|
||||
(diff-map (make-sparse-keymap)))
|
||||
(suppress-keymap map)
|
||||
(define-key map "?" 'git-help)
|
||||
(define-key map "h" 'git-help)
|
||||
(define-key map " " 'git-next-file)
|
||||
(define-key map "a" 'git-add-file)
|
||||
(define-key map "c" 'git-commit-file)
|
||||
@ -995,12 +1010,28 @@ Commands:
|
||||
(set (make-local-variable 'list-buffers-directory) default-directory)
|
||||
(run-hooks 'git-status-mode-hook)))
|
||||
|
||||
(defun git-find-status-buffer (dir)
|
||||
"Find the git status buffer handling a specified directory."
|
||||
(let ((list (buffer-list))
|
||||
(fulldir (expand-file-name dir))
|
||||
found)
|
||||
(while (and list (not found))
|
||||
(let ((buffer (car list)))
|
||||
(with-current-buffer buffer
|
||||
(when (and list-buffers-directory
|
||||
(string-equal fulldir (expand-file-name list-buffers-directory))
|
||||
(string-match "\\*git-status\\*$" (buffer-name buffer)))
|
||||
(setq found buffer))))
|
||||
(setq list (cdr list)))
|
||||
found))
|
||||
|
||||
(defun git-status (dir)
|
||||
"Entry point into git-status mode."
|
||||
(interactive "DSelect directory: ")
|
||||
(setq dir (git-get-top-dir dir))
|
||||
(if (file-directory-p (concat (file-name-as-directory dir) ".git"))
|
||||
(let ((buffer (create-file-buffer (expand-file-name "*git-status*" dir))))
|
||||
(let ((buffer (or (and git-reuse-status-buffer (git-find-status-buffer dir))
|
||||
(create-file-buffer (expand-file-name "*git-status*" dir)))))
|
||||
(switch-to-buffer buffer)
|
||||
(cd dir)
|
||||
(git-status-mode)
|
||||
@ -1008,5 +1039,10 @@ Commands:
|
||||
(goto-char (point-min)))
|
||||
(message "%s is not a git working tree." dir)))
|
||||
|
||||
(defun git-help ()
|
||||
"Display help for Git mode."
|
||||
(interactive)
|
||||
(describe-function 'git-status-mode))
|
||||
|
||||
(provide 'git)
|
||||
;;; git.el ends here
|
||||
|
||||
@ -95,16 +95,17 @@
|
||||
"Register FILE into the git version-control system."
|
||||
(vc-git--run-command file "update-index" "--add" "--"))
|
||||
|
||||
(defun vc-git-print-log (file)
|
||||
(defun vc-git-print-log (file &optional buffer)
|
||||
(let ((name (file-relative-name file))
|
||||
(coding-system-for-read git-commits-coding-system))
|
||||
(vc-do-command nil 'async "git" name "rev-list" "--pretty" "HEAD" "--")))
|
||||
(vc-do-command buffer 'async "git" name "rev-list" "--pretty" "HEAD" "--")))
|
||||
|
||||
(defun vc-git-diff (file &optional rev1 rev2)
|
||||
(let ((name (file-relative-name file)))
|
||||
(defun vc-git-diff (file &optional rev1 rev2 buffer)
|
||||
(let ((name (file-relative-name file))
|
||||
(buf (or buffer "*vc-diff*")))
|
||||
(if (and rev1 rev2)
|
||||
(vc-do-command "*vc-diff*" 0 "git" name "diff-tree" "-p" rev1 rev2 "--")
|
||||
(vc-do-command "*vc-diff*" 0 "git" name "diff-index" "-p" (or rev1 "HEAD") "--"))
|
||||
(vc-do-command buf 0 "git" name "diff-tree" "-p" rev1 rev2 "--")
|
||||
(vc-do-command buf 0 "git" name "diff-index" "-p" (or rev1 "HEAD") "--"))
|
||||
; git-diff-index doesn't set exit status like diff does
|
||||
(if (vc-git-workfile-unchanged-p file) 0 1)))
|
||||
|
||||
|
||||
4
contrib/git-svn/.gitignore
vendored
4
contrib/git-svn/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
git-svn
|
||||
git-svn.xml
|
||||
git-svn.html
|
||||
git-svn.1
|
||||
@ -1,44 +0,0 @@
|
||||
all: git-svn
|
||||
|
||||
prefix?=$(HOME)
|
||||
bindir=$(prefix)/bin
|
||||
mandir=$(prefix)/man
|
||||
man1=$(mandir)/man1
|
||||
INSTALL?=install
|
||||
doc_conf=../../Documentation/asciidoc.conf
|
||||
-include ../../config.mak
|
||||
|
||||
git-svn: git-svn.perl
|
||||
cp $< $@
|
||||
chmod +x $@
|
||||
|
||||
install: all
|
||||
$(INSTALL) -d -m755 $(DESTDIR)$(bindir)
|
||||
$(INSTALL) git-svn $(DESTDIR)$(bindir)
|
||||
|
||||
install-doc: doc
|
||||
$(INSTALL) git-svn.1 $(DESTDIR)$(man1)
|
||||
|
||||
doc: git-svn.1
|
||||
git-svn.1 : git-svn.xml
|
||||
xmlto man git-svn.xml
|
||||
git-svn.xml : git-svn.txt
|
||||
asciidoc -b docbook -d manpage \
|
||||
-f ../../Documentation/asciidoc.conf $<
|
||||
git-svn.html : git-svn.txt
|
||||
asciidoc -b xhtml11 -d manpage \
|
||||
-f ../../Documentation/asciidoc.conf $<
|
||||
test: git-svn
|
||||
cd t && for i in t????-*.sh; do $(SHELL) ./$$i $(TEST_FLAGS); done
|
||||
|
||||
# we can test NO_OPTIMIZE_COMMITS independently of LC_ALL
|
||||
full-test:
|
||||
$(MAKE) test GIT_SVN_NO_LIB=1 GIT_SVN_NO_OPTIMIZE_COMMITS=1 LC_ALL=C
|
||||
$(MAKE) test GIT_SVN_NO_LIB=0 GIT_SVN_NO_OPTIMIZE_COMMITS=1 LC_ALL=C
|
||||
$(MAKE) test GIT_SVN_NO_LIB=1 GIT_SVN_NO_OPTIMIZE_COMMITS=0 \
|
||||
LC_ALL=en_US.UTF-8
|
||||
$(MAKE) test GIT_SVN_NO_LIB=0 GIT_SVN_NO_OPTIMIZE_COMMITS=0 \
|
||||
LC_ALL=en_US.UTF-8
|
||||
|
||||
clean:
|
||||
rm -f git-svn *.xml *.html *.1
|
||||
@ -1,45 +0,0 @@
|
||||
PATH=$PWD/../:$PATH
|
||||
if test -d ../../../t
|
||||
then
|
||||
cd ../../../t
|
||||
else
|
||||
echo "Must be run in contrib/git-svn/t" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
GIT_DIR=$PWD/.git
|
||||
GIT_SVN_DIR=$GIT_DIR/svn/git-svn
|
||||
SVN_TREE=$GIT_SVN_DIR/svn-tree
|
||||
|
||||
svnadmin >/dev/null 2>&1
|
||||
if test $? != 1
|
||||
then
|
||||
test_expect_success 'skipping contrib/git-svn test' :
|
||||
test_done
|
||||
exit
|
||||
fi
|
||||
|
||||
svn >/dev/null 2>&1
|
||||
if test $? != 1
|
||||
then
|
||||
test_expect_success 'skipping contrib/git-svn test' :
|
||||
test_done
|
||||
exit
|
||||
fi
|
||||
|
||||
svnrepo=$PWD/svnrepo
|
||||
|
||||
set -e
|
||||
|
||||
if svnadmin create --help | grep fs-type >/dev/null
|
||||
then
|
||||
svnadmin create --fs-type fsfs "$svnrepo"
|
||||
else
|
||||
svnadmin create "$svnrepo"
|
||||
fi
|
||||
|
||||
svnrepo="file://$svnrepo/test-git-svn"
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user