Merge with git://kernel.org/pub/scm/git/git.git

This commit is contained in:
Martin Langhoff
2006-05-08 10:03:37 +12:00
58 changed files with 2869 additions and 840 deletions

View File

@ -64,9 +64,11 @@ core.ignoreStat::
slow, such as Microsoft Windows. See gitlink:git-update-index[1]. slow, such as Microsoft Windows. See gitlink:git-update-index[1].
False by default. False by default.
core.onlyUseSymrefs:: core.preferSymlinkRefs::
Always use the "symref" format instead of symbolic links for HEAD Instead of the default "symref" format for HEAD
and other symbolic reference files. True by default. and other symbolic reference files, use symbolic links.
This is sometimes needed to work with old scripts that
expect HEAD to be a symbolic link.
core.repositoryFormatVersion:: core.repositoryFormatVersion::
Internal variable identifying the repository format and layout Internal variable identifying the repository format and layout

View File

@ -26,7 +26,7 @@ OPTIONS
-v:: -v::
Be verbose. Be verbose.
--:: \--::
This option can be used to separate command-line options from This option can be used to separate command-line options from
the list of files, (useful when filenames might be mistaken the list of files, (useful when filenames might be mistaken
for command-line options). for command-line options).

View File

@ -63,7 +63,7 @@ OPTIONS
Only meaningful with `--stdin`; paths are separated with Only meaningful with `--stdin`; paths are separated with
NUL character instead of LF. NUL character instead of LF.
--:: \--::
Do not interpret any more arguments as options. Do not interpret any more arguments as options.
The order of the flags used to matter, but not anymore. The order of the flags used to matter, but not anymore.

View File

@ -11,11 +11,20 @@ SYNOPSIS
DESCRIPTION DESCRIPTION
----------- -----------
Each commit between the fork-point and <head> is examined, and compared against The changeset (or "diff") of each commit between the fork-point and <head>
the change each commit between the fork-point and <upstream> introduces. is compared against each commit between the fork-point and <upstream>.
Commits already included in upstream are prefixed with '-' (meaning "drop from
my local pull"), while commits missing from upstream are prefixed with '+' Every commit with a changeset that doesn't exist in the other branch
(meaning "add to the updated upstream"). has its id (sha1) reported, prefixed by a symbol. Those existing only
in the <upstream> branch are prefixed with a minus (-) sign, and those
that only exist in the <head> branch are prefixed with a plus (+) symbol.
Because git-cherry compares the changeset rather than the commit id
(sha1), you can use git-cherry to find out if a commit you made locally
has been applied <upstream> under a different commit id. For example,
this will happen if you're feeding patches <upstream> via email rather
than pushing or pulling commits directly.
OPTIONS OPTIONS
------- -------

View File

@ -101,7 +101,7 @@ OPTIONS
is not allowed. is not allowed.
Examples Examples
~~~~~~~~ --------
Clone from upstream:: Clone from upstream::
+ +

View File

@ -106,7 +106,7 @@ but can be used to amend a merge commit.
index and the latest commit does not match on the index and the latest commit does not match on the
specified paths to avoid confusion. specified paths to avoid confusion.
--:: \--::
Do not interpret any more arguments as options. Do not interpret any more arguments as options.
<file>...:: <file>...::

View File

@ -7,13 +7,23 @@ git-count-objects - Reports on unpacked objects
SYNOPSIS SYNOPSIS
-------- --------
'git-count-objects' 'git-count-objects' [-v]
DESCRIPTION DESCRIPTION
----------- -----------
This counts the number of unpacked object files and disk space consumed by This counts the number of unpacked object files and disk space consumed by
them, to help you decide when it is a good time to repack. them, to help you decide when it is a good time to repack.
OPTIONS
-------
-v::
In addition to the number of loose objects and disk
space consumed, it reports the number of in-pack
objects, and number of objects that can be removed by
running `git-prune-packed`.
Author Author
------ ------
Written by Junio C Hamano <junkio@cox.net> Written by Junio C Hamano <junkio@cox.net>

View File

@ -92,7 +92,7 @@ separated with a single space are given.
Furthermore, it lists only files which were modified Furthermore, it lists only files which were modified
from all parents. from all parents.
-cc:: --cc::
This flag changes the way a merge commit patch is displayed, This flag changes the way a merge commit patch is displayed,
in a similar way to the '-c' option. It implies the '-c' in a similar way to the '-c' option. It implies the '-c'
and '-p' options and further compresses the patch output and '-p' options and further compresses the patch output

View File

@ -29,6 +29,7 @@ CONFIGURATION
git-imap-send requires the following values in the repository git-imap-send requires the following values in the repository
configuration file (shown with examples): configuration file (shown with examples):
..........................
[imap] [imap]
Folder = "INBOX.Drafts" Folder = "INBOX.Drafts"
@ -38,8 +39,9 @@ configuration file (shown with examples):
[imap] [imap]
Host = imap.server.com Host = imap.server.com
User = bob User = bob
Password = pwd Pass = pwd
Port = 143 Port = 143
..........................
BUGS BUGS

View File

@ -51,7 +51,7 @@ git log v2.6.12.. include/scsi drivers/scsi::
Show all commits since version 'v2.6.12' that changed any file Show all commits since version 'v2.6.12' that changed any file
in the include/scsi or drivers/scsi subdirectories in the include/scsi or drivers/scsi subdirectories
git log --since="2 weeks ago" -- gitk:: git log --since="2 weeks ago" \-- gitk::
Show the changes during the last two weeks to the file 'gitk'. Show the changes during the last two weeks to the file 'gitk'.
The "--" is necessary to avoid confusion with the *branch* named The "--" is necessary to avoid confusion with the *branch* named

View File

@ -106,7 +106,7 @@ OPTIONS
lines, show only handful hexdigits prefix. lines, show only handful hexdigits prefix.
Non default number of digits can be specified with --abbrev=<n>. Non default number of digits can be specified with --abbrev=<n>.
--:: \--::
Do not interpret any more arguments as options. Do not interpret any more arguments as options.
<file>:: <file>::

View File

@ -8,7 +8,7 @@ git-merge-index - Runs a merge for files needing merging
SYNOPSIS SYNOPSIS
-------- --------
'git-merge-index' [-o] [-q] <merge-program> (-a | -- | <file>\*) 'git-merge-index' [-o] [-q] <merge-program> (-a | \-- | <file>\*)
DESCRIPTION DESCRIPTION
----------- -----------
@ -19,7 +19,7 @@ files are passed as arguments 5, 6 and 7.
OPTIONS OPTIONS
------- -------
--:: \--::
Do not interpret any more arguments as options. Do not interpret any more arguments as options.
-a:: -a::

View File

@ -41,6 +41,7 @@ Enter git-name-rev:
------------ ------------
% git name-rev 33db5f4d9027a10e477ccf054b2c1ab94f74c85a % git name-rev 33db5f4d9027a10e477ccf054b2c1ab94f74c85a
33db5f4d9027a10e477ccf054b2c1ab94f74c85a tags/v0.99^0~940
------------ ------------
Now you are wiser, because you know that it happened 940 revisions before v0.99. Now you are wiser, because you know that it happened 940 revisions before v0.99.

View File

@ -28,7 +28,7 @@ OPTIONS
Do not remove anything; just report what it would Do not remove anything; just report what it would
remove. remove.
--:: \--::
Do not interpret any more arguments as options. Do not interpret any more arguments as options.
<head>...:: <head>...::

View File

@ -38,6 +38,7 @@ OPTIONS
-d:: -d::
After packing, if the newly created packs make some After packing, if the newly created packs make some
existing packs redundant, remove the redundant packs. existing packs redundant, remove the redundant packs.
Also runs gitlink:git-prune-packed[1].
-l:: -l::
Pass the `--local` option to `git pack-objects`, see Pass the `--local` option to `git pack-objects`, see

View File

@ -34,10 +34,10 @@ convert the value to the canonical form (simple decimal number for int,
a "true" or "false" string for bool). If no type specifier is passed, a "true" or "false" string for bool). If no type specifier is passed,
no checks or transformations are performed on the value. no checks or transformations are performed on the value.
This command will fail if This command will fail if:
. .git/config is invalid, . The .git/config file is invalid,
. .git/config can not be written to, . Can not write to .git/config,
. no section was provided, . no section was provided,
. the section or key is invalid, . the section or key is invalid,
. you try to unset an option which does not exist, or . you try to unset an option which does not exist, or
@ -49,7 +49,7 @@ OPTIONS
--replace-all:: --replace-all::
Default behaviour is to replace at most one line. This replaces Default behaviour is to replace at most one line. This replaces
all lines matching the key (and optionally the value_regex) all lines matching the key (and optionally the value_regex).
--get:: --get::
Get the value for a given key (optionally filtered by a regex Get the value for a given key (optionally filtered by a regex
@ -59,6 +59,9 @@ OPTIONS
Like get, but does not fail if the number of values for the key Like get, but does not fail if the number of values for the key
is not exactly one. is not exactly one.
--get-regexp::
Like --get-all, but interprets the name as a regular expression.
--unset:: --unset::
Remove the line matching the key from .git/config. Remove the line matching the key from .git/config.

View File

@ -43,7 +43,7 @@ OPTIONS
Commit to make the current HEAD. Commit to make the current HEAD.
Examples Examples
~~~~~~~~ --------
Undo a commit and redo:: Undo a commit and redo::
+ +

View File

@ -32,7 +32,7 @@ OPTIONS
-v:: -v::
Be verbose. Be verbose.
--:: \--::
This option can be used to separate command-line options from This option can be used to separate command-line options from
the list of files, (useful when filenames might be mistaken the list of files, (useful when filenames might be mistaken
for command-line options). for command-line options).

View File

@ -13,9 +13,16 @@ SYNOPSIS
DESCRIPTION DESCRIPTION
----------- -----------
Reads a packed archive (.pack) from the standard input, and Read a packed archive (.pack) from the standard input, expanding
expands the objects contained in the pack into "one-file the objects contained within and writing them into the repository in
one-object" format in $GIT_OBJECT_DIRECTORY. "loose" (one object per file) format.
Objects that already exist in the repository will *not* be unpacked
from the pack-file. Therefore, nothing will be unpacked if you use
this command on a pack-file that exists within the target repository.
Please see the `git-repack` documentation for options to generate
new packs and replace existing ones.
OPTIONS OPTIONS
------- -------

View File

@ -10,12 +10,12 @@ SYNOPSIS
-------- --------
[verse] [verse]
'git-update-index' 'git-update-index'
[--add] [--remove | --force-remove] [--replace] [--add] [--remove | --force-remove] [--replace]
[--refresh [-q] [--unmerged] [--ignore-missing]] [--refresh] [-q] [--unmerged] [--ignore-missing]
[--cacheinfo <mode> <object> <file>]\* [--cacheinfo <mode> <object> <file>]\*
[--chmod=(+|-)x] [--chmod=(+|-)x]
[--assume-unchanged | --no-assume-unchanged] [--assume-unchanged | --no-assume-unchanged]
[--really-refresh] [--really-refresh] [--unresolve]
[--info-only] [--index-info] [--info-only] [--index-info]
[-z] [--stdin] [-z] [--stdin]
[--verbose] [--verbose]
@ -80,6 +80,10 @@ OPTIONS
filesystem that has very slow lstat(2) system call filesystem that has very slow lstat(2) system call
(e.g. cifs). (e.g. cifs).
--unresolve::
Restores the 'unmerged' or 'needs updating' state of a
file during a merge if it was cleared by accident.
--info-only:: --info-only::
Do not create objects in the object database for all Do not create objects in the object database for all
<file> arguments that follow this flag; just insert <file> arguments that follow this flag; just insert
@ -109,7 +113,7 @@ OPTIONS
Only meaningful with `--stdin`; paths are separated with Only meaningful with `--stdin`; paths are separated with
NUL character instead of LF. NUL character instead of LF.
--:: \--::
Do not interpret any more arguments as options. Do not interpret any more arguments as options.
<file>:: <file>::

View File

@ -25,7 +25,7 @@ OPTIONS
-v:: -v::
After verifying the pack, show list of objects contained After verifying the pack, show list of objects contained
in the pack. in the pack.
--:: \--::
Do not interpret any more arguments as options. Do not interpret any more arguments as options.
OUTPUT FORMAT OUTPUT FORMAT

View File

@ -58,7 +58,7 @@ git-whatchanged -p v2.6.12.. include/scsi drivers/scsi::
Show as patches the commits since version 'v2.6.12' that changed Show as patches the commits since version 'v2.6.12' that changed
any file in the include/scsi or drivers/scsi subdirectories any file in the include/scsi or drivers/scsi subdirectories
git-whatchanged --since="2 weeks ago" -- gitk:: git-whatchanged --since="2 weeks ago" \-- gitk::
Show the changes during the last two weeks to the file 'gitk'. Show the changes during the last two weeks to the file 'gitk'.
The "--" is necessary to avoid confusion with the *branch* named The "--" is necessary to avoid confusion with the *branch* named

View File

@ -31,7 +31,7 @@ gitk v2.6.12.. include/scsi drivers/scsi::
Show as the changes since version 'v2.6.12' that changed any Show as the changes since version 'v2.6.12' that changed any
file in the include/scsi or drivers/scsi subdirectories file in the include/scsi or drivers/scsi subdirectories
gitk --since="2 weeks ago" -- gitk:: gitk --since="2 weeks ago" \-- gitk::
Show the changes during the last two weeks to the file 'gitk'. Show the changes during the last two weeks to the file 'gitk'.
The "--" is necessary to avoid confusion with the *branch* named The "--" is necessary to avoid confusion with the *branch* named

View File

@ -1,39 +1,71 @@
object:: alternate object database::
The unit of storage in git. It is uniquely identified by Via the alternates mechanism, a repository can inherit part of its
the SHA1 of its contents. Consequently, an object can not object database from another object database, which is called
be changed. "alternate".
object name:: bare repository::
The unique identifier of an object. The hash of the object's contents A bare repository is normally an appropriately named
using the Secure Hash Algorithm 1 and usually represented by the 40 directory with a `.git` suffix that does not have a
character hexadecimal encoding of the hash of the object (possibly locally checked-out copy of any of the files under revision
followed by a white space). control. That is, all of the `git` administrative and
control files that would normally be present in the
SHA1:: hidden `.git` sub-directory are directly present in
Synonym for object name. the `repository.git` directory instead, and no other files
are present and checked out. Usually publishers of public
object identifier:: repositories make bare repositories available.
Synonym for object name.
hash::
In git's context, synonym to object name.
object database::
Stores a set of "objects", and an individual object is identified
by its object name. The objects usually live in `$GIT_DIR/objects/`.
blob object:: blob object::
Untyped object, e.g. the contents of a file. Untyped object, e.g. the contents of a file.
tree object:: branch::
An object containing a list of file names and modes along with refs A non-cyclical graph of revisions, i.e. the complete history of
to the associated blob and/or tree objects. A tree is equivalent a particular revision, which is called the branch head. The
to a directory. branch heads are stored in `$GIT_DIR/refs/heads/`.
tree:: cache::
Either a working tree, or a tree object together with the Obsolete for: index.
dependent blob and tree objects (i.e. a stored representation
of a working tree). chain::
A list of objects, where each object in the list contains a
reference to its successor (for example, the successor of a commit
could be one of its parents).
changeset::
BitKeeper/cvsps speak for "commit". Since git does not store
changes, but states, it really does not make sense to use
the term "changesets" with git.
checkout::
The action of updating the working tree to a revision which was
stored in the object database.
cherry-picking::
In SCM jargon, "cherry pick" means to choose a subset of
changes out of a series of changes (typically commits)
and record them as a new series of changes on top of
different codebase. In GIT, this is performed by
"git cherry-pick" command to extract the change
introduced by an existing commit and to record it based
on the tip of the current branch as a new commit.
clean::
A working tree is clean, if it corresponds to the revision
referenced by the current head. Also see "dirty".
commit::
As a verb: The action of storing the current state of the index in the
object database. The result is a revision.
As a noun: Short hand for commit object.
commit object::
An object which contains the information about a particular
revision, such as parents, committer, author, date and the
tree object which corresponds to the top directory of the
stored revision.
core git::
Fundamental data structures and utilities of git. Exposes only
limited source code management tools.
DAG:: DAG::
Directed acyclic graph. The commit objects form a directed acyclic Directed acyclic graph. The commit objects form a directed acyclic
@ -41,6 +73,63 @@ DAG::
objects is acyclic (there is no chain which begins and ends with the objects is acyclic (there is no chain which begins and ends with the
same object). same object).
dircache::
You are *waaaaay* behind.
dirty::
A working tree is said to be dirty if it contains modifications
which have not been committed to the current branch.
directory::
The list you get with "ls" :-)
ent::
Favorite synonym to "tree-ish" by some total geeks. See
`http://en.wikipedia.org/wiki/Ent_(Middle-earth)` for an in-depth
explanation.
fast forward::
A fast-forward is a special type of merge where you have
a revision and you are "merging" another branch's changes
that happen to be a descendant of what you have.
In such these cases, you do not make a new merge commit but
instead just update to his revision. This will happen
frequently on a tracking branch of a remote repository.
fetch::
Fetching a branch means to get the branch's head ref from a
remote repository, to find out which objects are missing from
the local object database, and to get them, too.
file system::
Linus Torvalds originally designed git to be a user space file
system, i.e. the infrastructure to hold files and directories.
That ensured the efficiency and speed of git.
git archive::
Synonym for repository (for arch people).
hash::
In git's context, synonym to object name.
head::
The top of a branch. It contains a ref to the corresponding
commit object.
head ref::
A ref pointing to a head. Often, this is abbreviated to "head".
Head refs are stored in `$GIT_DIR/refs/heads/`.
hook::
During the normal execution of several git commands,
call-outs are made to optional scripts that allow
a developer to add functionality or checking.
Typically, the hooks allow for a command to be pre-verified
and potentially aborted, and allow for a post-notification
after the operation is done.
The hook scripts are found in the `$GIT_DIR/hooks/` directory,
and are enabled by simply making them executable.
index:: index::
A collection of files with stat information, whose contents are A collection of files with stat information, whose contents are
stored as objects. The index is a stored version of your working stored as objects. The index is a stored version of your working
@ -53,92 +142,167 @@ index entry::
yet finished (i.e. if the index contains multiple versions of yet finished (i.e. if the index contains multiple versions of
that file). that file).
unmerged index: master::
An index which contains unmerged index entries. The default development branch. Whenever you create a git
repository, a branch named "master" is created, and becomes
the active branch. In most cases, this contains the local
development, though that is purely conventional and not required.
cache:: merge::
Obsolete for: index. To merge branches means to try to accumulate the changes since a
common ancestor and apply them to the first branch. An automatic
merge uses heuristics to accomplish that. Evidently, an automatic
merge can fail.
working tree:: object::
The set of files and directories currently being worked on, The unit of storage in git. It is uniquely identified by
i.e. you can work in your working tree without using git at all. the SHA1 of its contents. Consequently, an object can not
be changed.
directory:: object database::
The list you get with "ls" :-) Stores a set of "objects", and an individual object is identified
by its object name. The objects usually live in `$GIT_DIR/objects/`.
revision:: object identifier::
A particular state of files and directories which was stored in Synonym for object name.
the object database. It is referenced by a commit object.
checkout:: object name::
The action of updating the working tree to a revision which was The unique identifier of an object. The hash of the object's contents
stored in the object database. using the Secure Hash Algorithm 1 and usually represented by the 40
character hexadecimal encoding of the hash of the object (possibly
followed by a white space).
commit:: object type:
As a verb: The action of storing the current state of the index in the One of the identifiers "commit","tree","tag" and "blob" describing
object database. The result is a revision. the type of an object.
As a noun: Short hand for commit object.
commit object:: octopus::
An object which contains the information about a particular To merge more than two branches. Also denotes an intelligent
revision, such as parents, committer, author, date and the predator.
tree object which corresponds to the top directory of the
stored revision. origin::
The default upstream tracking branch. Most projects have at
least one upstream project which they track. By default
'origin' is used for that purpose. New upstream updates
will be fetched into this branch; you should never commit
to it yourself.
pack::
A set of objects which have been compressed into one file (to save
space or to transmit them efficiently).
pack index::
The list of identifiers, and other information, of the objects in a
pack, to assist in efficiently accessing the contents of a pack.
parent:: parent::
A commit object contains a (possibly empty) list of the logical A commit object contains a (possibly empty) list of the logical
predecessor(s) in the line of development, i.e. its parents. predecessor(s) in the line of development, i.e. its parents.
changeset:: pickaxe::
BitKeeper/cvsps speak for "commit". Since git does not store The term pickaxe refers to an option to the diffcore routines
changes, but states, it really does not make sense to use that help select changes that add or delete a given text string.
the term "changesets" with git. With the --pickaxe-all option, it can be used to view the
full changeset that introduced or removed, say, a particular
line of text. See gitlink:git-diff[1].
clean:: plumbing::
A working tree is clean, if it corresponds to the revision Cute name for core git.
referenced by the current head.
dirty:: porcelain::
A working tree is said to be dirty if it contains modifications Cute name for programs and program suites depending on core git,
which have not been committed to the current branch. presenting a high level access to core git. Porcelains expose
more of a SCM interface than the plumbing.
head:: pull::
The top of a branch. It contains a ref to the corresponding Pulling a branch means to fetch it and merge it.
commit object.
branch:: push::
A non-cyclical graph of revisions, i.e. the complete history of Pushing a branch means to get the branch's head ref from a remote
a particular revision, which is called the branch head. The repository, find out if it is an ancestor to the branch's local
branch heads are stored in `$GIT_DIR/refs/heads/`. head ref is a direct, and in that case, putting all objects, which
are reachable from the local head ref, and which are missing from
the remote repository, into the remote object database, and updating
the remote head ref. If the remote head is not an ancestor to the
local head, the push fails.
master:: reachable::
The default branch. Whenever you create a git repository, a branch An object is reachable from a ref/commit/tree/tag, if there is a
named "master" is created, and becomes the active branch. In most chain leading from the latter to the former.
cases, this contains the local development.
origin:: rebase::
The default upstream branch. Most projects have one upstream To clean a branch by starting from the head of the main line of
project which they track, and by default 'origin' is used for development ("master"), and reapply the (possibly cherry-picked)
that purpose. New updates from upstream will be fetched into changes from that branch.
this branch; you should never commit to it yourself.
ref:: ref::
A 40-byte hex representation of a SHA1 pointing to a particular A 40-byte hex representation of a SHA1 or a name that denotes
object. These may be stored in `$GIT_DIR/refs/`. a particular object. These may be stored in `$GIT_DIR/refs/`.
head ref:: refspec::
A ref pointing to a head. Often, this is abbreviated to "head". A refspec is used by fetch and push to describe the mapping
Head refs are stored in `$GIT_DIR/refs/heads/`. between remote ref and local ref. They are combined with
a colon in the format <src>:<dst>, preceded by an optional
plus sign, +. For example:
`git fetch $URL refs/heads/master:refs/heads/origin`
means "grab the master branch head from the $URL and store
it as my origin branch head".
And `git push $URL refs/heads/master:refs/heads/to-upstream`
means "publish my master branch head as to-upstream master head
at $URL". See also gitlink:git-push[1]
repository::
A collection of refs together with an object database containing
all objects, which are reachable from the refs, possibly accompanied
by meta data from one or more porcelains. A repository can
share an object database with other repositories.
resolve::
The action of fixing up manually what a failed automatic merge
left behind.
revision::
A particular state of files and directories which was stored in
the object database. It is referenced by a commit object.
rewind::
To throw away part of the development, i.e. to assign the head to
an earlier revision.
SCM::
Source code management (tool).
SHA1::
Synonym for object name.
topic branch::
A regular git branch that is used by a developer to
identify a conceptual line of development. Since branches
are very easy and inexpensive, it is often desirable to
have several small branches that each contain very well
defined concepts or small incremental yet related changes.
tracking branch::
A regular git branch that is used to follow changes from
another repository. A tracking branch should not contain
direct modifications or have local commits made to it.
A tracking branch can usually be identified as the
right-hand-side ref in a Pull: refspec.
tree object::
An object containing a list of file names and modes along with refs
to the associated blob and/or tree objects. A tree is equivalent
to a directory.
tree::
Either a working tree, or a tree object together with the
dependent blob and tree objects (i.e. a stored representation
of a working tree).
tree-ish:: tree-ish::
A ref pointing to either a commit object, a tree object, or a A ref pointing to either a commit object, a tree object, or a
tag object pointing to a tag or commit or tree object. tag object pointing to a tag or commit or tree object.
ent::
Favorite synonym to "tree-ish" by some total geeks. See
`http://en.wikipedia.org/wiki/Ent_(Middle-earth)` for an in-depth
explanation.
tag object:: tag object::
An object containing a ref pointing to another object, which can An object containing a ref pointing to another object, which can
contain a message just like a commit object. It can also contain a message just like a commit object. It can also
@ -153,101 +317,10 @@ tag::
A tag is most typically used to mark a particular point in the A tag is most typically used to mark a particular point in the
commit ancestry chain. commit ancestry chain.
merge:: unmerged index:
To merge branches means to try to accumulate the changes since a An index which contains unmerged index entries.
common ancestor and apply them to the first branch. An automatic
merge uses heuristics to accomplish that. Evidently, an automatic
merge can fail.
octopus:: working tree::
To merge more than two branches. Also denotes an intelligent The set of files and directories currently being worked on,
predator. i.e. you can work in your working tree without using git at all.
resolve::
The action of fixing up manually what a failed automatic merge
left behind.
rewind::
To throw away part of the development, i.e. to assign the head to
an earlier revision.
rebase::
To clean a branch by starting from the head of the main line of
development ("master"), and reapply the (possibly cherry-picked)
changes from that branch.
repository::
A collection of refs together with an object database containing
all objects, which are reachable from the refs, possibly accompanied
by meta data from one or more porcelains. A repository can
share an object database with other repositories.
git archive::
Synonym for repository (for arch people).
file system::
Linus Torvalds originally designed git to be a user space file
system, i.e. the infrastructure to hold files and directories.
That ensured the efficiency and speed of git.
alternate object database::
Via the alternates mechanism, a repository can inherit part of its
object database from another object database, which is called
"alternate".
reachable::
An object is reachable from a ref/commit/tree/tag, if there is a
chain leading from the latter to the former.
chain::
A list of objects, where each object in the list contains a
reference to its successor (for example, the successor of a commit
could be one of its parents).
fetch::
Fetching a branch means to get the branch's head ref from a
remote repository, to find out which objects are missing from
the local object database, and to get them, too.
pull::
Pulling a branch means to fetch it and merge it.
push::
Pushing a branch means to get the branch's head ref from a remote
repository, find out if it is an ancestor to the branch's local
head ref is a direct, and in that case, putting all objects, which
are reachable from the local head ref, and which are missing from
the remote repository, into the remote object database, and updating
the remote head ref. If the remote head is not an ancestor to the
local head, the push fails.
pack::
A set of objects which have been compressed into one file (to save
space or to transmit them efficiently).
pack index::
The list of identifiers, and other information, of the objects in a
pack, to assist in efficiently accessing the contents of a pack.
core git::
Fundamental data structures and utilities of git. Exposes only
limited source code management tools.
plumbing::
Cute name for core git.
porcelain::
Cute name for programs and program suites depending on core git,
presenting a high level access to core git. Porcelains expose
more of a SCM interface than the plumbing.
object type:
One of the identifiers "commit","tree","tag" and "blob" describing
the type of an object.
SCM::
Source code management (tool).
dircache::
You are *waaaaay* behind.

View File

@ -48,7 +48,7 @@ This list is sorted alphabetically:
'; ';
@keys=sort {uc($a) cmp uc($b)} keys %terms; @keys=sort {uc($a) cmp uc($b)} keys %terms;
$pattern='(\b'.join('\b|\b',reverse @keys).'\b)'; $pattern='(\b(?<!link:git-)'.join('\b|\b(?<!link:git-)',reverse @keys).'\b)';
foreach $key (@keys) { foreach $key (@keys) {
$terms{$key}=~s/$pattern/sprintf "<<ref_".no_spaces($1).",$1>>";/eg; $terms{$key}=~s/$pattern/sprintf "<<ref_".no_spaces($1).",$1>>";/eg;
print '[[ref_'.no_spaces($key).']]'.$key."::\n" print '[[ref_'.no_spaces($key).']]'.$key."::\n"

View File

@ -28,8 +28,8 @@ all:
# #
# Define NO_SETENV if you don't have setenv in the C library. # Define NO_SETENV if you don't have setenv in the C library.
# #
# Define USE_SYMLINK_HEAD if you want .git/HEAD to be a symbolic link. # Define NO_SYMLINK_HEAD if you never want .git/HEAD to be a symbolic link.
# Don't enable it on Windows. # Enable it on Windows. By default, symrefs are still used.
# #
# Define PPC_SHA1 environment variable when running make to make use of # Define PPC_SHA1 environment variable when running make to make use of
# a bundled SHA1 routine optimized for PowerPC. # a bundled SHA1 routine optimized for PowerPC.
@ -115,13 +115,13 @@ SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
SCRIPT_SH = \ SCRIPT_SH = \
git-add.sh git-bisect.sh git-branch.sh git-checkout.sh \ git-add.sh git-bisect.sh git-branch.sh git-checkout.sh \
git-cherry.sh git-clean.sh git-clone.sh git-commit.sh \ git-cherry.sh git-clean.sh git-clone.sh git-commit.sh \
git-count-objects.sh git-diff.sh git-fetch.sh \ git-fetch.sh \
git-format-patch.sh git-ls-remote.sh \ git-format-patch.sh git-ls-remote.sh \
git-merge-one-file.sh git-parse-remote.sh \ git-merge-one-file.sh git-parse-remote.sh \
git-prune.sh git-pull.sh git-push.sh git-rebase.sh \ git-prune.sh git-pull.sh git-rebase.sh \
git-repack.sh git-request-pull.sh git-reset.sh \ git-repack.sh git-request-pull.sh git-reset.sh \
git-resolve.sh git-revert.sh git-rm.sh git-sh-setup.sh \ git-resolve.sh git-revert.sh git-rm.sh git-sh-setup.sh \
git-tag.sh git-verify-tag.sh git-whatchanged.sh \ git-tag.sh git-verify-tag.sh \
git-applymbox.sh git-applypatch.sh git-am.sh \ git-applymbox.sh git-applypatch.sh git-am.sh \
git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \ git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \
git-merge-resolve.sh git-merge-ours.sh git-grep.sh \ git-merge-resolve.sh git-merge-ours.sh git-grep.sh \
@ -139,7 +139,7 @@ SCRIPT_PYTHON = \
SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \ SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
$(patsubst %.perl,%,$(SCRIPT_PERL)) \ $(patsubst %.perl,%,$(SCRIPT_PERL)) \
$(patsubst %.py,%,$(SCRIPT_PYTHON)) \ $(patsubst %.py,%,$(SCRIPT_PYTHON)) \
git-cherry-pick git-show git-status git-cherry-pick git-status
# The ones that do not have to link with lcrypto, lz nor xdiff. # The ones that do not have to link with lcrypto, lz nor xdiff.
SIMPLE_PROGRAMS = \ SIMPLE_PROGRAMS = \
@ -167,7 +167,8 @@ PROGRAMS = \
git-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X \ git-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X \
git-describe$X git-merge-tree$X git-blame$X git-imap-send$X git-describe$X git-merge-tree$X git-blame$X git-imap-send$X
BUILT_INS = git-log$X BUILT_INS = git-log$X git-whatchanged$X git-show$X \
git-count-objects$X git-diff$X git-push$X
# what 'all' will build and 'install' will install, in gitexecdir # what 'all' will build and 'install' will install, in gitexecdir
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS) ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
@ -214,7 +215,7 @@ LIB_OBJS = \
$(DIFF_OBJS) $(DIFF_OBJS)
BUILTIN_OBJS = \ BUILTIN_OBJS = \
builtin-log.o builtin-help.o builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB) GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
LIBS = $(GITLIBS) -lz LIBS = $(GITLIBS) -lz
@ -263,6 +264,7 @@ ifeq ($(uname_O),Cygwin)
NO_D_TYPE_IN_DIRENT = YesPlease NO_D_TYPE_IN_DIRENT = YesPlease
NO_D_INO_IN_DIRENT = YesPlease NO_D_INO_IN_DIRENT = YesPlease
NO_STRCASESTR = YesPlease NO_STRCASESTR = YesPlease
NO_SYMLINK_HEAD = YesPlease
NEEDS_LIBICONV = YesPlease NEEDS_LIBICONV = YesPlease
# There are conflicting reports about this. # There are conflicting reports about this.
# On some boxes NO_MMAP is needed, and not so elsewhere. # On some boxes NO_MMAP is needed, and not so elsewhere.
@ -386,6 +388,9 @@ endif
ifdef NO_D_INO_IN_DIRENT ifdef NO_D_INO_IN_DIRENT
ALL_CFLAGS += -DNO_D_INO_IN_DIRENT ALL_CFLAGS += -DNO_D_INO_IN_DIRENT
endif endif
ifdef NO_SYMLINK_HEAD
ALL_CFLAGS += -DNO_SYMLINK_HEAD
endif
ifdef NO_STRCASESTR ifdef NO_STRCASESTR
COMPAT_CFLAGS += -DNO_STRCASESTR COMPAT_CFLAGS += -DNO_STRCASESTR
COMPAT_OBJS += compat/strcasestr.o COMPAT_OBJS += compat/strcasestr.o
@ -505,9 +510,6 @@ $(patsubst %.py,%,$(SCRIPT_PYTHON)) : % : %.py
git-cherry-pick: git-revert git-cherry-pick: git-revert
cp $< $@ cp $< $@
git-show: git-whatchanged
cp $< $@
git-status: git-commit git-status: git-commit
cp $< $@ cp $< $@
@ -562,10 +564,6 @@ git-http-push$X: revision.o http.o http-push.o $(LIB_FILE)
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
git-rev-list$X: rev-list.o $(LIB_FILE)
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(LIBS) $(OPENSSL_LIBSSL)
init-db.o: init-db.c init-db.o: init-db.c
$(CC) -c $(ALL_CFLAGS) \ $(CC) -c $(ALL_CFLAGS) \
-DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $*.c -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $*.c

10
blame.c
View File

@ -515,9 +515,9 @@ static int compare_tree_path(struct rev_info* revs,
paths[1] = NULL; paths[1] = NULL;
diff_tree_setup_paths(get_pathspec(revs->prefix, paths), diff_tree_setup_paths(get_pathspec(revs->prefix, paths),
&revs->diffopt); &revs->pruning);
ret = rev_compare_tree(revs, c1->tree, c2->tree); ret = rev_compare_tree(revs, c1->tree, c2->tree);
diff_tree_release_paths(&revs->diffopt); diff_tree_release_paths(&revs->pruning);
return ret; return ret;
} }
@ -531,9 +531,9 @@ static int same_tree_as_empty_path(struct rev_info *revs, struct tree* t1,
paths[1] = NULL; paths[1] = NULL;
diff_tree_setup_paths(get_pathspec(revs->prefix, paths), diff_tree_setup_paths(get_pathspec(revs->prefix, paths),
&revs->diffopt); &revs->pruning);
ret = rev_same_tree_as_empty(revs, t1); ret = rev_same_tree_as_empty(revs, t1);
diff_tree_release_paths(&revs->diffopt); diff_tree_release_paths(&revs->pruning);
return ret; return ret;
} }
@ -834,7 +834,7 @@ int main(int argc, const char **argv)
args[0] = filename; args[0] = filename;
args[1] = NULL; args[1] = NULL;
diff_tree_setup_paths(args, &rev.diffopt); diff_tree_setup_paths(args, &rev.pruning);
prepare_revision_walk(&rev); prepare_revision_walk(&rev);
process_commits(&rev, filename, &initial); process_commits(&rev, filename, &initial);

125
builtin-count.c Normal file
View File

@ -0,0 +1,125 @@
/*
* Builtin "git count-objects".
*
* Copyright (c) 2006 Junio C Hamano
*/
#include "cache.h"
#include "builtin.h"
static const char count_objects_usage[] = "git-count-objects [-v]";
static void count_objects(DIR *d, char *path, int len, int verbose,
unsigned long *loose,
unsigned long *loose_size,
unsigned long *packed_loose,
unsigned long *garbage)
{
struct dirent *ent;
while ((ent = readdir(d)) != NULL) {
char hex[41];
unsigned char sha1[20];
const char *cp;
int bad = 0;
if ((ent->d_name[0] == '.') &&
(ent->d_name[1] == 0 ||
((ent->d_name[1] == '.') && (ent->d_name[2] == 0))))
continue;
for (cp = ent->d_name; *cp; cp++) {
int ch = *cp;
if (('0' <= ch && ch <= '9') ||
('a' <= ch && ch <= 'f'))
continue;
bad = 1;
break;
}
if (cp - ent->d_name != 38)
bad = 1;
else {
struct stat st;
memcpy(path + len + 3, ent->d_name, 38);
path[len + 2] = '/';
path[len + 41] = 0;
if (lstat(path, &st) || !S_ISREG(st.st_mode))
bad = 1;
else
(*loose_size) += st.st_blocks;
}
if (bad) {
if (verbose) {
error("garbage found: %.*s/%s",
len + 2, path, ent->d_name);
(*garbage)++;
}
continue;
}
(*loose)++;
if (!verbose)
continue;
memcpy(hex, path+len, 2);
memcpy(hex+2, ent->d_name, 38);
hex[40] = 0;
if (get_sha1_hex(hex, sha1))
die("internal error");
if (has_sha1_pack(sha1))
(*packed_loose)++;
}
}
int cmd_count_objects(int ac, const char **av, char **ep)
{
int i;
int verbose = 0;
const char *objdir = get_object_directory();
int len = strlen(objdir);
char *path = xmalloc(len + 50);
unsigned long loose = 0, packed = 0, packed_loose = 0, garbage = 0;
unsigned long loose_size = 0;
for (i = 1; i < ac; i++) {
const char *arg = av[i];
if (*arg != '-')
break;
else if (!strcmp(arg, "-v"))
verbose = 1;
else
usage(count_objects_usage);
}
/* we do not take arguments other than flags for now */
if (i < ac)
usage(count_objects_usage);
memcpy(path, objdir, len);
if (len && objdir[len-1] != '/')
path[len++] = '/';
for (i = 0; i < 256; i++) {
DIR *d;
sprintf(path + len, "%02x", i);
d = opendir(path);
if (!d)
continue;
count_objects(d, path, len, verbose,
&loose, &loose_size, &packed_loose, &garbage);
closedir(d);
}
if (verbose) {
struct packed_git *p;
if (!packed_git)
prepare_packed_git();
for (p = packed_git; p; p = p->next) {
if (!p->pack_local)
continue;
packed += num_packed_objects(p);
}
printf("count: %lu\n", loose);
printf("size: %lu\n", loose_size / 2);
printf("in-pack: %lu\n", packed);
printf("prune-packable: %lu\n", packed_loose);
printf("garbage: %lu\n", garbage);
}
else
printf("%lu objects, %lu kilobytes\n",
loose, loose_size / 2);
return 0;
}

369
builtin-diff.c Normal file
View File

@ -0,0 +1,369 @@
/*
* Builtin "git diff"
*
* Copyright (c) 2006 Junio C Hamano
*/
#include "cache.h"
#include "commit.h"
#include "blob.h"
#include "tag.h"
#include "diff.h"
#include "diffcore.h"
#include "revision.h"
#include "log-tree.h"
#include "builtin.h"
/* NEEDSWORK: struct object has place for name but we _do_
* know mode when we extracted the blob out of a tree, which
* we currently lose.
*/
struct blobinfo {
unsigned char sha1[20];
const char *name;
};
static const char builtin_diff_usage[] =
"diff <options> <rev>{0,2} -- <path>*";
static int builtin_diff_files(struct rev_info *revs,
int argc, const char **argv)
{
int silent = 0;
while (1 < argc) {
const char *arg = argv[1];
if (!strcmp(arg, "--base"))
revs->max_count = 1;
else if (!strcmp(arg, "--ours"))
revs->max_count = 2;
else if (!strcmp(arg, "--theirs"))
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--;
}
/*
* Make sure there are NO revision (i.e. pending object) parameter,
* specified rev.max_count is reasonable (0 <= n <= 3), and
* there is no other revision filtering parameter.
*/
if (revs->pending_objects ||
revs->min_age != -1 ||
revs->max_age != -1 ||
3 < revs->max_count)
usage(builtin_diff_usage);
if (revs->max_count < 0 &&
(revs->diffopt.output_format == DIFF_FORMAT_PATCH))
revs->combine_merges = revs->dense_combined_merges = 1;
/*
* Backward compatibility wart - "diff-files -s" used to
* defeat the common diff option "-s" which asked for
* DIFF_FORMAT_NO_OUTPUT.
*/
if (revs->diffopt.output_format == DIFF_FORMAT_NO_OUTPUT)
revs->diffopt.output_format = DIFF_FORMAT_RAW;
return run_diff_files(revs, silent);
}
static void stuff_change(struct diff_options *opt,
unsigned old_mode, unsigned new_mode,
const unsigned char *old_sha1,
const unsigned char *new_sha1,
const char *old_name,
const char *new_name)
{
struct diff_filespec *one, *two;
if (memcmp(null_sha1, old_sha1, 20) &&
memcmp(null_sha1, new_sha1, 20) &&
!memcmp(old_sha1, new_sha1, 20))
return;
if (opt->reverse_diff) {
unsigned tmp;
const
const unsigned char *tmp_u;
const char *tmp_c;
tmp = old_mode; old_mode = new_mode; new_mode = tmp;
tmp_u = old_sha1; old_sha1 = new_sha1; new_sha1 = tmp_u;
tmp_c = old_name; old_name = new_name; new_name = tmp_c;
}
one = alloc_filespec(old_name);
two = alloc_filespec(new_name);
fill_filespec(one, old_sha1, old_mode);
fill_filespec(two, new_sha1, new_mode);
/* NEEDSWORK: shouldn't this part of diffopt??? */
diff_queue(&diff_queued_diff, one, two);
}
static int builtin_diff_b_f(struct rev_info *revs,
int argc, const char **argv,
struct blobinfo *blob,
const char *path)
{
/* 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 (lstat(path, &st))
die("'%s': %s", path, strerror(errno));
if (!(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)))
die("'%s': not a regular file or symlink", path);
stuff_change(&revs->diffopt,
canon_mode(st.st_mode), canon_mode(st.st_mode),
blob[0].sha1, null_sha1,
blob[0].name, path);
diffcore_std(&revs->diffopt);
diff_flush(&revs->diffopt);
return 0;
}
static int builtin_diff_blobs(struct rev_info *revs,
int argc, const char **argv,
struct blobinfo *blob)
{
/* Blobs */
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--;
}
stuff_change(&revs->diffopt,
mode, mode,
blob[0].sha1, blob[1].sha1,
blob[1].name, blob[1].name);
diffcore_std(&revs->diffopt);
diff_flush(&revs->diffopt);
return 0;
}
static int builtin_diff_index(struct rev_info *revs,
int argc, const char **argv)
{
int cached = 0;
while (1 < argc) {
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--;
}
/*
* Make sure there is one revision (i.e. pending object),
* and there is no revision filtering parameters.
*/
if (!revs->pending_objects || revs->pending_objects->next ||
revs->max_count != -1 || revs->min_age != -1 ||
revs->max_age != -1)
usage(builtin_diff_usage);
return run_diff_index(revs, cached);
}
static int builtin_diff_tree(struct rev_info *revs,
int argc, const char **argv,
struct object_list *ent)
{
const unsigned char *(sha1[2]);
int swap = 1;
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--;
}
/* We saw two trees, ent[0] and ent[1].
* unless ent[0] is unintesting, they are swapped
*/
if (ent[0].item->flags & UNINTERESTING)
swap = 0;
sha1[swap] = ent[0].item->sha1;
sha1[1-swap] = ent[1].item->sha1;
diff_tree_sha1(sha1[0], sha1[1], "", &revs->diffopt);
log_tree_diff_flush(revs);
return 0;
}
static int builtin_diff_combined(struct rev_info *revs,
int argc, const char **argv,
struct object_list *ent,
int ents)
{
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 (!revs->dense_combined_merges && !revs->combine_merges)
revs->dense_combined_merges = revs->combine_merges = 1;
parent = xmalloc(ents * sizeof(*parent));
/* Again, the revs are all reverse */
for (i = 0; i < ents; i++)
memcpy(parent + i, ent[ents - 1 - i].item->sha1, 20);
diff_tree_combined(parent[0], parent + 1, ents - 1,
revs->dense_combined_merges, revs);
return 0;
}
static void add_head(struct rev_info *revs)
{
unsigned char sha1[20];
struct object *obj;
if (get_sha1("HEAD", sha1))
return;
obj = parse_object(sha1);
if (!obj)
return;
add_object(obj, &revs->pending_objects, NULL, "HEAD");
}
int cmd_diff(int argc, const char **argv, char **envp)
{
struct rev_info rev;
struct object_list *list, ent[100];
int ents = 0, blobs = 0, paths = 0;
const char *path = NULL;
struct blobinfo blob[2];
/*
* We could get N tree-ish in the rev.pending_objects list.
* Also there could be M blobs there, and P pathspecs.
*
* N=0, M=0:
* cache vs files (diff-files)
* N=0, M=2:
* compare two random blobs. P must be zero.
* N=0, M=1, P=1:
* compare a blob with a working tree file.
*
* N=1, M=0:
* tree vs cache (diff-index --cached)
*
* N=2, M=0:
* tree vs tree (diff-tree)
*
* Other cases are errors.
*/
git_config(git_diff_config);
init_revisions(&rev);
rev.diffopt.output_format = DIFF_FORMAT_PATCH;
argc = setup_revisions(argc, argv, &rev, NULL);
/* Do we have --cached and not have a pending object, then
* default to HEAD by hand. Eek.
*/
if (!rev.pending_objects) {
int i;
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
if (!strcmp(arg, "--"))
break;
else if (!strcmp(arg, "--cached")) {
add_head(&rev);
break;
}
}
}
for (list = rev.pending_objects; list; list = list->next) {
struct object *obj = list->item;
const char *name = list->name;
int flags = (obj->flags & UNINTERESTING);
if (!obj->parsed)
obj = parse_object(obj->sha1);
obj = deref_tag(obj, NULL, 0);
if (!obj)
die("invalid object '%s' given.", name);
if (!strcmp(obj->type, commit_type))
obj = &((struct commit *)obj)->tree->object;
if (!strcmp(obj->type, tree_type)) {
if (ARRAY_SIZE(ent) <= ents)
die("more than %d trees given: '%s'",
(int) ARRAY_SIZE(ent), name);
obj->flags |= flags;
ent[ents].item = obj;
ent[ents].name = name;
ents++;
continue;
}
if (!strcmp(obj->type, blob_type)) {
if (2 <= blobs)
die("more than two blobs given: '%s'", name);
memcpy(blob[blobs].sha1, obj->sha1, 20);
blob[blobs].name = name;
blobs++;
continue;
}
die("unhandled object '%s' given.", name);
}
if (rev.prune_data) {
const char **pathspec = rev.prune_data;
while (*pathspec) {
if (!path)
path = *pathspec;
paths++;
pathspec++;
}
}
/*
* Now, do the arguments look reasonable?
*/
if (!ents) {
switch (blobs) {
case 0:
return builtin_diff_files(&rev, argc, argv);
break;
case 1:
if (paths != 1)
usage(builtin_diff_usage);
return builtin_diff_b_f(&rev, argc, argv, blob, path);
break;
case 2:
if (paths)
usage(builtin_diff_usage);
return builtin_diff_blobs(&rev, argc, argv, blob);
break;
default:
usage(builtin_diff_usage);
}
}
else if (blobs)
usage(builtin_diff_usage);
else if (ents == 1)
return builtin_diff_index(&rev, argc, argv);
else if (ents == 2)
return builtin_diff_tree(&rev, argc, argv, ent);
else
return builtin_diff_combined(&rev, argc, argv, ent, ents);
usage(builtin_diff_usage);
}

312
builtin-push.c Normal file
View File

@ -0,0 +1,312 @@
/*
* "git push"
*/
#include "cache.h"
#include "refs.h"
#include "run-command.h"
#include "builtin.h"
#define MAX_URI (16)
static const char push_usage[] = "git push [--all] [--tags] [--force] <repository> [<refspec>...]";
static int all = 0, tags = 0, force = 0, thin = 1;
static const char *execute = NULL;
#define BUF_SIZE (2084)
static char buffer[BUF_SIZE];
static const char **refspec = NULL;
static int refspec_nr = 0;
static void add_refspec(const char *ref)
{
int nr = refspec_nr + 1;
refspec = xrealloc(refspec, nr * sizeof(char *));
refspec[nr-1] = ref;
refspec_nr = nr;
}
static int expand_one_ref(const char *ref, const unsigned char *sha1)
{
/* Ignore the "refs/" at the beginning of the refname */
ref += 5;
if (strncmp(ref, "tags/", 5))
return 0;
add_refspec(strdup(ref));
return 0;
}
static void expand_refspecs(void)
{
if (all) {
if (refspec_nr)
die("cannot mix '--all' and a refspec");
/*
* No need to expand "--all" - we'll just use
* the "--all" flag to send-pack
*/
return;
}
if (!tags)
return;
for_each_ref(expand_one_ref);
}
static void set_refspecs(const char **refs, int nr)
{
if (nr) {
size_t bytes = nr * sizeof(char *);
refspec = xrealloc(refspec, bytes);
memcpy(refspec, refs, bytes);
refspec_nr = nr;
}
expand_refspecs();
}
static int get_remotes_uri(const char *repo, const char *uri[MAX_URI])
{
int n = 0;
FILE *f = fopen(git_path("remotes/%s", repo), "r");
int has_explicit_refspec = refspec_nr || all || tags;
if (!f)
return -1;
while (fgets(buffer, BUF_SIZE, f)) {
int is_refspec;
char *s, *p;
if (!strncmp("URL: ", buffer, 5)) {
is_refspec = 0;
s = buffer + 5;
} else if (!strncmp("Push: ", buffer, 6)) {
is_refspec = 1;
s = buffer + 6;
} else
continue;
/* Remove whitespace at the head.. */
while (isspace(*s))
s++;
if (!*s)
continue;
/* ..and at the end */
p = s + strlen(s);
while (isspace(p[-1]))
*--p = 0;
if (!is_refspec) {
if (n < MAX_URI)
uri[n++] = strdup(s);
else
error("more than %d URL's specified, ignoreing the rest", MAX_URI);
}
else if (is_refspec && !has_explicit_refspec)
add_refspec(strdup(s));
}
fclose(f);
if (!n)
die("remote '%s' has no URL", repo);
return n;
}
static const char **config_uri;
static const char *config_repo;
static int config_repo_len;
static int config_current_uri;
static int config_get_refspecs;
static int get_remote_config(const char* key, const char* value)
{
if (!strncmp(key, "remote.", 7) &&
!strncmp(key + 7, config_repo, config_repo_len)) {
if (!strcmp(key + 7 + config_repo_len, ".url")) {
if (config_current_uri < MAX_URI)
config_uri[config_current_uri++] = strdup(value);
else
error("more than %d URL's specified, ignoring the rest", MAX_URI);
}
else if (config_get_refspecs &&
!strcmp(key + 7 + config_repo_len, ".push"))
add_refspec(strdup(value));
}
return 0;
}
static int get_config_remotes_uri(const char *repo, const char *uri[MAX_URI])
{
config_repo_len = strlen(repo);
config_repo = repo;
config_current_uri = 0;
config_uri = uri;
config_get_refspecs = !(refspec_nr || all || tags);
git_config(get_remote_config);
return config_current_uri;
}
static int get_branches_uri(const char *repo, const char *uri[MAX_URI])
{
const char *slash = strchr(repo, '/');
int n = slash ? slash - repo : 1000;
FILE *f = fopen(git_path("branches/%.*s", n, repo), "r");
char *s, *p;
int len;
if (!f)
return 0;
s = fgets(buffer, BUF_SIZE, f);
fclose(f);
if (!s)
return 0;
while (isspace(*s))
s++;
if (!*s)
return 0;
p = s + strlen(s);
while (isspace(p[-1]))
*--p = 0;
len = p - s;
if (slash)
len += strlen(slash);
p = xmalloc(len + 1);
strcpy(p, s);
if (slash)
strcat(p, slash);
uri[0] = p;
return 1;
}
/*
* Read remotes and branches file, fill the push target URI
* list. If there is no command line refspecs, read Push: lines
* to set up the *refspec list as well.
* return the number of push target URIs
*/
static int read_config(const char *repo, const char *uri[MAX_URI])
{
int n;
if (*repo != '/') {
n = get_remotes_uri(repo, uri);
if (n > 0)
return n;
n = get_config_remotes_uri(repo, uri);
if (n > 0)
return n;
n = get_branches_uri(repo, uri);
if (n > 0)
return n;
}
uri[0] = repo;
return 1;
}
static int do_push(const char *repo)
{
const char *uri[MAX_URI];
int i, n;
int remote;
const char **argv;
int argc;
n = read_config(repo, uri);
if (n <= 0)
die("bad repository '%s'", repo);
argv = xmalloc((refspec_nr + 10) * sizeof(char *));
argv[0] = "dummy-send-pack";
argc = 1;
if (all)
argv[argc++] = "--all";
if (force)
argv[argc++] = "--force";
if (execute)
argv[argc++] = execute;
if (thin)
argv[argc++] = "--thin";
remote = argc;
argv[argc++] = "dummy-remote";
while (refspec_nr--)
argv[argc++] = *refspec++;
argv[argc] = NULL;
for (i = 0; i < n; i++) {
int error;
const char *dest = uri[i];
const char *sender = "git-send-pack";
if (!strncmp(dest, "http://", 7) ||
!strncmp(dest, "https://", 8))
sender = "git-http-push";
argv[0] = sender;
argv[remote] = dest;
error = run_command_v(argc, argv);
if (!error)
continue;
switch (error) {
case -ERR_RUN_COMMAND_FORK:
die("unable to fork for %s", sender);
case -ERR_RUN_COMMAND_EXEC:
die("unable to exec %s", sender);
case -ERR_RUN_COMMAND_WAITPID:
case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
die("%s died with strange error", sender);
default:
return -error;
}
}
return 0;
}
int cmd_push(int argc, const char **argv, char **envp)
{
int i;
const char *repo = "origin"; // default repository
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
if (arg[0] != '-') {
repo = arg;
i++;
break;
}
if (!strcmp(arg, "--all")) {
all = 1;
continue;
}
if (!strcmp(arg, "--tags")) {
tags = 1;
continue;
}
if (!strcmp(arg, "--force")) {
force = 1;
continue;
}
if (!strcmp(arg, "--thin")) {
thin = 1;
continue;
}
if (!strcmp(arg, "--no-thin")) {
thin = 0;
continue;
}
if (!strncmp(arg, "--exec=", 7)) {
execute = arg;
continue;
}
usage(push_usage);
}
set_refspecs(argv + i, argc - i);
return do_push(repo);
}

View File

@ -19,5 +19,9 @@ extern int cmd_version(int argc, const char **argv, char **envp);
extern int cmd_whatchanged(int argc, const char **argv, char **envp); 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_show(int argc, const char **argv, char **envp);
extern int cmd_log(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_count_objects(int argc, const char **argv, char **envp);
extern int cmd_push(int argc, const char **argv, char **envp);
#endif #endif

View File

@ -169,7 +169,7 @@ extern void rollback_index_file(struct cache_file *);
/* Environment bits from configuration mechanism */ /* Environment bits from configuration mechanism */
extern int trust_executable_bit; extern int trust_executable_bit;
extern int assume_unchanged; extern int assume_unchanged;
extern int only_use_symrefs; extern int prefer_symlink_refs;
extern int warn_ambiguous_refs; extern int warn_ambiguous_refs;
extern int diff_rename_limit_default; extern int diff_rename_limit_default;
extern int shared_repository; extern int shared_repository;

View File

@ -269,12 +269,16 @@ int main(int argc, char **argv)
/* Check out named files first */ /* Check out named files first */
for ( ; i < argc; i++) { for ( ; i < argc; i++) {
const char *arg = argv[i]; const char *arg = argv[i];
const char *p;
if (all) if (all)
die("git-checkout-index: don't mix '--all' and explicit filenames"); die("git-checkout-index: don't mix '--all' and explicit filenames");
if (read_from_stdin) if (read_from_stdin)
die("git-checkout-index: don't mix '--stdin' and explicit filenames"); die("git-checkout-index: don't mix '--stdin' and explicit filenames");
checkout_file(prefix_path(prefix, prefix_length, arg)); p = prefix_path(prefix, prefix_length, arg);
checkout_file(p);
if (p < arg || p > arg + strlen(arg))
free((char*)p);
} }
if (read_from_stdin) { if (read_from_stdin) {
@ -284,6 +288,8 @@ int main(int argc, char **argv)
strbuf_init(&buf); strbuf_init(&buf);
while (1) { while (1) {
char *path_name; char *path_name;
const char *p;
read_line(&buf, stdin, line_termination); read_line(&buf, stdin, line_termination);
if (buf.eof) if (buf.eof)
break; break;
@ -291,7 +297,10 @@ int main(int argc, char **argv)
path_name = unquote_c_style(buf.buf, NULL); path_name = unquote_c_style(buf.buf, NULL);
else else
path_name = buf.buf; path_name = buf.buf;
checkout_file(prefix_path(prefix, prefix_length, path_name)); p = prefix_path(prefix, prefix_length, path_name);
checkout_file(p);
if (p < path_name || p > path_name + strlen(path_name))
free((char *)p);
if (path_name != buf.buf) if (path_name != buf.buf)
free(path_name); free(path_name);
} }

View File

@ -831,15 +831,16 @@ void show_combined_diff(struct combine_diff_path *p,
} }
} }
void diff_tree_combined_merge(const unsigned char *sha1, void diff_tree_combined(const unsigned char *sha1,
int dense, struct rev_info *rev) const unsigned char parent[][20],
int num_parent,
int dense,
struct rev_info *rev)
{ {
struct diff_options *opt = &rev->diffopt; struct diff_options *opt = &rev->diffopt;
struct commit *commit = lookup_commit(sha1);
struct diff_options diffopts; struct diff_options diffopts;
struct commit_list *parents;
struct combine_diff_path *p, *paths = NULL; struct combine_diff_path *p, *paths = NULL;
int num_parent, i, num_paths; int i, num_paths;
int do_diffstat; int do_diffstat;
do_diffstat = (opt->output_format == DIFF_FORMAT_DIFFSTAT || do_diffstat = (opt->output_format == DIFF_FORMAT_DIFFSTAT ||
@ -849,17 +850,8 @@ void diff_tree_combined_merge(const unsigned char *sha1,
diffopts.with_stat = 0; diffopts.with_stat = 0;
diffopts.recursive = 1; diffopts.recursive = 1;
/* count parents */
for (parents = commit->parents, num_parent = 0;
parents;
parents = parents->next, num_parent++)
; /* nothing */
/* find set of paths that everybody touches */ /* find set of paths that everybody touches */
for (parents = commit->parents, i = 0; for (i = 0; i < num_parent; i++) {
parents;
parents = parents->next, i++) {
struct commit *parent = parents->item;
/* show stat against the first parent even /* show stat against the first parent even
* when doing combined diff. * when doing combined diff.
*/ */
@ -867,8 +859,7 @@ void diff_tree_combined_merge(const unsigned char *sha1,
diffopts.output_format = DIFF_FORMAT_DIFFSTAT; diffopts.output_format = DIFF_FORMAT_DIFFSTAT;
else else
diffopts.output_format = DIFF_FORMAT_NO_OUTPUT; diffopts.output_format = DIFF_FORMAT_NO_OUTPUT;
diff_tree_sha1(parent->object.sha1, commit->object.sha1, "", diff_tree_sha1(parent[i], sha1, "", &diffopts);
&diffopts);
diffcore_std(&diffopts); diffcore_std(&diffopts);
paths = intersect_paths(paths, i, num_parent); paths = intersect_paths(paths, i, num_parent);
@ -907,3 +898,25 @@ void diff_tree_combined_merge(const unsigned char *sha1,
free(tmp); free(tmp);
} }
} }
void diff_tree_combined_merge(const unsigned char *sha1,
int dense, struct rev_info *rev)
{
int num_parent;
const unsigned char (*parent)[20];
struct commit *commit = lookup_commit(sha1);
struct commit_list *parents;
/* count parents */
for (parents = commit->parents, num_parent = 0;
parents;
parents = parents->next, num_parent++)
; /* nothing */
parent = xmalloc(num_parent * sizeof(*parent));
for (parents = commit->parents, num_parent = 0;
parents;
parents = parents->next, num_parent++)
memcpy(parent + num_parent, parents->item->object.sha1, 20);
diff_tree_combined(sha1, parent, num_parent, dense, rev);
}

View File

@ -227,8 +227,8 @@ int git_default_config(const char *var, const char *value)
return 0; return 0;
} }
if (!strcmp(var, "core.symrefsonly")) { if (!strcmp(var, "core.prefersymlinkrefs")) {
only_use_symrefs = git_config_bool(var, value); prefer_symlink_refs = git_config_bool(var, value);
return 0; return 0;
} }
@ -335,8 +335,11 @@ static int store_aux(const char* key, const char* value)
store.offset[store.seen] = ftell(config_file); store.offset[store.seen] = ftell(config_file);
store.state = KEY_SEEN; store.state = KEY_SEEN;
store.seen++; store.seen++;
} else if(!strncmp(key, store.key, store.baselen)) } else if (strrchr(key, '.') - key == store.baselen &&
store.state = SECTION_SEEN; !strncmp(key, store.key, store.baselen)) {
store.state = SECTION_SEEN;
store.offset[store.seen] = ftell(config_file);
}
} }
return 0; return 0;
} }

View File

@ -8,7 +8,7 @@ use vars qw/ $AUTHOR $VERSION
$GIT_SVN_INDEX $GIT_SVN $GIT_SVN_INDEX $GIT_SVN
$GIT_DIR $REV_DIR/; $GIT_DIR $REV_DIR/;
$AUTHOR = 'Eric Wong <normalperson@yhbt.net>'; $AUTHOR = 'Eric Wong <normalperson@yhbt.net>';
$VERSION = '0.11.0'; $VERSION = '1.0.0';
use Cwd qw/abs_path/; use Cwd qw/abs_path/;
$GIT_DIR = abs_path($ENV{GIT_DIR} || '.git'); $GIT_DIR = abs_path($ENV{GIT_DIR} || '.git');
@ -42,7 +42,8 @@ my %fc_opts = ( 'no-ignore-externals' => \$_no_ignore_ext,
my %cmd = ( my %cmd = (
fetch => [ \&fetch, "Download new revisions from SVN", fetch => [ \&fetch, "Download new revisions from SVN",
{ 'revision|r=s' => \$_revision, %fc_opts } ], { 'revision|r=s' => \$_revision, %fc_opts } ],
init => [ \&init, "Initialize and fetch (import)", { } ], init => [ \&init, "Initialize a repo for tracking" .
" (requires URL argument)", { } ],
commit => [ \&commit, "Commit git revisions to SVN", commit => [ \&commit, "Commit git revisions to SVN",
{ 'stdin|' => \$_stdin, { 'stdin|' => \$_stdin,
'edit|e' => \$_edit, 'edit|e' => \$_edit,
@ -220,7 +221,8 @@ when you have upgraded your tools and habits to use refs/remotes/$GIT_SVN
} }
sub init { sub init {
$SVN_URL = shift or croak "SVN repository location required\n"; $SVN_URL = shift or die "SVN repository location required " .
"as a command-line argument\n";
unless (-d $GIT_DIR) { unless (-d $GIT_DIR) {
sys('git-init-db'); sys('git-init-db');
} }

View File

@ -36,17 +36,22 @@ COMMANDS
-------- --------
init:: init::
Creates an empty git repository with additional metadata Creates an empty git repository with additional metadata
directories for git-svn. The SVN_URL must be specified directories for git-svn. The Subversion URL must be specified
at this point. as a command-line argument.
fetch:: fetch::
Fetch unfetched revisions from the SVN_URL we are tracking. Fetch unfetched revisions from the Subversion URL we are
refs/heads/remotes/git-svn will be updated to the latest revision. tracking. refs/remotes/git-svn will be updated to the
latest revision.
Note: You should never attempt to modify the remotes/git-svn branch Note: You should never attempt to modify the remotes/git-svn
outside of git-svn. Instead, create a branch from remotes/git-svn branch outside of git-svn. Instead, create a branch from
and work on that branch. Use the 'commit' command (see below) remotes/git-svn and work on that branch. Use the 'commit'
to write git commits back to remotes/git-svn. command (see below) to write git commits back to
remotes/git-svn.
See 'Additional Fetch Arguments' if you are interested in
manually joining branches on commit.
commit:: commit::
Commit specified commit or tree objects to SVN. This relies on Commit specified commit or tree objects to SVN. This relies on
@ -62,9 +67,9 @@ rebuild::
tracked with git-svn. Unfortunately, git-clone does not clone tracked with git-svn. Unfortunately, git-clone does not clone
git-svn metadata and the svn working tree that git-svn uses for git-svn metadata and the svn working tree that git-svn uses for
its operations. This rebuilds the metadata so git-svn can its operations. This rebuilds the metadata so git-svn can
resume fetch operations. SVN_URL may be optionally specified if resume fetch operations. A Subversion URL may be optionally
the directory/repository you're tracking has moved or changed specified at the command-line if the directory/repository you're
protocols. tracking has moved or changed protocols.
show-ignore:: show-ignore::
Recursively finds and lists the svn:ignore property on Recursively finds and lists the svn:ignore property on
@ -123,6 +128,24 @@ OPTIONS
repo-config key: svn.l repo-config key: svn.l
repo-config key: svn.findcopiesharder repo-config key: svn.findcopiesharder
-A<filename>::
--authors-file=<filename>::
Syntax is compatible with the files used by git-svnimport and
git-cvsimport:
------------------------------------------------------------------------
loginname = Joe User <user@example.com>
------------------------------------------------------------------------
If this option is specified and git-svn encounters an SVN
committer name that does not exist in the authors-file, git-svn
will abort operation. The user will then have to add the
appropriate entry. Re-running the previous git-svn command
after the authors-file is modified should continue operation.
repo-config key: svn.authors-file
ADVANCED OPTIONS ADVANCED OPTIONS
---------------- ----------------
-b<refname>:: -b<refname>::

View File

@ -2,11 +2,11 @@
#define DELTA_H #define DELTA_H
/* handling of delta buffers */ /* handling of delta buffers */
extern void *diff_delta(void *from_buf, unsigned long from_size, extern void *diff_delta(const void *from_buf, unsigned long from_size,
void *to_buf, unsigned long to_size, const void *to_buf, unsigned long to_size,
unsigned long *delta_size, unsigned long max_size); unsigned long *delta_size, unsigned long max_size);
extern void *patch_delta(void *src_buf, unsigned long src_size, extern void *patch_delta(void *src_buf, unsigned long src_size,
void *delta_buf, unsigned long delta_size, const void *delta_buf, unsigned long delta_size,
unsigned long *dst_size); unsigned long *dst_size);
/* the smallest possible delta size is 4 bytes */ /* the smallest possible delta size is 4 bytes */

View File

@ -131,8 +131,8 @@ static struct index ** delta_index(const unsigned char *buf,
/* the maximum size for any opcode */ /* the maximum size for any opcode */
#define MAX_OP_SIZE COPYOP_SIZE(0xffffffff, 0xffffffff) #define MAX_OP_SIZE COPYOP_SIZE(0xffffffff, 0xffffffff)
void *diff_delta(void *from_buf, unsigned long from_size, void *diff_delta(const void *from_buf, unsigned long from_size,
void *to_buf, unsigned long to_size, const void *to_buf, unsigned long to_size,
unsigned long *delta_size, unsigned long *delta_size,
unsigned long max_size) unsigned long max_size)
{ {

6
diff.c
View File

@ -1018,14 +1018,12 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o)
} }
if (memcmp(one->sha1, two->sha1, 20)) { if (memcmp(one->sha1, two->sha1, 20)) {
char one_sha1[41];
int abbrev = o->full_index ? 40 : DEFAULT_ABBREV; int abbrev = o->full_index ? 40 : DEFAULT_ABBREV;
memcpy(one_sha1, sha1_to_hex(one->sha1), 41);
len += snprintf(msg + len, sizeof(msg) - len, len += snprintf(msg + len, sizeof(msg) - len,
"index %.*s..%.*s", "index %.*s..%.*s",
abbrev, one_sha1, abbrev, abbrev, sha1_to_hex(one->sha1),
sha1_to_hex(two->sha1)); abbrev, sha1_to_hex(two->sha1));
if (one->mode == two->mode) if (one->mode == two->mode)
len += snprintf(msg + len, sizeof(msg) - len, len += snprintf(msg + len, sizeof(msg) - len,
" %06o", one->mode); " %06o", one->mode);

2
diff.h
View File

@ -75,6 +75,8 @@ struct combine_diff_path {
extern void show_combined_diff(struct combine_diff_path *elem, int num_parent, extern void show_combined_diff(struct combine_diff_path *elem, int num_parent,
int dense, struct rev_info *); int dense, struct rev_info *);
extern void diff_tree_combined(const unsigned char *sha1, const unsigned char parent[][20], int num_parent, int dense, struct rev_info *rev);
extern void diff_tree_combined_merge(const unsigned char *sha1, int, struct rev_info *); extern void diff_tree_combined_merge(const unsigned char *sha1, int, struct rev_info *);
extern void diff_addremove(struct diff_options *, extern void diff_addremove(struct diff_options *,

View File

@ -13,7 +13,7 @@ char git_default_email[MAX_GITNAME];
char git_default_name[MAX_GITNAME]; char git_default_name[MAX_GITNAME];
int trust_executable_bit = 1; int trust_executable_bit = 1;
int assume_unchanged = 0; int assume_unchanged = 0;
int only_use_symrefs = 0; int prefer_symlink_refs = 0;
int warn_ambiguous_refs = 1; int warn_ambiguous_refs = 1;
int repository_format_version = 0; int repository_format_version = 0;
char git_commit_encoding[MAX_ENCODING_LENGTH] = "utf-8"; char git_commit_encoding[MAX_ENCODING_LENGTH] = "utf-8";

View File

@ -1,31 +0,0 @@
#!/bin/sh
#
# Copyright (c) 2005 Junio C Hamano
#
GIT_DIR=`git-rev-parse --git-dir` || exit $?
dc </dev/null 2>/dev/null || {
# This is not a real DC at all -- it just knows how
# this script feeds DC and does the computation itself.
dc () {
while read a b
do
case $a,$b in
0,) acc=0 ;;
*,+) acc=$(($acc + $a)) ;;
p,) echo "$acc" ;;
esac
done
}
}
echo $(find "$GIT_DIR/objects"/?? -type f -print 2>/dev/null | wc -l) objects, \
$({
echo 0
# "no-such" is to help Darwin folks by not using xargs -r.
find "$GIT_DIR/objects"/?? -type f -print 2>/dev/null |
xargs du -k "$GIT_DIR/objects/no-such" 2>/dev/null |
sed -e 's/[ ].*/ +/'
echo p
} | dc) kilobytes

View File

@ -1,74 +0,0 @@
#!/bin/sh
#
# Copyright (c) 2005 Linus Torvalds
# Copyright (c) 2005 Junio C Hamano
USAGE='[ --diff-options ] <ent>{0,2} [<path>...]'
SUBDIRECTORY_OK='Yes'
. git-sh-setup
rev=$(git-rev-parse --revs-only --no-flags --sq "$@") || exit
flags=$(git-rev-parse --no-revs --flags --sq "$@")
files=$(git-rev-parse --no-revs --no-flags --sq "$@")
# I often say 'git diff --cached -p' and get scolded by git-diff-files, but
# obviously I mean 'git diff --cached -p HEAD' in that case.
case "$rev" in
'')
case " $flags " in
*" '--cached' "*)
rev='HEAD '
;;
esac
esac
# If we have -[123] --ours --theirs --base, don't do --cc by default.
case " $flags " in
*" '-"[123]"' "* | *" '--ours' "* | *" '--base' "* | *" '--theirs' "*)
cc_or_p=-p ;;
*)
cc_or_p=--cc ;;
esac
# If we do not have --name-status, --name-only, -r, -c or --stat,
# default to --cc.
case " $flags " in
*" '--name-status' "* | *" '--name-only' "* | *" '-r' "* | *" '-c' "* | \
*" '--stat' "*)
;;
*)
flags="$flags'$cc_or_p' " ;;
esac
# If we do not have -B, -C, -r, nor -p, default to -M.
case " $flags " in
*" '-"[BCMrp]* | *" '--find-copies-harder' "*)
;; # something like -M50.
*)
flags="$flags'-M' " ;;
esac
case "$rev" in
?*' '?*' '?*)
usage
;;
?*' '^?*)
begin=$(expr "$rev" : '.*^.\([0-9a-f]*\).*') &&
end=$(expr "$rev" : '.\([0-9a-f]*\). .*') || exit
cmd="git-diff-tree $flags $begin $end -- $files"
;;
?*' '?*)
cmd="git-diff-tree $flags $rev -- $files"
;;
?*' ')
cmd="git-diff-index $flags $rev -- $files"
;;
'')
cmd="git-diff-files $flags -- $files"
;;
*)
usage
;;
esac
eval "$cmd"

View File

@ -1,28 +0,0 @@
#!/bin/sh
USAGE='[-p] [--max-count=<n>] [<since>..<limit>] [--pretty=<format>] [-m] [git-diff-tree options] [git-rev-list options]'
SUBDIRECTORY_OK='Yes'
. git-sh-setup
diff_tree_flags=$(git-rev-parse --sq --no-revs --flags "$@") || exit
case "$0" in
*whatchanged)
count=
test -z "$diff_tree_flags" &&
diff_tree_flags=$(git-repo-config --get whatchanged.difftree)
diff_tree_default_flags='-c -M --abbrev' ;;
*show)
count=-n1
test -z "$diff_tree_flags" &&
diff_tree_flags=$(git-repo-config --get show.difftree)
diff_tree_default_flags='--cc --always' ;;
esac
test -z "$diff_tree_flags" &&
diff_tree_flags="$diff_tree_default_flags"
rev_list_args=$(git-rev-parse --sq --default HEAD --revs-only "$@") &&
diff_tree_args=$(git-rev-parse --sq --no-revs --no-flags "$@") &&
eval "git-rev-list $count $rev_list_args" |
eval "git-diff-tree --stdin --pretty -r $diff_tree_flags $diff_tree_args" |
LESS="$LESS -S" ${PAGER:-less}

3
git.c
View File

@ -46,6 +46,9 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
{ "log", cmd_log }, { "log", cmd_log },
{ "whatchanged", cmd_whatchanged }, { "whatchanged", cmd_whatchanged },
{ "show", cmd_show }, { "show", cmd_show },
{ "push", cmd_push },
{ "count-objects", cmd_count_objects },
{ "diff", cmd_diff },
}; };
int i; int i;

1777
gitk

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,15 @@
#include "commit.h" #include "commit.h"
#include "log-tree.h" #include "log-tree.h"
static void show_parents(struct commit *commit, int abbrev)
{
struct commit_list *p;
for (p = commit->parents; p ; p = p->next) {
struct commit *parent = p->item;
printf(" %s", diff_unique_abbrev(parent->object.sha1, abbrev));
}
}
void show_log(struct rev_info *opt, struct log_info *log, const char *sep) void show_log(struct rev_info *opt, struct log_info *log, const char *sep)
{ {
static char this_header[16384]; static char this_header[16384];
@ -14,7 +23,10 @@ void show_log(struct rev_info *opt, struct log_info *log, const char *sep)
opt->loginfo = NULL; opt->loginfo = NULL;
if (!opt->verbose_header) { if (!opt->verbose_header) {
puts(sha1_to_hex(commit->object.sha1)); fputs(diff_unique_abbrev(commit->object.sha1, abbrev_commit), stdout);
if (opt->parents)
show_parents(commit, abbrev_commit);
putchar('\n');
return; return;
} }
@ -40,7 +52,9 @@ void show_log(struct rev_info *opt, struct log_info *log, const char *sep)
printf("%s%s", printf("%s%s",
opt->commit_format == CMIT_FMT_ONELINE ? "" : "commit ", opt->commit_format == CMIT_FMT_ONELINE ? "" : "commit ",
diff_unique_abbrev(commit->object.sha1, abbrev_commit)); diff_unique_abbrev(commit->object.sha1, abbrev_commit));
if (parent) if (opt->parents)
show_parents(commit, abbrev_commit);
if (parent)
printf(" (from %s)", diff_unique_abbrev(parent->object.sha1, abbrev_commit)); printf(" (from %s)", diff_unique_abbrev(parent->object.sha1, abbrev_commit));
putchar(opt->commit_format == CMIT_FMT_ONELINE ? ' ' : '\n'); putchar(opt->commit_format == CMIT_FMT_ONELINE ? ' ' : '\n');

View File

@ -24,16 +24,14 @@ static const char *sha1_to_hex_zero(const unsigned char *sha1)
static void resolve(const char *base, struct name_entry *branch1, struct name_entry *result) static void resolve(const char *base, struct name_entry *branch1, struct name_entry *result)
{ {
char branch1_sha1[50];
/* If it's already branch1, don't bother showing it */ /* If it's already branch1, don't bother showing it */
if (!branch1) if (!branch1)
return; return;
memcpy(branch1_sha1, sha1_to_hex_zero(branch1->sha1), 41);
printf("0 %06o->%06o %s->%s %s%s\n", printf("0 %06o->%06o %s->%s %s%s\n",
branch1->mode, result->mode, branch1->mode, result->mode,
branch1_sha1, sha1_to_hex_zero(result->sha1), sha1_to_hex_zero(branch1->sha1),
sha1_to_hex_zero(result->sha1),
base, result->path); base, result->path);
} }

View File

@ -1239,6 +1239,7 @@ int main(int argc, char **argv)
setup_git_directory(); setup_git_directory();
progress = isatty(2);
for (i = 1; i < argc; i++) { for (i = 1; i < argc; i++) {
const char *arg = argv[i]; const char *arg = argv[i];
@ -1269,6 +1270,10 @@ int main(int argc, char **argv)
usage(pack_usage); usage(pack_usage);
continue; continue;
} }
if (!strcmp("--progress", arg)) {
progress = 1;
continue;
}
if (!strcmp("-q", arg)) { if (!strcmp("-q", arg)) {
progress = 0; progress = 0;
continue; continue;

View File

@ -14,7 +14,7 @@
#include "delta.h" #include "delta.h"
void *patch_delta(void *src_buf, unsigned long src_size, void *patch_delta(void *src_buf, unsigned long src_size,
void *delta_buf, unsigned long delta_size, const void *delta_buf, unsigned long delta_size,
unsigned long *dst_size) unsigned long *dst_size)
{ {
const unsigned char *data, *top; const unsigned char *data, *top;

4
refs.c
View File

@ -76,8 +76,8 @@ int create_symref(const char *git_HEAD, const char *refs_heads_master)
char ref[1000]; char ref[1000];
int fd, len, written; int fd, len, written;
#ifdef USE_SYMLINK_HEAD #ifndef NO_SYMLINK_HEAD
if (!only_use_symrefs) { if (prefer_symlink_refs) {
unlink(git_HEAD); unlink(git_HEAD);
if (!symlink(refs_heads_master, git_HEAD)) if (!symlink(refs_heads_master, git_HEAD))
return 0; return 0;

View File

@ -2,11 +2,13 @@
#include <regex.h> #include <regex.h>
static const char git_config_set_usage[] = static const char git_config_set_usage[] =
"git-repo-config [ --bool | --int ] [--get | --get-all | --replace-all | --unset | --unset-all] name [value [value_regex]] | --list"; "git-repo-config [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --unset | --unset-all] name [value [value_regex]] | --list";
static char* key = NULL; static char* key = NULL;
static char* value = NULL; static regex_t* key_regexp = NULL;
static regex_t* regexp = NULL; static regex_t* regexp = NULL;
static int show_keys = 0;
static int use_key_regexp = 0;
static int do_all = 0; static int do_all = 0;
static int do_not_match = 0; static int do_not_match = 0;
static int seen = 0; static int seen = 0;
@ -23,34 +25,40 @@ static int show_all_config(const char *key_, const char *value_)
static int show_config(const char* key_, const char* value_) static int show_config(const char* key_, const char* value_)
{ {
char value[256];
const char *vptr = value;
int dup_error = 0;
if (value_ == NULL) if (value_ == NULL)
value_ = ""; value_ = "";
if (!strcmp(key_, key) && if (!use_key_regexp && strcmp(key_, key))
(regexp == NULL || return 0;
if (use_key_regexp && regexec(key_regexp, key_, 0, NULL, 0))
return 0;
if (regexp != NULL &&
(do_not_match ^ (do_not_match ^
!regexec(regexp, value_, 0, NULL, 0)))) { regexec(regexp, value_, 0, NULL, 0)))
if (do_all) { return 0;
printf("%s\n", value_);
return 0;
}
if (seen > 0) {
fprintf(stderr, "More than one value: %s\n", value);
free(value);
}
if (type == T_INT) { if (show_keys)
value = malloc(256); printf("%s ", key_);
sprintf(value, "%d", git_config_int(key_, value_)); if (seen && !do_all)
} else if (type == T_BOOL) { dup_error = 1;
value = malloc(256); if (type == T_INT)
sprintf(value, "%s", git_config_bool(key_, value_) sprintf(value, "%d", git_config_int(key_, value_));
? "true" : "false"); else if (type == T_BOOL)
} else { vptr = git_config_bool(key_, value_) ? "true" : "false";
value = strdup(value_); else
} vptr = value_;
seen++; seen++;
if (dup_error) {
error("More than one value for the key %s: %s",
key_, vptr);
} }
else
printf("%s\n", vptr);
return 0; return 0;
} }
@ -63,6 +71,14 @@ static int get_value(const char* key_, const char* regex_)
key[i] = tolower(key_[i]); key[i] = tolower(key_[i]);
key[i] = 0; key[i] = 0;
if (use_key_regexp) {
key_regexp = (regex_t*)malloc(sizeof(regex_t));
if (regcomp(key_regexp, key, REG_EXTENDED)) {
fprintf(stderr, "Invalid key pattern: %s\n", key_);
return -1;
}
}
if (regex_) { if (regex_) {
if (regex_[0] == '!') { if (regex_[0] == '!') {
do_not_match = 1; do_not_match = 1;
@ -77,10 +93,6 @@ static int get_value(const char* key_, const char* regex_)
} }
git_config(show_config); git_config(show_config);
if (value) {
printf("%s\n", value);
free(value);
}
free(key); free(key);
if (regexp) { if (regexp) {
regfree(regexp); regfree(regexp);
@ -88,9 +100,9 @@ static int get_value(const char* key_, const char* regex_)
} }
if (do_all) if (do_all)
return 0; return !seen;
return seen == 1 ? 0 : 1; return (seen == 1) ? 0 : 1;
} }
int main(int argc, const char **argv) int main(int argc, const char **argv)
@ -123,6 +135,11 @@ int main(int argc, const char **argv)
else if (!strcmp(argv[1], "--get-all")) { else if (!strcmp(argv[1], "--get-all")) {
do_all = 1; do_all = 1;
return get_value(argv[2], NULL); return get_value(argv[2], NULL);
} else if (!strcmp(argv[1], "--get-regexp")) {
show_keys = 1;
use_key_regexp = 1;
do_all = 1;
return get_value(argv[2], NULL);
} else } else
return git_config_set(argv[1], argv[2]); return git_config_set(argv[1], argv[2]);
@ -136,6 +153,11 @@ int main(int argc, const char **argv)
else if (!strcmp(argv[1], "--get-all")) { else if (!strcmp(argv[1], "--get-all")) {
do_all = 1; do_all = 1;
return get_value(argv[2], argv[3]); return get_value(argv[2], argv[3]);
} else if (!strcmp(argv[1], "--get-regexp")) {
show_keys = 1;
use_key_regexp = 1;
do_all = 1;
return get_value(argv[2], argv[3]);
} else if (!strcmp(argv[1], "--replace-all")) } else if (!strcmp(argv[1], "--replace-all"))
return git_config_set_multivar(argv[2], argv[3], NULL, 1); return git_config_set_multivar(argv[2], argv[3], NULL, 1);

View File

@ -574,7 +574,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
revs->max_count = atoi(arg + 12); revs->max_count = atoi(arg + 12);
continue; continue;
} }
/* accept -<digit>, like traditilnal "head" */ /* accept -<digit>, like traditional "head" */
if ((*arg == '-') && isdigit(arg[1])) { if ((*arg == '-') && isdigit(arg[1])) {
revs->max_count = atoi(arg + 1); revs->max_count = atoi(arg + 1);
continue; continue;
@ -694,6 +694,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
} }
if (!strcmp(arg, "-c")) { if (!strcmp(arg, "-c")) {
revs->diff = 1; revs->diff = 1;
revs->dense_combined_merges = 0;
revs->combine_merges = 1; revs->combine_merges = 1;
continue; continue;
} }

View File

@ -108,9 +108,10 @@ int safe_create_leading_directories(char *path)
char * sha1_to_hex(const unsigned char *sha1) char * sha1_to_hex(const unsigned char *sha1)
{ {
static char buffer[50]; static int bufno;
static char hexbuffer[4][50];
static const char hex[] = "0123456789abcdef"; static const char hex[] = "0123456789abcdef";
char *buf = buffer; char *buffer = hexbuffer[3 & ++bufno], *buf = buffer;
int i; int i;
for (i = 0; i < 20; i++) { for (i = 0; i < 20; i++) {

View File

@ -5,7 +5,7 @@
#include "refs.h" #include "refs.h"
static const char show_branch_usage[] = static const char show_branch_usage[] =
"git-show-branch [--current] [--all] [--heads] [--tags] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...]"; "git-show-branch [--dense] [--current] [--all] [--heads] [--tags] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...]";
static int default_num = 0; static int default_num = 0;
static int default_alloc = 0; static int default_alloc = 0;
@ -527,6 +527,27 @@ static int git_show_branch_config(const char *var, const char *value)
return git_default_config(var, value); return git_default_config(var, value);
} }
static int omit_in_dense(struct commit *commit, struct commit **rev, int n)
{
/* If the commit is tip of the named branches, do not
* omit it.
* Otherwise, if it is a merge that is reachable from only one
* tip, it is not that interesting.
*/
int i, flag, count;
for (i = 0; i < n; i++)
if (rev[i] == commit)
return 0;
flag = commit->object.flags;
for (i = count = 0; i < n; i++) {
if (flag & (1u << (i + REV_SHIFT)))
count++;
}
if (count == 1)
return 1;
return 0;
}
int main(int ac, char **av) int main(int ac, char **av)
{ {
struct commit *rev[MAX_REVS], *commit; struct commit *rev[MAX_REVS], *commit;
@ -548,6 +569,7 @@ int main(int ac, char **av)
int with_current_branch = 0; int with_current_branch = 0;
int head_at = -1; int head_at = -1;
int topics = 0; int topics = 0;
int dense = 1;
setup_git_directory(); setup_git_directory();
git_config(git_show_branch_config); git_config(git_show_branch_config);
@ -590,6 +612,8 @@ int main(int ac, char **av)
lifo = 1; lifo = 1;
else if (!strcmp(arg, "--topics")) else if (!strcmp(arg, "--topics"))
topics = 1; topics = 1;
else if (!strcmp(arg, "--sparse"))
dense = 0;
else if (!strcmp(arg, "--date-order")) else if (!strcmp(arg, "--date-order"))
lifo = 0; lifo = 0;
else else
@ -732,12 +756,15 @@ int main(int ac, char **av)
shown_merge_point |= is_merge_point; shown_merge_point |= is_merge_point;
if (1 < num_rev) { if (1 < num_rev) {
int is_merge = !!(commit->parents && commit->parents->next); int is_merge = !!(commit->parents &&
commit->parents->next);
if (topics && if (topics &&
!is_merge_point && !is_merge_point &&
(this_flag & (1u << REV_SHIFT))) (this_flag & (1u << REV_SHIFT)))
continue; continue;
if (dense && is_merge &&
omit_in_dense(commit, rev, num_rev))
continue;
for (i = 0; i < num_rev; i++) { for (i = 0; i < num_rev; i++) {
int mark; int mark;
if (!(this_flag & (1u << (i + REV_SHIFT)))) if (!(this_flag & (1u << (i + REV_SHIFT))))

View File

@ -247,6 +247,24 @@ EOF
test_expect_success 'hierarchical section value' 'cmp .git/config expect' test_expect_success 'hierarchical section value' 'cmp .git/config expect'
cat > expect << EOF
beta.noindent=sillyValue
nextsection.nonewline=wow2 for me
123456.a123=987
1.2.3.alpha=beta
EOF
test_expect_success 'working --list' \
'git-repo-config --list > output && cmp output expect'
cat > expect << EOF
beta.noindent sillyValue
nextsection.nonewline wow2 for me
EOF
test_expect_success '--get-regexp' \
'git-repo-config --get-regexp in > output && cmp output expect'
cat > .git/config << EOF cat > .git/config << EOF
[novalue] [novalue]
variable variable
@ -255,5 +273,41 @@ EOF
test_expect_success 'get variable with no value' \ test_expect_success 'get variable with no value' \
'git-repo-config --get novalue.variable ^$' 'git-repo-config --get novalue.variable ^$'
git-repo-config > output 2>&1
test_expect_success 'no arguments, but no crash' \
"test $? = 129 && grep usage output"
cat > .git/config << EOF
[a.b]
c = d
EOF
git-repo-config a.x y
cat > expect << EOF
[a.b]
c = d
[a]
x = y
EOF
test_expect_success 'new section is partial match of another' 'cmp .git/config expect'
git-repo-config b.x y
git-repo-config a.b c
cat > expect << EOF
[a.b]
c = d
[a]
x = y
b = c
[b]
x = y
EOF
test_expect_success 'new variable inserts into proper section' 'cmp .git/config expect'
test_done test_done

View File

@ -364,23 +364,26 @@ static void update_one(const char *path, const char *prefix, int prefix_length)
const char *p = prefix_path(prefix, prefix_length, path); const char *p = prefix_path(prefix, prefix_length, path);
if (!verify_path(p)) { if (!verify_path(p)) {
fprintf(stderr, "Ignoring path %s\n", path); fprintf(stderr, "Ignoring path %s\n", path);
return; goto free_return;
} }
if (mark_valid_only) { if (mark_valid_only) {
if (mark_valid(p)) if (mark_valid(p))
die("Unable to mark file %s", path); die("Unable to mark file %s", path);
return; goto free_return;
} }
if (force_remove) { if (force_remove) {
if (remove_file_from_cache(p)) if (remove_file_from_cache(p))
die("git-update-index: unable to remove %s", path); die("git-update-index: unable to remove %s", path);
report("remove '%s'", path); report("remove '%s'", path);
return; goto free_return;
} }
if (add_file_to_cache(p)) if (add_file_to_cache(p))
die("Unable to process file %s", path); die("Unable to process file %s", path);
report("add '%s'", path); report("add '%s'", path);
free_return:
if (p < path || p > path + strlen(path))
free((char*)p);
} }
static void read_index_info(int line_termination) static void read_index_info(int line_termination)
@ -473,7 +476,7 @@ static void read_index_info(int line_termination)
} }
static const char update_index_usage[] = static const char update_index_usage[] =
"git-update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--cacheinfo] [--chmod=(+|-)x] [--info-only] [--force-remove] [--stdin] [--index-info] [--ignore-missing] [-z] [--verbose] [--] <file>..."; "git-update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--really-refresh] [--cacheinfo] [--chmod=(+|-)x] [--assume-unchanged] [--info-only] [--force-remove] [--stdin] [--index-info] [--unresolve] [--ignore-missing] [-z] [--verbose] [--] <file>...";
static unsigned char head_sha1[20]; static unsigned char head_sha1[20];
static unsigned char merge_head_sha1[20]; static unsigned char merge_head_sha1[20];
@ -576,7 +579,8 @@ static void read_head_pointers(void)
} }
} }
static int do_unresolve(int ac, const char **av) static int do_unresolve(int ac, const char **av,
const char *prefix, int prefix_length)
{ {
int i; int i;
int err = 0; int err = 0;
@ -588,7 +592,10 @@ static int do_unresolve(int ac, const char **av)
for (i = 1; i < ac; i++) { for (i = 1; i < ac; i++) {
const char *arg = av[i]; const char *arg = av[i];
err |= unresolve_one(arg); const char *p = prefix_path(prefix, prefix_length, arg);
err |= unresolve_one(p);
if (p < arg || p > arg + strlen(arg))
free((char*)p);
} }
return err; return err;
} }
@ -704,7 +711,8 @@ int main(int argc, const char **argv)
break; break;
} }
if (!strcmp(path, "--unresolve")) { if (!strcmp(path, "--unresolve")) {
has_errors = do_unresolve(argc - i, argv + i); has_errors = do_unresolve(argc - i, argv + i,
prefix, prefix_length);
if (has_errors) if (has_errors)
active_cache_changed = 0; active_cache_changed = 0;
goto finish; goto finish;
@ -730,6 +738,7 @@ int main(int argc, const char **argv)
strbuf_init(&buf); strbuf_init(&buf);
while (1) { while (1) {
char *path_name; char *path_name;
const char *p;
read_line(&buf, stdin, line_termination); read_line(&buf, stdin, line_termination);
if (buf.eof) if (buf.eof)
break; break;
@ -737,11 +746,12 @@ int main(int argc, const char **argv)
path_name = unquote_c_style(buf.buf, NULL); path_name = unquote_c_style(buf.buf, NULL);
else else
path_name = buf.buf; path_name = buf.buf;
update_one(path_name, prefix, prefix_length); p = prefix_path(prefix, prefix_length, path_name);
if (set_executable_bit) { update_one(p, NULL, 0);
const char *p = prefix_path(prefix, prefix_length, path_name); if (set_executable_bit)
chmod_path(set_executable_bit, p); chmod_path(set_executable_bit, p);
} if (p < path_name || p > path_name + strlen(path_name))
free((char*) p);
if (path_name != buf.buf) if (path_name != buf.buf)
free(path_name); free(path_name);
} }