Merge branch 'master' into js/diff-ni

* master: (201 commits)
  Documentation: link in 1.5.0.2 material to the top documentation page.
  Documentation: document remote.<name>.tagopt
  GIT 1.5.0.2
  git-remote: support remotes with a dot in the name
  Documentation: describe "-f/-t/-m" options to "git-remote add"
  diff --cc: fix display of symlink conflicts during a merge.
  merge-recursive: fix longstanding bug in merging symlinks
  merge-index: fix longstanding bug in merging symlinks
  diff --cached: give more sensible error message when HEAD is yet to be created.
  Update tests to use test-chmtime
  Add test-chmtime: a utility to change mtime on files
  Add Release Notes to prepare for 1.5.0.2
  Allow arbitrary number of arguments to git-pack-objects
  rerere: do not deal with symlinks.
  rerere: do not skip two conflicted paths next to each other.
  Don't modify CREDITS-FILE if it hasn't changed.
  diff-patch: Avoid emitting double-slashes in textual patch.
  Reword git-am 3-way fallback failure message.
  Limit filename for format-patch
  core.legacyheaders: Use the description used in RelNotes-1.5.0
  ...
This commit is contained in:
Junio C Hamano 2007-02-26 01:20:42 -08:00
commit 048f48a2fd
109 changed files with 6766 additions and 2952 deletions

1
.gitignore vendored
View file

@ -139,6 +139,7 @@ git-whatchanged
git-write-tree
git-core-*/?*
gitweb/gitweb.cgi
test-chmtime
test-date
test-delta
test-dump-cache-tree

View file

@ -27,6 +27,7 @@ Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Ramsay Allan Jones <ramsay@ramsay1.demon.co.uk>
René Scharfe <rene.scharfe@lsrfire.ath.cx>
Robert Fitzsimons <robfitz@273k.net>
Sam Vilain <sam@vilain.net>
Santi Béjar <sbejar@gmail.com>
Sean Estabrooks <seanlkml@sympatico.ca>
Shawn O. Pearce <spearce@spearce.org>

View file

@ -0,0 +1,65 @@
GIT v1.5.0.2 Release Notes
==========================
Fixes since v1.5.0.1
--------------------
* Bugfixes
- Automated merge conflict handling when changes to symbolic
links conflicted were completely broken. The merge-resolve
strategy created a regular file with conflict markers in it
in place of the symbolic link. The default strategy,
merge-recursive was even more broken. It removed the path
that was pointed at by the symbolic link. Both of these
problems have been fixed.
- 'git diff maint master next' did not correctly give combined
diff across three trees.
- 'git fast-import' portability fix for Solaris.
- 'git show-ref --verify' without arguments did not error out
but segfaulted.
- 'git diff :tracked-file `pwd`/an-untracked-file' gave an extra
slashes after a/ and b/.
- 'git format-patch' produced too long filenames if the commit
message had too long line at the beginning.
- Running 'make all' and then without changing anything
running 'make install' still rebuilt some files. This
was inconvenient when building as yourself and then
installing as root (especially problematic when the source
directory is on NFS and root is mapped to nobody).
- 'git-rerere' failed to deal with two unconflicted paths that
sorted next to each other.
- 'git-rerere' attempted to open(2) a symlink and failed if
there was a conflict. Since a conflicting change to a
symlink would not benefit from rerere anyway, the command
now ignores conflicting changes to symlinks.
- 'git-repack' did not like to pass more than 64 arguments
internally to underlying 'rev-list' logic, which made it
impossible to repack after accumulating many (small) packs
in the repository.
- 'git-diff' to review the combined diff during a conflicted
merge were not reading the working tree version correctly
when changes to a symbolic link conflicted. It should have
read the data using readlink(2) but read from the regular
file the symbolic link pointed at.
- 'git-remote' did not like period in a remote's name.
* Documentation updates
- added and clarified core.bare, core.legacyheaders configurations.
- updated "git-clone --depth" documentation.
* Assorted git-gui fixes.

View file

@ -448,7 +448,7 @@ Updates in v1.5.0 since v1.4.4 series
- There is a partial support for 'shallow' repositories that
keeps only recent history. A 'shallow clone' is created by
specifying how deep that truncated history should be
(e.g. "git clone --depth=5 git://some.where/repo.git").
(e.g. "git clone --depth 5 git://some.where/repo.git").
Currently a shallow repository has number of limitations:

View file

@ -5,7 +5,8 @@ The git configuration file contains a number of variables that affect
the git command's behavior. `.git/config` file for each repository
is used to store the information for that repository, and
`$HOME/.gitconfig` is used to store per user information to give
fallback values for `.git/config` file.
fallback values for `.git/config` file. The file `/etc/gitconfig`
can be used to store system-wide defaults.
They can be used by both the git plumbing
and the porcelains. The variables are divided into sections, where
@ -142,6 +143,18 @@ core.preferSymlinkRefs::
This is sometimes needed to work with old scripts that
expect HEAD to be a symbolic link.
core.bare::
If true this repository is assumed to be 'bare' and has no
working directory associated with it. If this is the case a
number of commands that require a working directory will be
disabled, such as gitlink:git-add[1] or gitlink:git-merge[1].
+
This setting is automatically guessed by gitlink:git-clone[1] or
gitlink:git-init[1] when the repository was created. By default a
repository that ends in "/.git" is assumed to be not bare (bare =
false), while all other repositories are assumed to be bare (bare
= true).
core.logAllRefUpdates::
Updates to a ref <ref> is logged to the file
"$GIT_DIR/logs/<ref>", by appending the new and old
@ -180,10 +193,17 @@ core.compression::
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).
A boolean which
changes the format of loose objects so that they are more
efficient to pack and to send out of the repository over git
native protocol, since v1.4.2. However, loose objects
written in the new format cannot be read by git older than
that version; people fetching from your repository using
older versions of git over dumb transports (e.g. http)
will also be affected.
+
To let git use the new loose object format, you have to
set core.legacyheaders to false.
core.packedGitWindowSize::
Number of bytes of a pack file to map into memory in a
@ -451,6 +471,10 @@ remote.<name>.push::
The default set of "refspec" for gitlink:git-push[1]. See
gitlink:git-push[1].
remote.<name>.skipDefaultUpdate::
If true, this remote will be skipped by default when updating
using the remote subcommand of gitlink:git-remote[1].
remote.<name>.receivepack::
The default program to execute on the remote side when pushing. See
option \--exec of gitlink:git-push[1].
@ -459,6 +483,14 @@ remote.<name>.uploadpack::
The default program to execute on the remote side when fetching. See
option \--exec of gitlink:git-fetch-pack[1].
remote.<name>.tagopt::
Setting this value to --no-tags disables automatic tag following when fetching
from remote <name>
remotes.<group>::
The list of remotes which are fetched by "git remote update
<group>". See gitlink:git-remote[1].
repack.usedeltabaseoffset::
Allow gitlink:git-repack[1] to create packs that uses
delta-base offset. Defaults to false.

View file

@ -11,7 +11,7 @@ SYNOPSIS
[verse]
'git-clone' [--template=<template_directory>] [-l [-s]] [-q] [-n] [--bare]
[-o <name>] [-u <upload-pack>] [--reference <repository>]
[--depth=<depth>] <repository> [<directory>]
[--depth <depth>] <repository> [<directory>]
DESCRIPTION
-----------
@ -96,7 +96,7 @@ OPTIONS
if unset the templates are taken from the installation
defined default, typically `/usr/share/git-core/templates`.
--depth=<depth>::
--depth <depth>::
Create a 'shallow' clone with a history truncated to the
specified number of revs. A shallow repository has
number of limitations (you cannot clone or fetch from

View file

@ -8,7 +8,7 @@ git-cvsexportcommit - Export a single commit to a CVS checkout
SYNOPSIS
--------
'git-cvsexportcommit' [-h] [-v] [-c] [-P] [-p] [-a] [-f] [-m msgprefix] [PARENTCOMMIT] COMMITID
'git-cvsexportcommit' [-h] [-v] [-c] [-P] [-p] [-a] [-d cvsroot] [-f] [-m msgprefix] [PARENTCOMMIT] COMMITID
DESCRIPTION
@ -43,6 +43,11 @@ OPTIONS
Add authorship information. Adds Author line, and Committer (if
different from Author) to the message.
-d::
Set an alternative CVSROOT to use. This corresponds to the CVS
-d parameter. Usually users will not want to set this, except
if using CVS in an asymmetric fashion.
-f::
Force the merge even if the files are not up to date.

View file

@ -13,6 +13,7 @@ SYNOPSIS
'git-remote' add <name> <url>
'git-remote' show <name>
'git-remote' prune <name>
'git-remote' update [group]
DESCRIPTION
-----------
@ -31,6 +32,19 @@ subcommands are available to perform operations on the remotes.
Adds a remote named <name> for the repository at
<url>. The command `git fetch <name>` can then be used to create and
update remote-tracking branches <name>/<branch>.
+
With `-f` option, `git fetch <name>` is run immediately after
the remote information is set up.
+
With `-t <branch>` option, instead of the default glob
refspec for the remote to track all branches under
`$GIT_DIR/remotes/<name>/`, a refspec to track only `<branch>`
is created. You can give more than one `-t <branch>` to track
multiple branche without grabbing all branches.
+
With `-m <master>` option, `$GIT_DIR/remotes/<name>/HEAD` is set
up to point at remote's `<master>` branch instead of whatever
branch the `HEAD` at the remote repository actually points at.
'show'::
@ -40,7 +54,17 @@ Gives some information about the remote <name>.
Deletes all stale tracking branches under <name>.
These stale branches have already been removed from the remote repository
referenced by <name>, but are still locally available in "remotes/<name>".
referenced by <name>, but are still locally available in
"remotes/<name>".
'update'::
Fetch updates for a named set of remotes in the repository as defined by
remotes.<group>. If a named group is not specified on the command line,
the configuration parameter remotes.default will get used; if
remotes.default is not defined, all remotes which do not the
configuration parameter remote.<name>.skipDefaultUpdate set to true will
be updated. (See gitlink:git-config[1]).
DISCUSSION

View file

@ -13,14 +13,13 @@ DESCRIPTION
-----------
git-svn is a simple conduit for changesets between Subversion and git.
It is not to be confused with gitlink:git-svnimport[1], which is
read-only and geared towards tracking multiple branches.
read-only.
git-svn was originally designed for an individual developer who wants a
bidirectional flow of changesets between a single branch in Subversion
and an arbitrary number of branches in git. Since its inception,
git-svn has gained the ability to track multiple branches in a manner
similar to git-svnimport; but it cannot (yet) automatically detect new
branches and tags like git-svnimport does.
similar to git-svnimport.
git-svn is especially useful when it comes to tracking repositories
not organized in the way Subversion developers recommend (trunk,
@ -31,26 +30,80 @@ COMMANDS
--
'init'::
Creates an empty git repository with additional metadata
directories for git-svn. The Subversion URL must be specified
as a command-line argument. Optionally, the target directory
to operate on can be specified as a second argument. Normally
this command initializes the current directory.
Initializes an empty git repository with additional
metadata directories for git-svn. The Subversion URL
may be specified as a command-line argument, or as full
URL arguments to -T/-t/-b. Optionally, the target
directory to operate on can be specified as a second
argument. Normally this command initializes the current
directory.
-T<trunk_subdir>::
--trunk=<trunk_subdir>::
-t<tags_subdir>::
--tags=<tags_subdir>::
-b<branches_subdir>::
--branches=<branches_subdir>::
These are optional command-line options for init. Each of
these flags can point to a relative repository path
(--tags=project/tags') or a full url
(--tags=https://foo.org/project/tags)
--no-metadata::
Set the 'noMetadata' option in the [svn-remote] config.
--use-svm-props::
Set the 'useSvmProps' option in the [svn-remote] config.
--use-svnsync-props::
Set the 'useSvnsyncProps' option in the [svn-remote] config.
--rewrite-root=<URL>::
Set the 'rewriteRoot' option in the [svn-remote] config.
--username=<USER>::
For transports that SVN handles authentication for (http,
https, and plain svn), specify the username. For other
transports (eg svn+ssh://), you must include the username in
the URL, eg svn+ssh://foo@svn.bar.com/project
--prefix=<prefix>
This allows one to specify a prefix which is prepended
to the names of remotes if trunk/branches/tags are
specified. The prefix does not automatically include a
trailing slash, so be sure you include one in the
argument if that is what you want. This is useful if
you wish to track multiple projects that share a common
repository.
'fetch'::
Fetch unfetched revisions from the Subversion URL we are
tracking. refs/remotes/git-svn will be updated to the
latest revision.
Fetch unfetched revisions from the Subversion remote we are
tracking. The name of the [svn-remote "..."] section in the
.git/config file may be specified as an optional command-line
argument.
Note: You should never attempt to modify the remotes/git-svn
branch outside of git-svn. Instead, create a branch from
remotes/git-svn and work on that branch. Use the 'dcommit'
command (see below) to write git commits back to
remotes/git-svn.
'clone'::
Runs 'init' and 'fetch'. It will automatically create a
directory based on the basename of the URL passed to it;
or if a second argument is passed; it will create a directory
and work within that. It accepts all arguments that the
'init' and 'fetch' commands accept; with the exception of
'--fetch-all'. After a repository is cloned, the 'fetch'
command will be able to update revisions without affecting
the working tree; and the 'rebase' command will be able
to update the working tree with the latest changes.
See '<<fetch-args,Additional Fetch Arguments>>' if you are interested in
manually joining branches on commit.
'rebase'::
This fetches revisions from the SVN parent of the current HEAD
and rebases the current (uncommitted to SVN) work against it.
This works similarly to 'svn update' or 'git-pull' except that
it preserves linear history with 'git-rebase' instead of
'git-merge' for ease of dcommit-ing with git-svn.
This accepts all options that 'git-svn fetch' and 'git-rebase'
accepts. However '--fetch-all' only fetches from the current
[svn-remote], and not all [svn-remote] definitions.
Like 'git-rebase'; this requires that the working tree be clean
and have no uncommitted changes.
'dcommit'::
Commit each diff from a specified head directly to the SVN
@ -96,16 +149,6 @@ manually joining branches on commit.
commit. All merging is assumed to have taken place
independently of git-svn functions.
'rebuild'::
Not a part of daily usage, but this is a useful command if
you've just cloned a repository (using gitlink:git-clone[1]) that was
tracked with git-svn. Unfortunately, git-clone does not clone
git-svn metadata and the svn working tree that git-svn uses for
its operations. This rebuilds the metadata so git-svn can
resume fetch operations. A Subversion URL may be optionally
specified at the command-line if the directory/repository you're
tracking has moved or changed protocols.
'show-ignore'::
Recursively finds and lists the svn:ignore property on
directories. The output is suitable for appending to
@ -122,53 +165,13 @@ manually joining branches on commit.
repository (that has been init-ed with git-svn).
The -r<revision> option is required for this.
'graft-branches'::
This command attempts to detect merges/branches from already
imported history. Techniques used currently include regexes,
file copies, and tree-matches). This command generates (or
modifies) the $GIT_DIR/info/grafts file. This command is
considered experimental, and inherently flawed because
merge-tracking in SVN is inherently flawed and inconsistent
across different repositories.
'multi-init'::
This command supports git-svnimport-like command-line syntax for
importing repositories that are laid out as recommended by the
SVN folks. This is a bit more tolerant than the git-svnimport
command-line syntax and doesn't require the user to figure out
where the repository URL ends and where the repository path
begins.
-T<trunk_subdir>::
--trunk=<trunk_subdir>::
-t<tags_subdir>::
--tags=<tags_subdir>::
-b<branches_subdir>::
--branches=<branches_subdir>::
These are the command-line options for multi-init. Each of
these flags can point to a relative repository path
(--tags=project/tags') or a full url
(--tags=https://foo.org/project/tags)
--prefix=<prefix>
This allows one to specify a prefix which is prepended to the
names of remotes. The prefix does not automatically include a
trailing slash, so be sure you include one in the argument if
that is what you want. This is useful if you wish to track
multiple projects that share a common repository.
'multi-fetch'::
This runs fetch on all known SVN branches we're tracking. This
will NOT discover new branches (unlike git-svnimport), so
multi-init will need to be re-run (it's idempotent).
--
OPTIONS
-------
--
--shared::
--shared[={false|true|umask|group|all|world|everybody}]::
--template=<template_directory>::
Only used with the 'init' command.
These are passed directly to gitlink:git-init[1].
@ -176,14 +179,15 @@ OPTIONS
-r <ARG>::
--revision <ARG>::
Only used with the 'fetch' command.
Used with the 'fetch' command.
Takes any valid -r<argument> svn would accept and passes it
directly to svn. -r<ARG1>:<ARG2> ranges and "{" DATE "}" syntax
is also supported. This is passed directly to svn, see svn
documentation for more details.
This allows revision ranges for partial/cauterized history
to be supported. $NUMBER, $NUMBER1:$NUMBER2 (numeric ranges),
$NUMBER:HEAD, and BASE:$NUMBER are all supported.
This can allow you to make partial mirrors when running fetch.
This can allow you to make partial mirrors when running fetch;
but is generally not recommended because history will be skipped
and lost.
-::
--stdin::
@ -270,7 +274,7 @@ config key: svn.repackflags
-s<strategy>::
--strategy=<strategy>::
These are only used with the 'dcommit' command.
These are only used with the 'dcommit' and 'rebase' commands.
Passed directly to git-rebase when using 'dcommit' if a
'git-reset' cannot be used (see dcommit).
@ -289,75 +293,79 @@ ADVANCED OPTIONS
----------------
--
-b<refname>::
--branch <refname>::
Used with 'fetch', 'dcommit' or 'set-tree'.
This can be used to join arbitrary git branches to remotes/git-svn
on new commits where the tree object is equivalent.
When used with different GIT_SVN_ID values, tags and branches in
SVN can be tracked this way, as can some merges where the heads
end up having completely equivalent content. This can even be
used to track branches across multiple SVN _repositories_.
This option may be specified multiple times, once for each
branch.
config key: svn.branch
-i<GIT_SVN_ID>::
--id <GIT_SVN_ID>::
This sets GIT_SVN_ID (instead of using the environment). See the
section on
'<<tracking-multiple-repos,Tracking Multiple Repositories or Branches>>'
for more information on using GIT_SVN_ID.
This sets GIT_SVN_ID (instead of using the environment). This
allows the user to override the default refname to fetch from
when tracking a single URL. The 'log' and 'dcommit' commands
no longer require this switch as an argument.
-R<remote name>::
--svn-remote <remote name>::
Specify the [svn-remote "<remote name>"] section to use,
this allows SVN multiple repositories to be tracked.
Default: "svn"
--follow-parent::
This is especially helpful when we're tracking a directory
that has been moved around within the repository, or if we
started tracking a branch and never tracked the trunk it was
descended from.
descended from. This feature is enabled by default, use
--no-follow-parent to disable it.
config key: svn.followparent
--no-metadata::
--
CONFIG FILE-ONLY OPTIONS
------------------------
--
svn.noMetadata::
svn-remote.<name>.noMetadata::
This gets rid of the git-svn-id: lines at the end of every commit.
With this, you lose the ability to use the rebuild command. If
you ever lose your .git/svn/git-svn/.rev_db file, you won't be
able to fetch again, either. This is fine for one-shot imports.
If you lose your .git/svn/git-svn/.rev_db file, git-svn will not
be able to rebuild it and you won't be able to fetch again,
either. This is fine for one-shot imports.
The 'git-svn log' command will not work on repositories using this,
either.
The 'git-svn log' command will not work on repositories using
this, either. Using this conflicts with the 'useSvmProps'
option for (hopefully) obvious reasons.
config key: svn.nometadata
svn.useSvmProps::
svn-remote.<name>.useSvmProps::
This allows git-svn to re-map repository URLs and UUIDs from
mirrors created using SVN::Mirror (or svk) for metadata.
--
If an SVN revision has a property, "svm:headrev", it is likely
that the revision was created by SVN::Mirror (also used by SVK).
The property contains a repository UUID and a revision. We want
to make it look like we are mirroring the original URL, so
introduce a helper function that returns the original identity
URL and UUID, and use it when generating metadata in commit
messages.
COMPATIBILITY OPTIONS
---------------------
--
svn.useSvnsyncProps::
svn-remote.<name>.useSvnsyncprops::
Similar to the useSvmProps option; this is for users
of the svnsync(1) command distributed with SVN 1.4.x and
later.
--upgrade::
Only used with the 'rebuild' command.
svn-remote.<name>.rewriteRoot::
This allows users to create repositories from alternate
URLs. For example, an administrator could run git-svn on the
server locally (accessing via file://) but wish to distribute
the repository with a public http:// or svn:// URL in the
metadata so users of it will see the public URL.
Run this if you used an old version of git-svn that used
"git-svn-HEAD" instead of "remotes/git-svn" as the branch
for tracking the remote.
Since the noMetadata, rewriteRoot, useSvnsyncProps and useSvmProps
options all affect the metadata generated and used by git-svn; they
*must* be set in the configuration file before any history is imported
and these settings should never be changed once they are set.
--ignore-nodate::
Only used with the 'fetch' command.
By default git-svn will crash if it tries to import a revision
from SVN which has '(no date)' listed as the date of the revision.
This is repository corruption on SVN's part, plain and simple.
But sometimes you really need those revisions anyway.
If supplied git-svn will convert '(no date)' entries to the UNIX
epoch (midnight on Jan. 1, 1970). Yes, that's probably very wrong.
SVN was very wrong.
Additionally, only one of these four options can be used per-svn-remote
section because they affect the 'git-svn-id:' metadata line.
--
@ -367,43 +375,37 @@ Basic Examples
Tracking and contributing to a the trunk of a Subversion-managed project:
------------------------------------------------------------------------
# Initialize a repo (like git init):
git-svn init http://svn.foo.org/project/trunk
# Fetch remote revisions:
git-svn fetch
# Create your own branch to hack on:
git checkout -b my-branch remotes/git-svn
# Do some work, and then commit your new changes to SVN, as well as
# automatically updating your working HEAD:
# Clone a repo (like git clone):
git-svn clone http://svn.foo.org/project/trunk
# Enter the newly cloned directory:
cd trunk
# You should be on master branch, double-check with git-branch
git branch
# Do some work and commit locally to git:
git commit ...
# Something is committed to SVN, rebase your local changes against the
# latest changes in SVN:
git-svn rebase
# Now commit your changes (that were committed previously using git) to SVN,
# as well as automatically updating your working HEAD:
git-svn dcommit
# Something is committed to SVN, rebase the latest into your branch:
git-svn fetch && git rebase remotes/git-svn
# Append svn:ignore settings to the default git exclude file:
git-svn show-ignore >> .git/info/exclude
------------------------------------------------------------------------
Tracking and contributing to an entire Subversion-managed project
(complete with a trunk, tags and branches):
See also:
'<<tracking-multiple-repos,Tracking Multiple Repositories or Branches>>'
------------------------------------------------------------------------
# Initialize a repo (like git init):
git-svn multi-init http://svn.foo.org/project \
-T trunk -b branches -t tags
# Fetch remote revisions:
git-svn multi-fetch
# Create your own branch of trunk to hack on:
git checkout -b my-trunk remotes/trunk
# Do some work, and then commit your new changes to SVN, as well as
# automatically updating your working HEAD:
git-svn dcommit -i trunk
# Something has been committed to trunk, rebase the latest into your branch:
git-svn multi-fetch && git rebase remotes/trunk
# Append svn:ignore settings of trunk to the default git exclude file:
git-svn show-ignore -i trunk >> .git/info/exclude
# Check for new branches and tags (no arguments are needed):
git-svn multi-init
# Clone a repo (like git clone):
git-svn clone http://svn.foo.org/project -T trunk -b branches -t tags
# View all branches and tags you have cloned:
git branch -r
# Reset your master to trunk (or any other branch, replacing 'trunk'
# with the appropriate name):
git reset --hard remotes/trunk
# You may only dcommit to one branch/tag/trunk at a time. The usage
# of dcommit/rebase/show-ignore should be teh same as above.
------------------------------------------------------------------------
REBASE VS. PULL/MERGE
@ -416,7 +418,7 @@ pulled or merged from. This is because the author favored
If you use 'git-svn set-tree A..B' to commit several diffs and you do
not have the latest remotes/git-svn merged into my-branch, you should
use 'git rebase' to update your work branch instead of 'git pull' or
use 'git-svn rebase' to update your work branch instead of 'git pull' or
'git merge'. 'pull/merge' can cause non-linear history to be flattened
when committing into SVN, which can lead to merge commits reversing
previous commits in SVN.
@ -426,67 +428,49 @@ DESIGN PHILOSOPHY
Merge tracking in Subversion is lacking and doing branched development
with Subversion is cumbersome as a result. git-svn does not do
automated merge/branch tracking by default and leaves it entirely up to
the user on the git side.
[[tracking-multiple-repos]]
TRACKING MULTIPLE REPOSITORIES OR BRANCHES
------------------------------------------
Because git-svn does not care about relationships between different
branches or directories in a Subversion repository, git-svn has a simple
hack to allow it to track an arbitrary number of related _or_ unrelated
SVN repositories via one git repository. Simply use the --id/-i flag or
set the GIT_SVN_ID environment variable to a name other other than
"git-svn" (the default) and git-svn will ignore the contents of the
$GIT_DIR/svn/git-svn directory and instead do all of its work in
$GIT_DIR/svn/$GIT_SVN_ID for that invocation. The interface branch will
be remotes/$GIT_SVN_ID, instead of remotes/git-svn. Any
remotes/$GIT_SVN_ID branch should never be modified by the user outside
of git-svn commands.
[[fetch-args]]
ADDITIONAL FETCH ARGUMENTS
--------------------------
This is for advanced users, most users should ignore this section.
Unfetched SVN revisions may be imported as children of existing commits
by specifying additional arguments to 'fetch'. Additional parents may
optionally be specified in the form of sha1 hex sums at the
command-line. Unfetched SVN revisions may also be tied to particular
git commits with the following syntax:
------------------------------------------------
svn_revision_number=git_commit_sha1
------------------------------------------------
This allows you to tie unfetched SVN revision 375 to your current HEAD:
------------------------------------------------
git-svn fetch 375=$(git-rev-parse HEAD)
------------------------------------------------
If you're tracking a directory that has moved, or otherwise been
branched or tagged off of another directory in the repository and you
care about the full history of the project, then you can use
the --follow-parent option.
------------------------------------------------
git-svn fetch --follow-parent
------------------------------------------------
the user on the git side. git-svn does however follow copy
history of the directory that it is tracking, however (much like
how 'svn log' works).
BUGS
----
We ignore all SVN properties except svn:executable. Too difficult to
map them since we rely heavily on git write-tree being _exactly_ the
same on both the SVN and git working trees and I prefer not to clutter
working trees with metadata files.
We ignore all SVN properties except svn:executable. Any unhandled
properties are logged to $GIT_DIR/svn/<refname>/unhandled.log
Renamed and copied directories are not detected by git and hence not
tracked when committing to SVN. I do not plan on adding support for
this as it's quite difficult and time-consuming to get working for all
the possible corner cases (git doesn't do it, either). Renamed and
copied files are fully supported if they're similar enough for git to
detect them.
the possible corner cases (git doesn't do it, either). Committing
renamed and copied files are fully supported if they're similar enough
for git to detect them.
CONFIGURATION
-------------
git-svn stores [svn-remote] configuration information in the
repository .git/config file. It is similar the core git
[remote] sections except 'fetch' keys do not accept glob
arguments; but they are instead handled by the 'branches'
and 'tags' keys. Since some SVN repositories are oddly
configured with multiple projects glob expansions such those
listed below are allowed:
------------------------------------------------------------------------
[svn-remote "project-a"]
url = http://server.org/svn
branches = branches/*/project-a:refs/remotes/project-a/branches/*
tags = tags/*/project-a:refs/remotes/project-a/tags/*
trunk = trunk/project-a:refs/remotes/project-a/trunk
------------------------------------------------------------------------
Keep in mind that the '*' (asterisk) wildcard of the local ref
(left of the ':') *must* be the farthest right path component;
however the remote wildcard may be anywhere as long as it's own
independent path componet (surrounded by '/' or EOL). This
type of configuration is not automatically created by 'init' and
should be manually entered with a text-editor or using
gitlink:git-config[1]
SEE ALSO
--------

View file

@ -35,6 +35,12 @@ ifdef::stalenotes[]
You are reading the documentation for the latest version of git.
Documentation for older releases are available here:
* link:v1.5.0.2/git.html[documentation for release 1.5.0.2]
* link:v1.5.0.2/RelNotes-1.5.0.2.txt[release notes for 1.5.0.2]
* link:v1.5.0.1/RelNotes-1.5.0.1.txt[release notes for 1.5.0.1]
* link:v1.5.0/git.html[documentation for release 1.5.0]
* link:v1.5.0/RelNotes-1.5.0.txt[release notes for 1.5.0]

View file

@ -28,6 +28,10 @@ all::
#
# Define NO_STRLCPY if you don't have strlcpy.
#
# Define NO_STRTOUMAX if you don't have strtoumax in the C library.
# If your compiler also does not support long long or does not have
# strtoull, define NO_STRTOULL.
#
# Define NO_SETENV if you don't have setenv in the C library.
#
# Define NO_SYMLINK_HEAD if you never want .git/HEAD to be a symbolic link.
@ -124,6 +128,7 @@ prefix = $(HOME)
bindir = $(prefix)/bin
gitexecdir = $(bindir)
template_dir = $(prefix)/share/git-core/templates/
ETC_GITCONFIG = $(prefix)/etc/gitconfig
# DESTDIR=
# default configuration for gitweb
@ -262,7 +267,8 @@ LIB_OBJS = \
revision.o pager.o tree-walk.o xdiff-interface.o \
write_or_die.o trace.o list-objects.o grep.o \
alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o
color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \
convert.o
BUILTIN_OBJS = \
builtin-add.o \
@ -353,11 +359,13 @@ ifeq ($(uname_S),SunOS)
NO_UNSETENV = YesPlease
NO_SETENV = YesPlease
NO_C99_FORMAT = YesPlease
NO_STRTOUMAX = YesPlease
endif
ifeq ($(uname_R),5.9)
NO_UNSETENV = YesPlease
NO_SETENV = YesPlease
NO_C99_FORMAT = YesPlease
NO_STRTOUMAX = YesPlease
endif
INSTALL = ginstall
TAR = gtar
@ -517,6 +525,13 @@ ifdef NO_STRLCPY
COMPAT_CFLAGS += -DNO_STRLCPY
COMPAT_OBJS += compat/strlcpy.o
endif
ifdef NO_STRTOUMAX
COMPAT_CFLAGS += -DNO_STRTOUMAX
COMPAT_OBJS += compat/strtoumax.o
endif
ifdef NO_STRTOULL
COMPAT_CFLAGS += -DNO_STRTOULL
endif
ifdef NO_SETENV
COMPAT_CFLAGS += -DNO_SETENV
COMPAT_OBJS += compat/setenv.o
@ -584,6 +599,7 @@ endif
# Shell quote (do not use $(call) to accommodate ancient setups);
SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER))
ETC_GITCONFIG_SQ = $(subst ','\'',$(ETC_GITCONFIG))
DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
bindir_SQ = $(subst ','\'',$(bindir))
@ -596,7 +612,8 @@ PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
LIBS = $(GITLIBS) $(EXTLIBS)
BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' $(COMPAT_CFLAGS)
BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' \
-DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"' $(COMPAT_CFLAGS)
LIB_OBJS += $(COMPAT_OBJS)
ALL_CFLAGS += $(BASIC_CFLAGS)
@ -812,7 +829,7 @@ GIT-CFLAGS: .FORCE-GIT-CFLAGS
export NO_SVN_TESTS
test: all
test: all test-chmtime$X
$(MAKE) -C t/ all
test-date$X: test-date.c date.o ctype.o
@ -827,6 +844,9 @@ test-dump-cache-tree$X: dump-cache-tree.o $(GITLIBS)
test-sha1$X: test-sha1.o $(GITLIBS)
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
test-chmtime$X: test-chmtime.c
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $<
check-sha1:: test-sha1$X
./test-sha1.sh
@ -882,7 +902,8 @@ dist: git.spec git-archive
$(TAR) rf $(GIT_TARNAME).tar \
$(GIT_TARNAME)/git.spec \
$(GIT_TARNAME)/version \
$(GIT_TARNAME)/git-gui/version
$(GIT_TARNAME)/git-gui/version \
$(GIT_TARNAME)/git-gui/credits
@rm -rf $(GIT_TARNAME)
gzip -f -9 $(GIT_TARNAME).tar

View file

@ -28,6 +28,7 @@ static int newfd = -1;
static int unidiff_zero;
static int p_value = 1;
static int p_value_known;
static int check_index;
static int write_index;
static int cached;
@ -144,6 +145,7 @@ struct patch {
unsigned long deflate_origlen;
int lines_added, lines_deleted;
int score;
unsigned int is_toplevel_relative:1;
unsigned int inaccurate_eof:1;
unsigned int is_binary:1;
unsigned int is_copy:1;
@ -238,7 +240,7 @@ static int name_terminate(const char *name, int namelen, int c, int terminate)
return 1;
}
static char * find_name(const char *line, char *def, int p_value, int terminate)
static char *find_name(const char *line, char *def, int p_value, int terminate)
{
int len;
const char *start = line;
@ -311,11 +313,54 @@ static char * find_name(const char *line, char *def, int p_value, int terminate)
return name;
}
static int count_slashes(const char *cp)
{
int cnt = 0;
char ch;
while ((ch = *cp++))
if (ch == '/')
cnt++;
return cnt;
}
/*
* Given the string after "--- " or "+++ ", guess the appropriate
* p_value for the given patch.
*/
static int guess_p_value(const char *nameline)
{
char *name, *cp;
int val = -1;
if (is_dev_null(nameline))
return -1;
name = find_name(nameline, NULL, 0, TERM_SPACE | TERM_TAB);
if (!name)
return -1;
cp = strchr(name, '/');
if (!cp)
val = 0;
else if (prefix) {
/*
* Does it begin with "a/$our-prefix" and such? Then this is
* very likely to apply to our directory.
*/
if (!strncmp(name, prefix, prefix_length))
val = count_slashes(prefix);
else {
cp++;
if (!strncmp(cp, prefix, prefix_length))
val = count_slashes(prefix) + 1;
}
}
free(name);
return val;
}
/*
* Get the name etc info from the --/+++ lines of a traditional patch header
*
* NOTE! This hardcodes "-p1" behaviour in filename detection.
*
* FIXME! The end-of-filename heuristics are kind of screwy. For existing
* files, we can happily check the index for a match, but for creating a
* new file we should try to match whatever "patch" does. I have no idea.
@ -326,6 +371,16 @@ static void parse_traditional_patch(const char *first, const char *second, struc
first += 4; /* skip "--- " */
second += 4; /* skip "+++ " */
if (!p_value_known) {
int p, q;
p = guess_p_value(first);
q = guess_p_value(second);
if (p < 0) p = q;
if (0 <= p && p == q) {
p_value = p;
p_value_known = 1;
}
}
if (is_dev_null(first)) {
patch->is_new = 1;
patch->is_delete = 0;
@ -787,6 +842,7 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc
{
unsigned long offset, len;
patch->is_toplevel_relative = 0;
patch->is_rename = patch->is_copy = 0;
patch->is_new = patch->is_delete = -1;
patch->old_mode = patch->new_mode = 0;
@ -831,6 +887,7 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc
die("git diff header lacks filename information (line %d)", linenr);
patch->old_name = patch->new_name = patch->def_name;
}
patch->is_toplevel_relative = 1;
*hdrsize = git_hdr_len;
return offset;
}
@ -1129,11 +1186,11 @@ static struct fragment *parse_binary_hunk(char **buf_p,
*status_p = 0;
if (!strncmp(buffer, "delta ", 6)) {
if (!prefixcmp(buffer, "delta ")) {
patch_method = BINARY_DELTA_DEFLATED;
origlen = strtoul(buffer + 6, NULL, 10);
}
else if (!strncmp(buffer, "literal ", 8)) {
else if (!prefixcmp(buffer, "literal ")) {
patch_method = BINARY_LITERAL_DEFLATED;
origlen = strtoul(buffer + 8, NULL, 10);
}
@ -1393,28 +1450,39 @@ static void show_stats(struct patch *patch)
free(qname);
}
static int read_old_data(struct stat *st, const char *path, void *buf, unsigned long size)
static int read_old_data(struct stat *st, const char *path, char **buf_p, unsigned long *alloc_p, unsigned long *size_p)
{
int fd;
unsigned long got;
unsigned long nsize;
char *nbuf;
unsigned long size = *size_p;
char *buf = *buf_p;
switch (st->st_mode & S_IFMT) {
case S_IFLNK:
return readlink(path, buf, size);
return readlink(path, buf, size) != size;
case S_IFREG:
fd = open(path, O_RDONLY);
if (fd < 0)
return error("unable to open %s", path);
got = 0;
for (;;) {
int ret = xread(fd, (char *) buf + got, size - got);
int ret = xread(fd, buf + got, size - got);
if (ret <= 0)
break;
got += ret;
}
close(fd);
return got;
nsize = got;
nbuf = buf;
if (convert_to_git(path, &nbuf, &nsize)) {
free(buf);
*buf_p = nbuf;
*alloc_p = nsize;
*size_p = nsize;
}
return got != size;
default:
return -1;
}
@ -1655,6 +1723,8 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
/* Ignore it, we already handled it */
break;
default:
if (apply_verbosely)
error("invalid start of line: '%c'", first);
return -1;
}
patch += len;
@ -1752,6 +1822,9 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
}
}
if (offset && apply_verbosely)
error("while searching for:\n%.*s", oldsize, oldlines);
free(old);
free(new);
return offset;
@ -1910,7 +1983,7 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *
size = st->st_size;
alloc = size + 8192;
buf = xmalloc(alloc);
if (read_old_data(st, patch->old_name, buf, alloc) != size)
if (read_old_data(st, patch->old_name, &buf, &alloc, &size))
return error("read of %s failed", patch->old_name);
}
@ -2232,7 +2305,7 @@ static void patch_stats(struct patch *patch)
}
}
static void remove_file(struct patch *patch)
static void remove_file(struct patch *patch, int rmdir_empty)
{
if (write_index) {
if (remove_file_from_cache(patch->old_name) < 0)
@ -2240,7 +2313,7 @@ static void remove_file(struct patch *patch)
cache_tree_invalidate_path(active_cache_tree, patch->old_name);
}
if (!cached) {
if (!unlink(patch->old_name)) {
if (!unlink(patch->old_name) && rmdir_empty) {
char *name = xstrdup(patch->old_name);
char *end = strrchr(name, '/');
while (end) {
@ -2282,12 +2355,22 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned
static int try_create_file(const char *path, unsigned int mode, const char *buf, unsigned long size)
{
int fd;
char *nbuf;
unsigned long nsize;
if (S_ISLNK(mode))
/* Although buf:size is counted string, it also is NUL
* terminated.
*/
return symlink(buf, path);
nsize = size;
nbuf = (char *) buf;
if (convert_to_working_tree(path, &nbuf, &nsize)) {
free((char *) buf);
buf = nbuf;
size = nsize;
}
fd = open(path, O_CREAT | O_EXCL | O_WRONLY, (mode & 0100) ? 0777 : 0666);
if (fd < 0)
return -1;
@ -2373,7 +2456,7 @@ static void write_out_one_result(struct patch *patch, int phase)
{
if (patch->is_delete > 0) {
if (phase == 0)
remove_file(patch);
remove_file(patch, 1);
return;
}
if (patch->is_new > 0 || patch->is_copy) {
@ -2386,7 +2469,7 @@ static void write_out_one_result(struct patch *patch, int phase)
* thing: remove the old, write the new
*/
if (phase == 0)
remove_file(patch);
remove_file(patch, 0);
if (phase == 1)
create_file(patch);
}
@ -2508,6 +2591,32 @@ static int use_patch(struct patch *p)
return 1;
}
static void prefix_one(char **name)
{
char *old_name = *name;
if (!old_name)
return;
*name = xstrdup(prefix_filename(prefix, prefix_length, *name));
free(old_name);
}
static void prefix_patches(struct patch *p)
{
if (!prefix || p->is_toplevel_relative)
return;
for ( ; p; p = p->next) {
if (p->new_name == p->old_name) {
char *prefixed = p->new_name;
prefix_one(&prefixed);
p->new_name = p->old_name = prefixed;
}
else {
prefix_one(&p->new_name);
prefix_one(&p->old_name);
}
}
}
static int apply_patch(int fd, const char *filename, int inaccurate_eof)
{
unsigned long offset, size;
@ -2530,11 +2639,14 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)
break;
if (apply_in_reverse)
reverse_patches(patch);
if (prefix)
prefix_patches(patch);
if (use_patch(patch)) {
patch_stats(patch);
*listp = patch;
listp = &patch->next;
} else {
}
else {
/* perhaps free it a bit better? */
free(patch);
skipped_patch++;
@ -2595,9 +2707,16 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
int read_stdin = 1;
int inaccurate_eof = 0;
int errs = 0;
int is_not_gitdir = 0;
const char *whitespace_option = NULL;
prefix = setup_git_directory_gently(&is_not_gitdir);
prefix_length = prefix ? strlen(prefix) : 0;
git_config(git_apply_config);
if (apply_default_whitespace)
parse_whitespace_option(apply_default_whitespace);
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
char *end;
@ -2608,15 +2727,16 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
read_stdin = 0;
continue;
}
if (!strncmp(arg, "--exclude=", 10)) {
if (!prefixcmp(arg, "--exclude=")) {
struct excludes *x = xmalloc(sizeof(*x));
x->path = arg + 10;
x->next = excludes;
excludes = x;
continue;
}
if (!strncmp(arg, "-p", 2)) {
if (!prefixcmp(arg, "-p")) {
p_value = atoi(arg + 2);
p_value_known = 1;
continue;
}
if (!strcmp(arg, "--no-add")) {
@ -2648,10 +2768,14 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
continue;
}
if (!strcmp(arg, "--index")) {
if (is_not_gitdir)
die("--index outside a repository");
check_index = 1;
continue;
}
if (!strcmp(arg, "--cached")) {
if (is_not_gitdir)
die("--cached outside a repository");
check_index = 1;
cached = 1;
continue;
@ -2669,13 +2793,13 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
line_termination = 0;
continue;
}
if (!strncmp(arg, "-C", 2)) {
if (!prefixcmp(arg, "-C")) {
p_context = strtoul(arg + 2, &end, 0);
if (*end != '\0')
die("unrecognized context count '%s'", arg + 2);
continue;
}
if (!strncmp(arg, "--whitespace=", 13)) {
if (!prefixcmp(arg, "--whitespace=")) {
whitespace_option = arg + 13;
parse_whitespace_option(arg + 13);
continue;
@ -2692,7 +2816,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
apply = apply_with_reject = apply_verbosely = 1;
continue;
}
if (!strcmp(arg, "--verbose")) {
if (!strcmp(arg, "-v") || !strcmp(arg, "--verbose")) {
apply_verbosely = 1;
continue;
}
@ -2700,14 +2824,6 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
inaccurate_eof = 1;
continue;
}
if (check_index && prefix_length < 0) {
prefix = setup_git_directory();
prefix_length = prefix ? strlen(prefix) : 0;
git_config(git_apply_config);
if (!whitespace_option && apply_default_whitespace)
parse_whitespace_option(apply_default_whitespace);
}
if (0 < prefix_length)
arg = prefix_filename(prefix, prefix_length, arg);

View file

@ -35,7 +35,7 @@ static int run_remote_archiver(const char *remote, int argc,
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
if (!strncmp("--exec=", arg, 7)) {
if (!prefixcmp(arg, "--exec=")) {
if (exec_at)
die("multiple --exec specified");
exec = arg + 7;
@ -62,7 +62,7 @@ static int run_remote_archiver(const char *remote, int argc,
if (buf[len-1] == '\n')
buf[--len] = 0;
if (strcmp(buf, "ACK")) {
if (len > 5 && !strncmp(buf, "NACK ", 5))
if (len > 5 && !prefixcmp(buf, "NACK "))
die("git-archive: NACK %s", buf + 5);
die("git-archive: protocol error");
}
@ -166,11 +166,11 @@ int parse_archive_args(int argc, const char **argv, struct archiver *ar)
verbose = 1;
continue;
}
if (!strncmp(arg, "--format=", 9)) {
if (!prefixcmp(arg, "--format=")) {
format = arg + 9;
continue;
}
if (!strncmp(arg, "--prefix=", 9)) {
if (!prefixcmp(arg, "--prefix=")) {
base = arg + 9;
continue;
}
@ -218,7 +218,7 @@ static const char *extract_remote_arg(int *ac, const char **av)
if (!strcmp(arg, "--"))
no_more_options = 1;
if (!no_more_options) {
if (!strncmp(arg, "--remote=", 9)) {
if (!prefixcmp(arg, "--remote=")) {
if (remote)
die("Multiple --remote specified");
remote = arg + 9;

View file

@ -2097,17 +2097,17 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
output_option |= OUTPUT_LONG_OBJECT_NAME;
else if (!strcmp("-S", arg) && ++i < argc)
revs_file = argv[i];
else if (!strncmp("-M", arg, 2)) {
else if (!prefixcmp(arg, "-M")) {
opt |= PICKAXE_BLAME_MOVE;
blame_move_score = parse_score(arg+2);
}
else if (!strncmp("-C", arg, 2)) {
else if (!prefixcmp(arg, "-C")) {
if (opt & PICKAXE_BLAME_COPY)
opt |= PICKAXE_BLAME_COPY_HARDER;
opt |= PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE;
blame_copy_score = parse_score(arg+2);
}
else if (!strncmp("-L", arg, 2)) {
else if (!prefixcmp(arg, "-L")) {
if (!arg[2]) {
if (++i >= argc)
usage(blame_usage);

View file

@ -59,7 +59,7 @@ int git_branch_config(const char *var, const char *value)
branch_use_color = git_config_colorbool(var, value);
return 0;
}
if (!strncmp(var, "color.branch.", 13)) {
if (!prefixcmp(var, "color.branch.")) {
int slot = parse_branch_color_slot(var, 13);
color_parse(value, var, branch_colors[slot]);
return 0;
@ -178,13 +178,13 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,
int len;
/* Detect kind */
if (!strncmp(refname, "refs/heads/", 11)) {
if (!prefixcmp(refname, "refs/heads/")) {
kind = REF_LOCAL_BRANCH;
refname += 11;
} else if (!strncmp(refname, "refs/remotes/", 13)) {
} else if (!prefixcmp(refname, "refs/remotes/")) {
kind = REF_REMOTE_BRANCH;
refname += 13;
} else if (!strncmp(refname, "refs/tags/", 10)) {
} else if (!prefixcmp(refname, "refs/tags/")) {
kind = REF_TAG;
refname += 10;
}
@ -446,7 +446,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
reflog = 1;
continue;
}
if (!strncmp(arg, "--abbrev=", 9)) {
if (!prefixcmp(arg, "--abbrev=")) {
abbrev = atoi(arg+9);
continue;
}
@ -476,7 +476,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
detached = 1;
}
else {
if (strncmp(head, "refs/heads/", 11))
if (prefixcmp(head, "refs/heads/"))
die("HEAD not found below refs/heads!");
head += 11;
}

View file

@ -223,12 +223,12 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
to_tempfile = 1;
continue;
}
if (!strncmp(arg, "--prefix=", 9)) {
if (!prefixcmp(arg, "--prefix=")) {
state.base_dir = arg+9;
state.base_dir_len = strlen(state.base_dir);
continue;
}
if (!strncmp(arg, "--stage=", 8)) {
if (!prefixcmp(arg, "--stage=")) {
if (!strcmp(arg + 8, "all")) {
to_tempfile = 1;
checkout_stage = CHECKOUT_ALL;

View file

@ -64,7 +64,7 @@ static int get_value(const char* key_, const char* regex_)
int ret = -1;
char *tl;
char *global = NULL, *repo_config = NULL;
const char *local;
const char *system_wide = NULL, *local;
local = getenv(CONFIG_ENVIRONMENT);
if (!local) {
@ -74,6 +74,7 @@ static int get_value(const char* key_, const char* regex_)
local = repo_config = xstrdup(git_path("config"));
if (home)
global = xstrdup(mkpath("%s/.gitconfig", home));
system_wide = ETC_GITCONFIG;
}
key = xstrdup(key_);
@ -103,11 +104,15 @@ static int get_value(const char* key_, const char* regex_)
}
}
if (do_all && system_wide)
git_config_from_file(show_config, system_wide);
if (do_all && global)
git_config_from_file(show_config, global);
git_config_from_file(show_config, local);
if (!do_all && !seen && global)
git_config_from_file(show_config, global);
if (!do_all && !seen && system_wide)
git_config_from_file(show_config, system_wide);
free(key);
if (regexp) {
@ -147,7 +152,10 @@ int cmd_config(int argc, const char **argv, const char *prefix)
} else {
die("$HOME not set");
}
} else if (!strcmp(argv[1], "--rename-section")) {
}
else if (!strcmp(argv[1], "--system"))
setenv("GIT_CONFIG", ETC_GITCONFIG, 1);
else if (!strcmp(argv[1], "--rename-section")) {
int ret;
if (argc != 4)
usage(git_config_set_usage);
@ -159,7 +167,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
return 1;
}
return 0;
} else
}
else
break;
argc--;
argv++;

View file

@ -52,7 +52,7 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, void
* If --tags, then any tags are used.
* Otherwise only annotated tags are used.
*/
if (!strncmp(path, "refs/tags/", 10)) {
if (!prefixcmp(path, "refs/tags/")) {
if (object->type == OBJ_TAG)
prio = 2;
else
@ -254,12 +254,12 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
all = 1;
else if (!strcmp(arg, "--tags"))
tags = 1;
else if (!strncmp(arg, "--abbrev=", 9)) {
else if (!prefixcmp(arg, "--abbrev=")) {
abbrev = strtoul(arg + 9, NULL, 10);
if (abbrev != 0 && (abbrev < MINIMUM_ABBREV || 40 < abbrev))
abbrev = DEFAULT_ABBREV;
}
else if (!strncmp(arg, "--candidates=", 13)) {
else if (!prefixcmp(arg, "--candidates=")) {
max_candidates = strtoul(arg + 13, NULL, 10);
if (max_candidates < 1)
max_candidates = 1;

View file

@ -162,7 +162,8 @@ static int builtin_diff_combined(struct rev_info *revs,
parent = xmalloc(ents * sizeof(*parent));
/* Again, the revs are all reverse */
for (i = 0; i < ents; i++)
hashcpy((unsigned char*)parent + i, ent[ents - 1 - i].item->sha1);
hashcpy((unsigned char *)(parent + i),
ent[ents - 1 - i].item->sha1);
diff_tree_combined(parent[0], parent + 1, ents - 1,
revs->dense_combined_merges, revs);
return 0;
@ -232,6 +233,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
break;
else if (!strcmp(arg, "--cached")) {
add_head(&rev);
if (!rev.pending.nr)
die("No HEAD commit to compare with (yet)");
break;
}
}

View file

@ -81,7 +81,7 @@ static int handle_line(char *line)
if (len < 43 || line[40] != '\t')
return 1;
if (!strncmp(line + 41, "not-for-merge", 13))
if (!prefixcmp(line + 41, "not-for-merge"))
return 0;
if (line[41] != '\t')
@ -119,15 +119,15 @@ static int handle_line(char *line)
if (pulling_head) {
origin = xstrdup(src);
src_data->head_status |= 1;
} else if (!strncmp(line, "branch ", 7)) {
} else if (!prefixcmp(line, "branch ")) {
origin = xstrdup(line + 7);
append_to_list(&src_data->branch, origin, NULL);
src_data->head_status |= 2;
} else if (!strncmp(line, "tag ", 4)) {
} else if (!prefixcmp(line, "tag ")) {
origin = line;
append_to_list(&src_data->tag, xstrdup(origin + 4), NULL);
src_data->head_status |= 2;
} else if (!strncmp(line, "remote branch ", 14)) {
} else if (!prefixcmp(line, "remote branch ")) {
origin = xstrdup(line + 14);
append_to_list(&src_data->r_branch, origin, NULL);
src_data->head_status |= 2;
@ -280,7 +280,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
current_branch = resolve_ref("HEAD", head_sha1, 1, NULL);
if (!current_branch)
die("No current branch");
if (!strncmp(current_branch, "refs/heads/", 11))
if (!prefixcmp(current_branch, "refs/heads/"))
current_branch += 11;
while (fgets(line, sizeof(line), in)) {

View file

@ -814,7 +814,7 @@ int cmd_for_each_ref(int ac, const char **av, char *prefix)
i++;
break;
}
if (!strncmp(arg, "--format=", 9)) {
if (!prefixcmp(arg, "--format=")) {
if (format)
die("more than one --format?");
format = arg + 9;
@ -844,7 +844,7 @@ int cmd_for_each_ref(int ac, const char **av, char *prefix)
quote_style = QUOTE_TCL;
continue;
}
if (!strncmp(arg, "--count=", 8)) {
if (!prefixcmp(arg, "--count=")) {
if (maxcount)
die("more than one --count?");
maxcount = atoi(arg + 8);
@ -852,7 +852,7 @@ int cmd_for_each_ref(int ac, const char **av, char *prefix)
die("The number %s did not parse", arg);
continue;
}
if (!strncmp(arg, "--sort=", 7)) {
if (!prefixcmp(arg, "--sort=")) {
struct ref_sort *s = xcalloc(1, sizeof(*s));
int len;

View file

@ -546,7 +546,7 @@ static int fsck_head_link(void)
if (!head_points_at || !(flag & REF_ISSYMREF))
return error("HEAD is not a symbolic ref");
if (strncmp(head_points_at, "refs/heads/", 11))
if (prefixcmp(head_points_at, "refs/heads/"))
return error("HEAD points to something strange (%s)",
head_points_at);
if (is_null_sha1(sha1))

View file

@ -527,9 +527,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
opt.word_regexp = 1;
continue;
}
if (!strncmp("-A", arg, 2) ||
!strncmp("-B", arg, 2) ||
!strncmp("-C", arg, 2) ||
if (!prefixcmp(arg, "-A") ||
!prefixcmp(arg, "-B") ||
!prefixcmp(arg, "-C") ||
(arg[0] == '-' && '1' <= arg[1] && arg[1] <= '9')) {
unsigned num;
const char *scan;

View file

@ -283,11 +283,11 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
for (i = 1; i < argc; i++, argv++) {
const char *arg = argv[1];
if (!strncmp(arg, "--template=", 11))
if (!prefixcmp(arg, "--template="))
template_dir = arg+11;
else if (!strcmp(arg, "--shared"))
shared_repository = PERM_GROUP;
else if (!strncmp(arg, "--shared=", 9))
else if (!prefixcmp(arg, "--shared="))
shared_repository = git_config_perm("arg", arg+9);
else
usage(init_db_usage);

View file

@ -32,7 +32,7 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
rev->always_show_header = 0;
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
if (!strncmp(arg, "--encoding=", 11)) {
if (!prefixcmp(arg, "--encoding=")) {
arg += 11;
if (strcmp(arg, "none"))
git_log_output_encoding = strdup(arg);
@ -224,6 +224,9 @@ int cmd_log(int argc, const char **argv, const char *prefix)
return cmd_log_walk(&rev);
}
/* format-patch */
#define FORMAT_PATCH_NAME_MAX 64
static int istitlechar(char c)
{
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
@ -264,15 +267,18 @@ static int git_format_config(const char *var, const char *value)
static FILE *realstdout = NULL;
static const char *output_directory = NULL;
static void reopen_stdout(struct commit *commit, int nr, int keep_subject)
static int reopen_stdout(struct commit *commit, int nr, int keep_subject)
{
char filename[1024];
char filename[PATH_MAX];
char *sol;
int len = 0;
int suffix_len = strlen(fmt_patch_suffix) + 10; /* ., NUL and slop */
int suffix_len = strlen(fmt_patch_suffix) + 1;
if (output_directory) {
strlcpy(filename, output_directory, 1000);
if (strlen(output_directory) >=
sizeof(filename) - FORMAT_PATCH_NAME_MAX - suffix_len)
return error("name of output directory is too long");
strlcpy(filename, output_directory, sizeof(filename) - suffix_len);
len = strlen(filename);
if (filename[len - 1] != '/')
filename[len++] = '/';
@ -287,7 +293,7 @@ static void reopen_stdout(struct commit *commit, int nr, int keep_subject)
sol += 2;
/* strip [PATCH] or [PATCH blabla] */
if (!keep_subject && !strncmp(sol, "[PATCH", 6)) {
if (!keep_subject && !prefixcmp(sol, "[PATCH")) {
char *eos = strchr(sol + 6, ']');
if (eos) {
while (isspace(*eos))
@ -297,7 +303,8 @@ static void reopen_stdout(struct commit *commit, int nr, int keep_subject)
}
for (j = 0;
len < sizeof(filename) - suffix_len &&
j < FORMAT_PATCH_NAME_MAX - suffix_len - 5 &&
len < sizeof(filename) - suffix_len &&
sol[j] && sol[j] != '\n';
j++) {
if (istitlechar(sol[j])) {
@ -314,10 +321,16 @@ static void reopen_stdout(struct commit *commit, int nr, int keep_subject)
}
while (filename[len - 1] == '.' || filename[len - 1] == '-')
len--;
filename[len] = 0;
}
if (len + suffix_len >= sizeof(filename))
return error("Patch pathname too long");
strcpy(filename + len, fmt_patch_suffix);
fprintf(realstdout, "%s\n", filename);
freopen(filename, "w", stdout);
if (freopen(filename, "w", stdout) == NULL)
return error("Cannot open patch file %s",filename);
return 0;
}
static int get_patch_id(struct commit *commit, struct diff_options *options,
@ -435,7 +448,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
else if (!strcmp(argv[i], "-n") ||
!strcmp(argv[i], "--numbered"))
numbered = 1;
else if (!strncmp(argv[i], "--start-number=", 15))
else if (!prefixcmp(argv[i], "--start-number="))
start_number = strtol(argv[i] + 15, NULL, 10);
else if (!strcmp(argv[i], "--start-number")) {
i++;
@ -471,13 +484,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
}
else if (!strcmp(argv[i], "--attach"))
rev.mime_boundary = git_version_string;
else if (!strncmp(argv[i], "--attach=", 9))
else if (!prefixcmp(argv[i], "--attach="))
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))
else if (!prefixcmp(argv[i], "--in-reply-to="))
in_reply_to = argv[i] + 14;
else if (!strcmp(argv[i], "--in-reply-to")) {
i++;
@ -485,7 +498,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
die("Need a Message-Id for --in-reply-to");
in_reply_to = argv[i];
}
else if (!strncmp(argv[i], "--suffix=", 9))
else if (!prefixcmp(argv[i], "--suffix="))
fmt_patch_suffix = argv[i] + 9;
else
argv[j++] = argv[i];
@ -573,7 +586,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
rev.message_id = message_id;
}
if (!use_stdout)
reopen_stdout(commit, rev.nr, keep_subject);
if (reopen_stdout(commit, rev.nr, keep_subject))
die("Failed to create output files");
shown = log_tree_commit(&rev, commit);
free(commit->buffer);
commit->buffer = NULL;

View file

@ -406,7 +406,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
add_exclude(argv[++i], "", 0, &dir.exclude_list[EXC_CMDL]);
continue;
}
if (!strncmp(arg, "--exclude=", 10)) {
if (!prefixcmp(arg, "--exclude=")) {
exc_given = 1;
add_exclude(arg+10, "", 0, &dir.exclude_list[EXC_CMDL]);
continue;
@ -416,12 +416,12 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
add_excludes_from_file(&dir, argv[++i]);
continue;
}
if (!strncmp(arg, "--exclude-from=", 15)) {
if (!prefixcmp(arg, "--exclude-from=")) {
exc_given = 1;
add_excludes_from_file(&dir, arg+15);
continue;
}
if (!strncmp(arg, "--exclude-per-directory=", 24)) {
if (!prefixcmp(arg, "--exclude-per-directory=")) {
exc_given = 1;
dir.exclude_per_dir = arg + 24;
continue;
@ -434,7 +434,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
error_unmatch = 1;
continue;
}
if (!strncmp(arg, "--abbrev=", 9)) {
if (!prefixcmp(arg, "--abbrev=")) {
abbrev = strtoul(arg+9, NULL, 10);
if (abbrev && abbrev < MINIMUM_ABBREV)
abbrev = MINIMUM_ABBREV;

View file

@ -118,7 +118,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
chomp_prefix = 0;
break;
}
if (!strncmp(argv[1]+2, "abbrev=",7)) {
if (!prefixcmp(argv[1]+2, "abbrev=")) {
abbrev = strtoul(argv[1]+9, NULL, 10);
if (abbrev && abbrev < MINIMUM_ABBREV)
abbrev = MINIMUM_ABBREV;

View file

@ -811,7 +811,7 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)
metainfo_charset = def_charset;
else if (!strcmp(argv[1], "-n"))
metainfo_charset = NULL;
else if (!strncmp(argv[1], "--encoding=", 11))
else if (!prefixcmp(argv[1], "--encoding="))
metainfo_charset = argv[1] + 11;
else
usage(mailinfo_usage);

View file

@ -57,13 +57,17 @@ static void name_rev(struct commit *commit,
parents;
parents = parents->next, parent_number++) {
if (parent_number > 1) {
char *new_name = xmalloc(strlen(tip_name)+8);
int len = strlen(tip_name);
char *new_name = xmalloc(len + 8);
if (len > 2 && !strcmp(tip_name + len - 2, "^0"))
len -= 2;
if (generation > 0)
sprintf(new_name, "%s~%d^%d", tip_name,
sprintf(new_name, "%.*s~%d^%d", len, tip_name,
generation, parent_number);
else
sprintf(new_name, "%s^%d", tip_name, parent_number);
sprintf(new_name, "%.*s^%d", len, tip_name,
parent_number);
name_rev(parents->item, new_name,
merge_traversals + 1 , 0, 0);
@ -85,7 +89,7 @@ static int name_ref(const char *path, const unsigned char *sha1, int flags, void
struct name_ref_data *data = cb_data;
int deref = 0;
if (data->tags_only && strncmp(path, "refs/tags/", 10))
if (data->tags_only && prefixcmp(path, "refs/tags/"))
return 0;
if (data->ref_filter && fnmatch(data->ref_filter, path, 0))
@ -101,9 +105,9 @@ static int name_ref(const char *path, const unsigned char *sha1, int flags, void
if (o && o->type == OBJ_COMMIT) {
struct commit *commit = (struct commit *)o;
if (!strncmp(path, "refs/heads/", 11))
if (!prefixcmp(path, "refs/heads/"))
path = path + 11;
else if (!strncmp(path, "refs/", 5))
else if (!prefixcmp(path, "refs/"))
path = path + 5;
name_rev(commit, xstrdup(path), 0, 0, deref);
@ -127,10 +131,15 @@ static const char* get_rev_name(struct object *o)
if (!n->generation)
return n->tip_name;
else {
int len = strlen(n->tip_name);
if (len > 2 && !strcmp(n->tip_name + len - 2, "^0"))
len -= 2;
snprintf(buffer, sizeof(buffer), "%.*s~%d", len, n->tip_name,
n->generation);
snprintf(buffer, sizeof(buffer), "%s~%d", n->tip_name, n->generation);
return buffer;
return buffer;
}
}
int cmd_name_rev(int argc, const char **argv, const char *prefix)
@ -156,7 +165,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
} else if (!strcmp(*argv, "--tags")) {
data.tags_only = 1;
continue;
} else if (!strncmp(*argv, "--refs=", 7)) {
} else if (!prefixcmp(*argv, "--refs=")) {
data.ref_filter = *argv + 7;
continue;
} else if (!strcmp(*argv, "--all")) {

View file

@ -1551,9 +1551,12 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
int use_internal_rev_list = 0;
int thin = 0;
int i;
const char *rp_av[64];
const char **rp_av;
int rp_ac_alloc = 64;
int rp_ac;
rp_av = xcalloc(rp_ac_alloc, sizeof(*rp_av));
rp_av[0] = "pack-objects";
rp_av[1] = "--objects"; /* --thin will make it --objects-edge */
rp_ac = 2;
@ -1579,14 +1582,14 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
incremental = 1;
continue;
}
if (!strncmp("--window=", arg, 9)) {
if (!prefixcmp(arg, "--window=")) {
char *end;
window = strtoul(arg+9, &end, 0);
if (!arg[9] || *end)
usage(pack_usage);
continue;
}
if (!strncmp("--depth=", arg, 8)) {
if (!prefixcmp(arg, "--depth=")) {
char *end;
depth = strtoul(arg+8, &end, 0);
if (!arg[8] || *end)
@ -1622,12 +1625,15 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
continue;
}
if (!strcmp("--unpacked", arg) ||
!strncmp("--unpacked=", arg, 11) ||
!prefixcmp(arg, "--unpacked=") ||
!strcmp("--reflog", arg) ||
!strcmp("--all", arg)) {
use_internal_rev_list = 1;
if (ARRAY_SIZE(rp_av) - 1 <= rp_ac)
die("too many internal rev-list options");
if (rp_ac >= rp_ac_alloc - 1) {
rp_ac_alloc = alloc_nr(rp_ac_alloc);
rp_av = xrealloc(rp_av,
rp_ac_alloc * sizeof(*rp_av));
}
rp_av[rp_ac++] = arg;
continue;
}

View file

@ -36,7 +36,7 @@ static int handle_one_ref(const char *path, const unsigned char *sha1,
/* Do not pack the symbolic refs */
if ((flags & REF_ISSYMREF))
return 0;
is_tag_ref = !strncmp(path, "refs/tags/", 10);
is_tag_ref = !prefixcmp(path, "refs/tags/");
/* ALWAYS pack refs that were already packed or are tags */
if (!cb->all && !is_tag_ref && !(flags & REF_ISPACKED))

View file

@ -32,7 +32,7 @@ static int expand_one_ref(const char *ref, const unsigned char *sha1, int flag,
/* Ignore the "refs/" at the beginning of the refname */
ref += 5;
if (!strncmp(ref, "tags/", 5))
if (!prefixcmp(ref, "tags/"))
add_refspec(xstrdup(ref));
return 0;
}
@ -149,10 +149,10 @@ static int get_remotes_uri(const char *repo, const char *uri[MAX_URI])
int is_refspec;
char *s, *p;
if (!strncmp("URL:", buffer, 4)) {
if (!prefixcmp(buffer, "URL:")) {
is_refspec = 0;
s = buffer + 4;
} else if (!strncmp("Push:", buffer, 5)) {
} else if (!prefixcmp(buffer, "Push:")) {
is_refspec = 1;
s = buffer + 5;
} else
@ -195,7 +195,7 @@ static int config_get_receivepack;
static int get_remote_config(const char* key, const char* value)
{
if (!strncmp(key, "remote.", 7) &&
if (!prefixcmp(key, "remote.") &&
!strncmp(key + 7, config_repo, config_repo_len)) {
if (!strcmp(key + 7 + config_repo_len, ".url")) {
if (config_current_uri < MAX_URI)
@ -324,8 +324,8 @@ static int do_push(const char *repo)
const char **dest_refspec = refspec;
const char *dest = uri[i];
const char *sender = "git-send-pack";
if (!strncmp(dest, "http://", 7) ||
!strncmp(dest, "https://", 8))
if (!prefixcmp(dest, "http://") ||
!prefixcmp(dest, "https://"))
sender = "git-http-push";
else if (thin)
argv[dest_argc++] = "--thin";
@ -373,7 +373,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
verbose=1;
continue;
}
if (!strncmp(arg, "--repo=", 7)) {
if (!prefixcmp(arg, "--repo=")) {
repo = arg+7;
continue;
}
@ -397,11 +397,11 @@ int cmd_push(int argc, const char **argv, const char *prefix)
thin = 0;
continue;
}
if (!strncmp(arg, "--receive-pack=", 15)) {
if (!prefixcmp(arg, "--receive-pack=")) {
receivepack = arg;
continue;
}
if (!strncmp(arg, "--exec=", 7)) {
if (!prefixcmp(arg, "--exec=")) {
receivepack = arg;
continue;
}

View file

@ -133,7 +133,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
* entries and put the entries from the tree under the
* given subdirectory.
*/
if (!strncmp(arg, "--prefix=", 9)) {
if (!prefixcmp(arg, "--prefix=")) {
if (stage || opts.merge || opts.prefix)
usage(read_tree_usage);
opts.prefix = arg + 9;
@ -179,7 +179,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
continue;
}
if (!strncmp(arg, "--exclude-per-directory=", 24)) {
if (!prefixcmp(arg, "--exclude-per-directory=")) {
struct dir_struct *dir;
if (opts.dir)

View file

@ -321,9 +321,9 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
const char *arg = argv[i];
if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n"))
cb.dry_run = 1;
else if (!strncmp(arg, "--expire=", 9))
else if (!prefixcmp(arg, "--expire="))
cb.expire_total = approxidate(arg + 9);
else if (!strncmp(arg, "--expire-unreachable=", 21))
else if (!prefixcmp(arg, "--expire-unreachable="))
cb.expire_unreachable = approxidate(arg + 21);
else if (!strcmp(arg, "--stale-fix"))
cb.stalefix = 1;

View file

@ -105,11 +105,11 @@ static int handle_file(const char *path,
SHA1_Init(&ctx);
while (fgets(buf, sizeof(buf), f)) {
if (!strncmp("<<<<<<< ", buf, 8))
if (!prefixcmp(buf, "<<<<<<< "))
hunk = 1;
else if (!strncmp("=======", buf, 7))
else if (!prefixcmp(buf, "======="))
hunk = 2;
else if (!strncmp(">>>>>>> ", buf, 8)) {
else if (!prefixcmp(buf, ">>>>>>> ")) {
hunk_no++;
hunk = 0;
if (memcmp(one->ptr, two->ptr, one->nr < two->nr ?
@ -154,13 +154,17 @@ static int find_conflict(struct path_list *conflict)
return error("Could not read index");
for (i = 0; i + 2 < active_nr; i++) {
struct cache_entry *e1 = active_cache[i];
struct cache_entry *e2 = active_cache[i + 1];
struct cache_entry *e3 = active_cache[i + 2];
if (ce_stage(e1) == 1 && ce_stage(e2) == 2 &&
ce_stage(e3) == 3 && ce_same_name(e1, e2) &&
ce_same_name(e1, e3)) {
struct cache_entry *e2 = active_cache[i+1];
struct cache_entry *e3 = active_cache[i+2];
if (ce_stage(e1) == 1 &&
ce_stage(e2) == 2 &&
ce_stage(e3) == 3 &&
ce_same_name(e1, e2) && ce_same_name(e1, e3) &&
S_ISREG(ntohl(e1->ce_mode)) &&
S_ISREG(ntohl(e2->ce_mode)) &&
S_ISREG(ntohl(e3->ce_mode))) {
path_list_insert((const char *)e1->name, conflict);
i += 3;
i += 2;
}
}
return 0;

View file

@ -233,7 +233,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
}
continue;
}
if (!strncmp(arg,"-n",2)) {
if (!prefixcmp(arg, "-n")) {
if ((filter & DO_FLAGS) && (filter & DO_REVS))
show(arg);
continue;
@ -274,7 +274,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
continue;
}
if (!strcmp(arg, "--short") ||
!strncmp(arg, "--short=", 8)) {
!prefixcmp(arg, "--short=")) {
filter &= ~(DO_FLAGS|DO_NOREV);
verify = 1;
abbrev = DEFAULT_ABBREV;
@ -352,19 +352,19 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
: "false");
continue;
}
if (!strncmp(arg, "--since=", 8)) {
if (!prefixcmp(arg, "--since=")) {
show_datestring("--max-age=", arg+8);
continue;
}
if (!strncmp(arg, "--after=", 8)) {
if (!prefixcmp(arg, "--after=")) {
show_datestring("--max-age=", arg+8);
continue;
}
if (!strncmp(arg, "--before=", 9)) {
if (!prefixcmp(arg, "--before=")) {
show_datestring("--min-age=", arg+9);
continue;
}
if (!strncmp(arg, "--until=", 8)) {
if (!prefixcmp(arg, "--until=")) {
show_datestring("--min-age=", arg+8);
continue;
}

View file

@ -124,7 +124,7 @@ static void insert_author_oneline(struct path_list *list,
else
free(buffer);
if (!strncmp(oneline, "[PATCH", 6)) {
if (!prefixcmp(oneline, "[PATCH")) {
char *eob = strchr(oneline, ']');
if (eob) {
@ -179,7 +179,7 @@ static void read_from_stdin(struct path_list *list)
while (fgets(buffer, sizeof(buffer), stdin) != NULL) {
char *bob;
if ((buffer[0] == 'A' || buffer[0] == 'a') &&
!strncmp(buffer + 1, "uthor: ", 7) &&
!prefixcmp(buffer + 1, "uthor: ") &&
(bob = strchr(buffer + 7, '<')) != NULL) {
char buffer2[1024], offset = 0;
@ -230,7 +230,7 @@ static void get_from_rev(struct rev_info *rev, struct path_list *list)
else
eol++;
if (!strncmp(buffer, "author ", 7)) {
if (!prefixcmp(buffer, "author ")) {
char *bracket = strchr(buffer, '<');
if (bracket == NULL || bracket > eol)

View file

@ -266,7 +266,7 @@ static void show_one_commit(struct commit *commit, int no_name)
pretty, sizeof(pretty), 0, NULL, NULL, 0);
else
strcpy(pretty, "(unavailable)");
if (!strncmp(pretty, "[PATCH] ", 8))
if (!prefixcmp(pretty, "[PATCH] "))
cp = pretty + 8;
else
cp = pretty;
@ -378,7 +378,7 @@ static int append_head_ref(const char *refname, const unsigned char *sha1, int f
{
unsigned char tmp[20];
int ofs = 11;
if (strncmp(refname, "refs/heads/", ofs))
if (prefixcmp(refname, "refs/heads/"))
return 0;
/* If both heads/foo and tags/foo exists, get_sha1 would
* get confused.
@ -392,7 +392,7 @@ static int append_remote_ref(const char *refname, const unsigned char *sha1, int
{
unsigned char tmp[20];
int ofs = 13;
if (strncmp(refname, "refs/remotes/", ofs))
if (prefixcmp(refname, "refs/remotes/"))
return 0;
/* If both heads/foo and tags/foo exists, get_sha1 would
* get confused.
@ -404,7 +404,7 @@ static int append_remote_ref(const char *refname, const unsigned char *sha1, int
static int append_tag_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
{
if (strncmp(refname, "refs/tags/", 10))
if (prefixcmp(refname, "refs/tags/"))
return 0;
return append_ref(refname + 5, sha1, 0);
}
@ -435,9 +435,9 @@ static int append_matching_ref(const char *refname, const unsigned char *sha1, i
return 0;
if (fnmatch(match_ref_pattern, tail, 0))
return 0;
if (!strncmp("refs/heads/", refname, 11))
if (!prefixcmp(refname, "refs/heads/"))
return append_head_ref(refname, sha1, flag, cb_data);
if (!strncmp("refs/tags/", refname, 10))
if (!prefixcmp(refname, "refs/tags/"))
return append_tag_ref(refname, sha1, flag, cb_data);
return append_ref(refname, sha1, 0);
}
@ -462,11 +462,11 @@ static int rev_is_head(char *head, int headlen, char *name,
if ((!head[0]) ||
(head_sha1 && sha1 && hashcmp(head_sha1, sha1)))
return 0;
if (!strncmp(head, "refs/heads/", 11))
if (!prefixcmp(head, "refs/heads/"))
head += 11;
if (!strncmp(name, "refs/heads/", 11))
if (!prefixcmp(name, "refs/heads/"))
name += 11;
else if (!strncmp(name, "heads/", 6))
else if (!prefixcmp(name, "heads/"))
name += 6;
return !strcmp(head, name);
}
@ -635,7 +635,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
with_current_branch = 1;
else if (!strcmp(arg, "--sha1-name"))
sha1_name = 1;
else if (!strncmp(arg, "--more=", 7))
else if (!prefixcmp(arg, "--more="))
extra = atoi(arg + 7);
else if (!strcmp(arg, "--merge-base"))
merge_base = 1;
@ -652,9 +652,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
else if (!strcmp(arg, "--reflog") || !strcmp(arg, "-g")) {
reflog = DEFAULT_REFLOG;
}
else if (!strncmp(arg, "--reflog=", 9))
else if (!prefixcmp(arg, "--reflog="))
parse_reflog_param(arg + 9, &reflog, &reflog_base);
else if (!strncmp(arg, "-g=", 3))
else if (!prefixcmp(arg, "-g="))
parse_reflog_param(arg + 3, &reflog, &reflog_base);
else
usage(show_branch_usage);

View file

@ -28,8 +28,8 @@ static int show_ref(const char *refname, const unsigned char *sha1, int flag, vo
if (tags_only || heads_only) {
int match;
match = heads_only && !strncmp(refname, "refs/heads/", 11);
match |= tags_only && !strncmp(refname, "refs/tags/", 10);
match = heads_only && !prefixcmp(refname, "refs/heads/");
match |= tags_only && !prefixcmp(refname, "refs/tags/");
if (!match)
return 0;
}
@ -178,8 +178,8 @@ int cmd_show_ref(int argc, const char **argv, const char *prefix)
hash_only = 1;
continue;
}
if (!strncmp(arg, "--hash=", 7) ||
(!strncmp(arg, "--abbrev", 8) &&
if (!prefixcmp(arg, "--hash=") ||
(!prefixcmp(arg, "--abbrev") &&
(arg[8] == '=' || arg[8] == '\0'))) {
if (arg[2] != 'h' && !arg[8])
/* --abbrev only */
@ -215,16 +215,18 @@ int cmd_show_ref(int argc, const char **argv, const char *prefix)
}
if (!strcmp(arg, "--exclude-existing"))
return exclude_existing(NULL);
if (!strncmp(arg, "--exclude-existing=", 19))
if (!prefixcmp(arg, "--exclude-existing="))
return exclude_existing(arg + 19);
usage(show_ref_usage);
}
if (verify) {
unsigned char sha1[20];
if (!pattern)
die("--verify requires a reference");
while (*pattern) {
if (!strncmp(*pattern, "refs/", 5) &&
unsigned char sha1[20];
if (!prefixcmp(*pattern, "refs/") &&
resolve_ref(*pattern, sha1, 1, NULL)) {
if (!quiet)
show_one(*pattern, sha1);

View file

@ -31,7 +31,7 @@ int cmd_tar_tree(int argc, const char **argv, const char *prefix)
nargv[nargc++] = "git-archive";
nargv[nargc++] = "--format=tar";
if (2 <= argc && !strncmp("--remote=", argv[1], 9)) {
if (2 <= argc && !prefixcmp(argv[1], "--remote=")) {
nargv[nargc++] = argv[1];
argv++;
argc--;

View file

@ -369,7 +369,7 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
recover = 1;
continue;
}
if (!strncmp(arg, "--pack_header=", 14)) {
if (!prefixcmp(arg, "--pack_header=")) {
struct pack_header *hdr;
char *c;

View file

@ -70,7 +70,7 @@ int cmd_write_tree(int argc, const char **argv, const char *unused_prefix)
const char *arg = argv[1];
if (!strcmp(arg, "--missing-ok"))
missing_ok = 1;
else if (!strncmp(arg, "--prefix=", 9))
else if (!prefixcmp(arg, "--prefix="))
prefix = arg + 9;
else
usage(write_tree_usage);

View file

@ -211,6 +211,7 @@ extern const char *apply_default_whitespace;
extern int zlib_compression_level;
extern size_t packed_git_window_size;
extern size_t packed_git_limit;
extern int auto_crlf;
#define GIT_REPO_VERSION 0
extern int repository_format_version;
@ -478,4 +479,8 @@ extern int nfvasprintf(char **str, const char *fmt, va_list va);
extern void trace_printf(const char *format, ...);
extern void trace_argv_printf(const char **argv, int count, const char *format, ...);
/* convert.c */
extern int convert_to_git(const char *path, char **bufp, unsigned long *sizep);
extern int convert_to_working_tree(const char *path, char **bufp, unsigned long *sizep);
#endif /* CACHE_H */

View file

@ -678,9 +678,25 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
else {
/* Used by diff-tree to read from the working tree */
struct stat st;
int fd;
if (0 <= (fd = open(elem->path, O_RDONLY)) &&
!fstat(fd, &st)) {
int fd = -1;
if (lstat(elem->path, &st) < 0)
goto deleted_file;
if (S_ISLNK(st.st_mode)) {
int len = st.st_size;
result_size = len;
result = xmalloc(len + 1);
if (result_size != readlink(elem->path, result, len)) {
error("readlink(%s): %s", elem->path,
strerror(errno));
return;
}
result[len] = 0;
elem->mode = canon_mode(st.st_mode);
}
else if (0 <= (fd = open(elem->path, O_RDONLY)) &&
!fstat(fd, &st)) {
int len = st.st_size;
int sz = 0;
@ -698,11 +714,12 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
result[len] = 0;
}
else {
/* deleted file */
deleted_file:
result_size = 0;
elem->mode = 0;
result = xcalloc(1, 1);
}
if (0 <= fd)
close(fd);
}

10
compat/strtoumax.c Normal file
View file

@ -0,0 +1,10 @@
#include "../git-compat-util.h"
uintmax_t gitstrtoumax (const char *nptr, char **endptr, int base)
{
#if defined(NO_STRTOULL)
return strtoul(nptr, endptr, base);
#else
return strtoull(nptr, endptr, base);
#endif
}

View file

@ -326,6 +326,15 @@ int git_default_config(const char *var, const char *value)
return 0;
}
if (!strcmp(var, "core.autocrlf")) {
if (value && !strcasecmp(value, "input")) {
auto_crlf = -1;
return 0;
}
auto_crlf = git_config_bool(var, value);
return 0;
}
if (!strcmp(var, "user.name")) {
strlcpy(git_default_name, value, sizeof(git_default_name));
return 0;
@ -385,6 +394,8 @@ int git_config(config_fn_t fn)
* config file otherwise. */
filename = getenv(CONFIG_ENVIRONMENT);
if (!filename) {
if (!access(ETC_GITCONFIG, R_OK))
ret += git_config_from_file(fn, ETC_GITCONFIG);
home = getenv("HOME");
filename = getenv(CONFIG_LOCAL_ENVIRONMENT);
if (!filename)

View file

@ -114,13 +114,32 @@ AC_CHECK_LIB([expat], [XML_ParserCreate],
[NO_EXPAT=YesPlease])
AC_SUBST(NO_EXPAT)
#
# Define NEEDS_LIBICONV if linking with libc is not enough (Darwin).
# Define NEEDS_LIBICONV if linking with libc is not enough (Darwin and
# some Solaris installations).
# Define NO_ICONV if neither libc nor libiconv support iconv.
AC_CHECK_LIB([c], [iconv],
[NEEDS_LIBICONV=],
AC_CHECK_LIB([iconv], [iconv],
[NEEDS_LIBICONV=YesPlease],
[NO_ICONV=YesPlease]))
AC_DEFUN([ICONVTEST_SRC], [
#include <iconv.h>
int main(void)
{
iconv_open("", "");
return 0;
}
])
AC_MSG_CHECKING([for iconv in -lc])
AC_LINK_IFELSE(ICONVTEST_SRC,
[AC_MSG_RESULT([yes])
NEEDS_LIBICONV=],
[AC_MSG_RESULT([no])
old_LIBS="$LIBS"
LIBS="$LIBS -liconv"
AC_MSG_CHECKING([for iconv in -liconv])
AC_LINK_IFELSE(ICONVTEST_SRC,
[AC_MSG_RESULT([yes])
NEEDS_LIBICONV=YesPlease],
[AC_MSG_RESULT([no])
NO_ICONV=YesPlease])
LIBS="$old_LIBS"])
AC_SUBST(NEEDS_LIBICONV)
AC_SUBST(NO_ICONV)
test -n "$NEEDS_LIBICONV" && LIBS="$LIBS -liconv"

View file

@ -96,7 +96,7 @@ int get_ack(int fd, unsigned char *result_sha1)
line[--len] = 0;
if (!strcmp(line, "NAK"))
return 0;
if (!strncmp(line, "ACK ", 4)) {
if (!prefixcmp(line, "ACK ")) {
if (!get_sha1_hex(line+4, result_sha1)) {
if (strstr(line+45, "continue"))
return 2;
@ -196,8 +196,8 @@ static int count_refspec_match(const char *pattern,
*/
if (namelen != patlen &&
patlen != namelen - 5 &&
strncmp(name, "refs/heads/", 11) &&
strncmp(name, "refs/tags/", 10)) {
prefixcmp(name, "refs/heads/") &&
prefixcmp(name, "refs/tags/")) {
/* We want to catch the case where only weak
* matches are found and there are multiple
* matches, and where more than one strong

View file

@ -25,11 +25,14 @@
my $tar_name = $1;
if ($tar_name =~ s/\.(tar\.gz|tgz)$//) {
open(I, '-|', 'gzcat', $tar_file) or die "Unable to gzcat $tar_file: $!\n";
open(I, '-|', 'gunzip', '-c', $tar_file)
or die "Unable to gunzip -c $tar_file: $!\n";
} elsif ($tar_name =~ s/\.(tar\.bz2|tbz2)$//) {
open(I, '-|', 'bzcat', $tar_file) or die "Unable to bzcat $tar_file: $!\n";
open(I, '-|', 'bunzip2', '-c', $tar_file)
or die "Unable to bunzip2 -c $tar_file: $!\n";
} elsif ($tar_name =~ s/\.tar\.Z$//) {
open(I, '-|', 'zcat', $tar_file) or die "Unable to zcat $tar_file: $!\n";
open(I, '-|', 'uncompress', '-c', $tar_file)
or die "Unable to uncompress -c $tar_file: $!\n";
} elsif ($tar_name =~ s/\.tar$//) {
open(I, $tar_file) or die "Unable to open $tar_file: $!\n";
} else {

186
convert.c Normal file
View file

@ -0,0 +1,186 @@
#include "cache.h"
/*
* convert.c - convert a file when checking it out and checking it in.
*
* This should use the pathname to decide on whether it wants to do some
* more interesting conversions (automatic gzip/unzip, general format
* conversions etc etc), but by default it just does automatic CRLF<->LF
* translation when the "auto_crlf" option is set.
*/
struct text_stat {
/* CR, LF and CRLF counts */
unsigned cr, lf, crlf;
/* These are just approximations! */
unsigned printable, nonprintable;
};
static void gather_stats(const char *buf, unsigned long size, struct text_stat *stats)
{
unsigned long i;
memset(stats, 0, sizeof(*stats));
for (i = 0; i < size; i++) {
unsigned char c = buf[i];
if (c == '\r') {
stats->cr++;
if (i+1 < size && buf[i+1] == '\n')
stats->crlf++;
continue;
}
if (c == '\n') {
stats->lf++;
continue;
}
if (c == 127)
/* DEL */
stats->nonprintable++;
else if (c < 32) {
switch (c) {
/* BS, HT, ESC and FF */
case '\b': case '\t': case '\033': case '\014':
stats->printable++;
break;
default:
stats->nonprintable++;
}
}
else
stats->printable++;
}
}
/*
* The same heuristics as diff.c::mmfile_is_binary()
*/
static int is_binary(unsigned long size, struct text_stat *stats)
{
if ((stats->printable >> 7) < stats->nonprintable)
return 1;
/*
* Other heuristics? Average line length might be relevant,
* as might LF vs CR vs CRLF counts..
*
* NOTE! It might be normal to have a low ratio of CRLF to LF
* (somebody starts with a LF-only file and edits it with an editor
* that adds CRLF only to lines that are added..). But do we
* want to support CR-only? Probably not.
*/
return 0;
}
int convert_to_git(const char *path, char **bufp, unsigned long *sizep)
{
char *buffer, *nbuf;
unsigned long size, nsize;
struct text_stat stats;
/*
* FIXME! Other pluggable conversions should go here,
* based on filename patterns. Right now we just do the
* stupid auto-CRLF one.
*/
if (!auto_crlf)
return 0;
size = *sizep;
if (!size)
return 0;
buffer = *bufp;
gather_stats(buffer, size, &stats);
/* No CR? Nothing to convert, regardless. */
if (!stats.cr)
return 0;
/*
* We're currently not going to even try to convert stuff
* that has bare CR characters. Does anybody do that crazy
* stuff?
*/
if (stats.cr != stats.crlf)
return 0;
/*
* And add some heuristics for binary vs text, of course...
*/
if (is_binary(size, &stats))
return 0;
/*
* Ok, allocate a new buffer, fill it in, and return true
* to let the caller know that we switched buffers on it.
*/
nsize = size - stats.crlf;
nbuf = xmalloc(nsize);
*bufp = nbuf;
*sizep = nsize;
do {
unsigned char c = *buffer++;
if (c != '\r')
*nbuf++ = c;
} while (--size);
return 1;
}
int convert_to_working_tree(const char *path, char **bufp, unsigned long *sizep)
{
char *buffer, *nbuf;
unsigned long size, nsize;
struct text_stat stats;
unsigned char last;
/*
* FIXME! Other pluggable conversions should go here,
* based on filename patterns. Right now we just do the
* stupid auto-CRLF one.
*/
if (auto_crlf <= 0)
return 0;
size = *sizep;
if (!size)
return 0;
buffer = *bufp;
gather_stats(buffer, size, &stats);
/* No LF? Nothing to convert, regardless. */
if (!stats.lf)
return 0;
/* Was it already in CRLF format? */
if (stats.lf == stats.crlf)
return 0;
/* If we have any bare CR characters, we're not going to touch it */
if (stats.cr != stats.crlf)
return 0;
if (is_binary(size, &stats))
return 0;
/*
* Ok, allocate a new buffer, fill it in, and return true
* to let the caller know that we switched buffers on it.
*/
nsize = size + stats.lf - stats.crlf;
nbuf = xmalloc(nsize);
*bufp = nbuf;
*sizep = nsize;
last = 0;
do {
unsigned char c = *buffer++;
if (c == '\n' && last != '\r')
*nbuf++ = '\r';
*nbuf++ = c;
last = c;
} while (--size);
return 1;
}

View file

@ -286,7 +286,7 @@ static int service_enabled;
static int git_daemon_config(const char *var, const char *value)
{
if (!strncmp(var, "daemon.", 7) &&
if (!prefixcmp(var, "daemon.") &&
!strcmp(var + 7, service_looking_at->config_name)) {
service_enabled = git_config_bool(var, value);
return 0;
@ -562,7 +562,7 @@ static int execute(struct sockaddr *addr)
for (i = 0; i < ARRAY_SIZE(daemon_service); i++) {
struct daemon_service *s = &(daemon_service[i]);
int namelen = strlen(s->name);
if (!strncmp("git-", line, 4) &&
if (!prefixcmp(line, "git-") &&
!strncmp(s->name, line + 4, namelen) &&
line[namelen + 4] == ' ') {
/*
@ -1011,7 +1011,7 @@ int main(int argc, char **argv)
for (i = 1; i < argc; i++) {
char *arg = argv[i];
if (!strncmp(arg, "--listen=", 9)) {
if (!prefixcmp(arg, "--listen=")) {
char *p = arg + 9;
char *ph = listen_addr = xmalloc(strlen(arg + 9) + 1);
while (*p)
@ -1019,7 +1019,7 @@ int main(int argc, char **argv)
*ph = 0;
continue;
}
if (!strncmp(arg, "--port=", 7)) {
if (!prefixcmp(arg, "--port=")) {
char *end;
unsigned long n;
n = strtoul(arg+7, &end, 0);
@ -1045,11 +1045,11 @@ int main(int argc, char **argv)
export_all_trees = 1;
continue;
}
if (!strncmp(arg, "--timeout=", 10)) {
if (!prefixcmp(arg, "--timeout=")) {
timeout = atoi(arg+10);
continue;
}
if (!strncmp(arg, "--init-timeout=", 15)) {
if (!prefixcmp(arg, "--init-timeout=")) {
init_timeout = atoi(arg+15);
continue;
}
@ -1057,11 +1057,11 @@ int main(int argc, char **argv)
strict_paths = 1;
continue;
}
if (!strncmp(arg, "--base-path=", 12)) {
if (!prefixcmp(arg, "--base-path=")) {
base_path = arg+12;
continue;
}
if (!strncmp(arg, "--interpolated-path=", 20)) {
if (!prefixcmp(arg, "--interpolated-path=")) {
interpolated_path = arg+20;
continue;
}
@ -1073,11 +1073,11 @@ int main(int argc, char **argv)
user_path = "";
continue;
}
if (!strncmp(arg, "--user-path=", 12)) {
if (!prefixcmp(arg, "--user-path=")) {
user_path = arg + 12;
continue;
}
if (!strncmp(arg, "--pid-file=", 11)) {
if (!prefixcmp(arg, "--pid-file=")) {
pid_file = arg + 11;
continue;
}
@ -1086,27 +1086,27 @@ int main(int argc, char **argv)
log_syslog = 1;
continue;
}
if (!strncmp(arg, "--user=", 7)) {
if (!prefixcmp(arg, "--user=")) {
user_name = arg + 7;
continue;
}
if (!strncmp(arg, "--group=", 8)) {
if (!prefixcmp(arg, "--group=")) {
group_name = arg + 8;
continue;
}
if (!strncmp(arg, "--enable=", 9)) {
if (!prefixcmp(arg, "--enable=")) {
enable_service(arg + 9, 1);
continue;
}
if (!strncmp(arg, "--disable=", 10)) {
if (!prefixcmp(arg, "--disable=")) {
enable_service(arg + 10, 0);
continue;
}
if (!strncmp(arg, "--allow-override=", 17)) {
if (!prefixcmp(arg, "--allow-override=")) {
make_service_overridable(arg + 17, 1);
continue;
}
if (!strncmp(arg, "--forbid-override=", 18)) {
if (!prefixcmp(arg, "--forbid-override=")) {
make_service_overridable(arg + 18, 0);
continue;
}

View file

@ -248,17 +248,27 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed)
path_len = ce_namelen(ce);
dpath = xmalloc (combine_diff_path_size (5, path_len));
dpath = xmalloc(combine_diff_path_size(5, path_len));
dpath->path = (char *) &(dpath->parent[5]);
dpath->next = NULL;
dpath->len = path_len;
memcpy(dpath->path, ce->name, path_len);
dpath->path[path_len] = '\0';
dpath->mode = 0;
hashclr(dpath->sha1);
memset(&(dpath->parent[0]), 0,
sizeof(struct combine_diff_parent)*5);
sizeof(struct combine_diff_parent)*5);
if (lstat(ce->name, &st) < 0) {
if (errno != ENOENT && errno != ENOTDIR) {
perror(ce->name);
continue;
}
if (silent_on_removed)
continue;
}
else
dpath->mode = canon_mode(st.st_mode);
while (i < entries) {
struct cache_entry *nce = active_cache[i];

149
diff.c
View file

@ -77,7 +77,7 @@ int git_diff_ui_config(const char *var, const char *value)
diff_detect_rename_default = DIFF_DETECT_RENAME;
return 0;
}
if (!strncmp(var, "diff.color.", 11) || !strncmp(var, "color.diff.", 11)) {
if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) {
int slot = parse_diff_color_slot(var, 11);
color_parse(value, var, diff_colors[slot]);
return 0;
@ -184,31 +184,43 @@ static void print_line_count(int count)
}
}
static void copy_file(int prefix, const char *data, int size)
static void copy_file(int prefix, const char *data, int size,
const char *set, const char *reset)
{
int ch, nl_just_seen = 1;
while (0 < size--) {
ch = *data++;
if (nl_just_seen)
if (nl_just_seen) {
fputs(set, stdout);
putchar(prefix);
putchar(ch);
if (ch == '\n')
}
if (ch == '\n') {
nl_just_seen = 1;
else
fputs(reset, stdout);
} else
nl_just_seen = 0;
putchar(ch);
}
if (!nl_just_seen)
printf("\n\\ No newline at end of file\n");
printf("%s\n\\ No newline at end of file\n", reset);
}
static void emit_rewrite_diff(const char *name_a,
const char *name_b,
struct diff_filespec *one,
struct diff_filespec *two)
struct diff_filespec *two,
int color_diff)
{
int lc_a, lc_b;
const char *name_a_tab, *name_b_tab;
const char *metainfo = diff_get_color(color_diff, DIFF_METAINFO);
const char *fraginfo = diff_get_color(color_diff, DIFF_FRAGINFO);
const char *old = diff_get_color(color_diff, DIFF_FILE_OLD);
const char *new = diff_get_color(color_diff, DIFF_FILE_NEW);
const char *reset = diff_get_color(color_diff, DIFF_RESET);
name_a += (*name_a == '/');
name_b += (*name_b == '/');
name_a_tab = strchr(name_a, ' ') ? "\t" : "";
name_b_tab = strchr(name_b, ' ') ? "\t" : "";
@ -216,17 +228,17 @@ static void emit_rewrite_diff(const char *name_a,
diff_populate_filespec(two, 0);
lc_a = count_lines(one->data, one->size);
lc_b = count_lines(two->data, two->size);
printf("--- a/%s%s\n+++ b/%s%s\n@@ -",
name_a, name_a_tab,
name_b, name_b_tab);
printf("%s--- a/%s%s%s\n%s+++ b/%s%s%s\n%s@@ -",
metainfo, name_a, name_a_tab, reset,
metainfo, name_b, name_b_tab, reset, fraginfo);
print_line_count(lc_a);
printf(" +");
print_line_count(lc_b);
printf(" @@\n");
printf(" @@%s\n", reset);
if (lc_a)
copy_file('-', one->data, one->size);
copy_file('-', one->data, one->size, old, reset);
if (lc_b)
copy_file('+', two->data, two->size);
copy_file('+', two->data, two->size, new, reset);
}
static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one)
@ -405,22 +417,16 @@ static void emit_line(const char *set, const char *reset, const char *line, int
puts(reset);
}
static void emit_add_line(const char *reset, struct emit_callback *ecbdata, const char *line, int len)
static void emit_line_with_ws(int nparents,
const char *set, const char *reset, const char *ws,
const char *line, int len)
{
int col0 = ecbdata->nparents;
int col0 = nparents;
int last_tab_in_indent = -1;
int last_space_in_indent = -1;
int i;
int tail = len;
int need_highlight_leading_space = 0;
const char *ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE);
const char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_NEW);
if (!*ws) {
emit_line(set, reset, line, len);
return;
}
/* The line is a newly added line. Does it have funny leading
* whitespaces? In indent, SP should never precede a TAB.
*/
@ -475,6 +481,18 @@ static void emit_add_line(const char *reset, struct emit_callback *ecbdata, cons
emit_line(set, reset, line + i, len - i);
}
static void emit_add_line(const char *reset, struct emit_callback *ecbdata, const char *line, int len)
{
const char *ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE);
const char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_NEW);
if (!*ws)
emit_line(set, reset, line, len);
else
emit_line_with_ws(ecbdata->nparents, set, reset, ws,
line, len);
}
static void fn_out_consume(void *priv, char *line, unsigned long len)
{
int i;
@ -884,30 +902,44 @@ static void show_numstat(struct diffstat_t* data, struct diff_options *options)
struct checkdiff_t {
struct xdiff_emit_state xm;
const char *filename;
int lineno;
int lineno, color_diff;
};
static void checkdiff_consume(void *priv, char *line, unsigned long len)
{
struct checkdiff_t *data = priv;
const char *ws = diff_get_color(data->color_diff, DIFF_WHITESPACE);
const char *reset = diff_get_color(data->color_diff, DIFF_RESET);
const char *set = diff_get_color(data->color_diff, DIFF_FILE_NEW);
if (line[0] == '+') {
int i, spaces = 0;
int i, spaces = 0, space_before_tab = 0, white_space_at_end = 0;
/* check space before tab */
for (i = 1; i < len && (line[i] == ' ' || line[i] == '\t'); i++)
if (line[i] == ' ')
spaces++;
if (line[i - 1] == '\t' && spaces)
printf("%s:%d: space before tab:%.*s\n",
data->filename, data->lineno, (int)len, line);
space_before_tab = 1;
/* check white space at line end */
if (line[len - 1] == '\n')
len--;
if (isspace(line[len - 1]))
printf("%s:%d: white space at end: %.*s\n",
data->filename, data->lineno, (int)len, line);
white_space_at_end = 1;
if (space_before_tab || white_space_at_end) {
printf("%s:%d: %s", data->filename, data->lineno, ws);
if (space_before_tab) {
printf("space before tab");
if (white_space_at_end)
putchar(',');
}
if (white_space_at_end)
printf("white space at end");
printf(":%s ", reset);
emit_line_with_ws(1, set, reset, ws, line, len);
}
data->lineno++;
} else if (line[0] == ' ')
@ -1034,8 +1066,8 @@ static void builtin_diff(const char *name_a,
const char *set = diff_get_color(o->color_diff, DIFF_METAINFO);
const char *reset = diff_get_color(o->color_diff, DIFF_RESET);
a_one = quote_two("a/", name_a);
b_two = quote_two("b/", name_b);
a_one = quote_two("a/", name_a + (*name_a == '/'));
b_two = quote_two("b/", name_b + (*name_b == '/'));
lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null";
lbl[1] = DIFF_FILE_VALID(two) ? b_two : "/dev/null";
printf("%sdiff --git %s %s%s\n", set, a_one, b_two, reset);
@ -1064,7 +1096,8 @@ static void builtin_diff(const char *name_a,
if ((one->mode ^ two->mode) & S_IFMT)
goto free_ab_and_return;
if (complete_rewrite) {
emit_rewrite_diff(name_a, name_b, one, two);
emit_rewrite_diff(name_a, name_b, one, two,
o->color_diff);
goto free_ab_and_return;
}
}
@ -1099,9 +1132,9 @@ static void builtin_diff(const char *name_a,
xecfg.flags = XDL_EMIT_FUNCNAMES;
if (!diffopts)
;
else if (!strncmp(diffopts, "--unified=", 10))
else if (!prefixcmp(diffopts, "--unified="))
xecfg.ctxlen = strtoul(diffopts + 10, NULL, 10);
else if (!strncmp(diffopts, "-u", 2))
else if (!prefixcmp(diffopts, "-u"))
xecfg.ctxlen = strtoul(diffopts + 2, NULL, 10);
ecb.outf = xdiff_outf;
ecb.priv = &ecbdata;
@ -1165,7 +1198,7 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
static void builtin_checkdiff(const char *name_a, const char *name_b,
struct diff_filespec *one,
struct diff_filespec *two)
struct diff_filespec *two, struct diff_options *o)
{
mmfile_t mf1, mf2;
struct checkdiff_t data;
@ -1177,6 +1210,7 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
data.xm.consume = checkdiff_consume;
data.filename = name_b ? name_b : name_a;
data.lineno = 0;
data.color_diff = o->color_diff;
if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
die("unable to read files to diff");
@ -1346,6 +1380,9 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
reuse_worktree_file(s->path, s->sha1, 0)) {
struct stat st;
int fd;
char *buf;
unsigned long size;
if (lstat(s->path, &st) < 0) {
if (errno == ENOENT) {
err_empty:
@ -1378,7 +1415,19 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
s->data = xmmap(NULL, s->size, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
s->should_munmap = 1;
/* FIXME! CRLF -> LF conversion goes here, based on "s->path" */
/*
* Convert from working tree format to canonical git format
*/
buf = s->data;
size = s->size;
if (convert_to_git(s->path, &buf, &size)) {
munmap(s->data, s->size);
s->should_munmap = 0;
s->data = buf;
s->size = size;
s->should_free = 1;
}
}
else {
char type[20];
@ -1787,7 +1836,7 @@ static void run_checkdiff(struct diff_filepair *p, struct diff_options *o)
diff_fill_sha1_info(p->one);
diff_fill_sha1_info(p->two);
builtin_checkdiff(name, other, p->one, p->two);
builtin_checkdiff(name, other, p->one, p->two, o);
}
void diff_setup(struct diff_options *options)
@ -1936,7 +1985,7 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
else if (!strcmp(arg, "--shortstat")) {
options->output_format |= DIFF_FORMAT_SHORTSTAT;
}
else if (!strncmp(arg, "--stat", 6)) {
else if (!prefixcmp(arg, "--stat")) {
char *end;
int width = options->stat_width;
int name_width = options->stat_name_width;
@ -1945,9 +1994,9 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
switch (*arg) {
case '-':
if (!strncmp(arg, "-width=", 7))
if (!prefixcmp(arg, "-width="))
width = strtoul(arg + 7, &end, 10);
else if (!strncmp(arg, "-name-width=", 12))
else if (!prefixcmp(arg, "-name-width="))
name_width = strtoul(arg + 12, &end, 10);
break;
case '=':
@ -1972,7 +2021,7 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
}
else if (!strcmp(arg, "-z"))
options->line_termination = 0;
else if (!strncmp(arg, "-l", 2))
else if (!prefixcmp(arg, "-l"))
options->rename_limit = strtoul(arg+2, NULL, 10);
else if (!strcmp(arg, "--full-index"))
options->full_index = 1;
@ -1989,31 +2038,31 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
options->output_format |= DIFF_FORMAT_NAME_STATUS;
else if (!strcmp(arg, "-R"))
options->reverse_diff = 1;
else if (!strncmp(arg, "-S", 2))
else if (!prefixcmp(arg, "-S"))
options->pickaxe = arg + 2;
else if (!strcmp(arg, "-s")) {
options->output_format |= DIFF_FORMAT_NO_OUTPUT;
}
else if (!strncmp(arg, "-O", 2))
else if (!prefixcmp(arg, "-O"))
options->orderfile = arg + 2;
else if (!strncmp(arg, "--diff-filter=", 14))
else if (!prefixcmp(arg, "--diff-filter="))
options->filter = arg + 14;
else if (!strcmp(arg, "--pickaxe-all"))
options->pickaxe_opts = DIFF_PICKAXE_ALL;
else if (!strcmp(arg, "--pickaxe-regex"))
options->pickaxe_opts = DIFF_PICKAXE_REGEX;
else if (!strncmp(arg, "-B", 2)) {
else if (!prefixcmp(arg, "-B")) {
if ((options->break_opt =
diff_scoreopt_parse(arg)) == -1)
return -1;
}
else if (!strncmp(arg, "-M", 2)) {
else if (!prefixcmp(arg, "-M")) {
if ((options->rename_score =
diff_scoreopt_parse(arg)) == -1)
return -1;
options->detect_rename = DIFF_DETECT_RENAME;
}
else if (!strncmp(arg, "-C", 2)) {
else if (!prefixcmp(arg, "-C")) {
if ((options->rename_score =
diff_scoreopt_parse(arg)) == -1)
return -1;
@ -2023,7 +2072,7 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
options->find_copies_harder = 1;
else if (!strcmp(arg, "--abbrev"))
options->abbrev = DEFAULT_ABBREV;
else if (!strncmp(arg, "--abbrev=", 9)) {
else if (!prefixcmp(arg, "--abbrev=")) {
options->abbrev = strtoul(arg + 9, NULL, 10);
if (options->abbrev < MINIMUM_ABBREV)
options->abbrev = MINIMUM_ABBREV;
@ -2533,7 +2582,7 @@ static void patch_id_consume(void *priv, char *line, unsigned long len)
int new_len;
/* Ignore line numbers when computing the SHA1 of the patch */
if (!strncmp(line, "@@ -", 4))
if (!prefixcmp(line, "@@ -"))
return;
new_len = remove_space(line, len);

16
entry.c
View file

@ -78,6 +78,9 @@ static int write_entry(struct cache_entry *ce, char *path, struct checkout *stat
path, sha1_to_hex(ce->sha1));
}
switch (ntohl(ce->ce_mode) & S_IFMT) {
char *buf;
unsigned long nsize;
case S_IFREG:
if (to_tempfile) {
strcpy(path, ".merge_file_XXXXXX");
@ -89,7 +92,18 @@ static int write_entry(struct cache_entry *ce, char *path, struct checkout *stat
return error("git-checkout-index: unable to create file %s (%s)",
path, strerror(errno));
}
/* FIXME: LF -> CRLF conversion goes here, based on "ce->name" */
/*
* Convert from git internal format to working tree format
*/
buf = new;
nsize = size;
if (convert_to_working_tree(ce->name, &buf, &nsize)) {
free(new);
new = buf;
size = nsize;
}
wrote = write_in_full(fd, new, size);
close(fd);
free(new);

View file

@ -28,6 +28,7 @@ size_t packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE;
size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT;
int pager_in_use;
int pager_use_color = 1;
int auto_crlf = 0; /* 1: both ways, -1: only when adding git objects */
static const char *git_dir;
static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file;

View file

@ -56,7 +56,7 @@ int execv_git_cmd(const char **argv)
len = strlen(git_command);
/* Trivial cleanup */
while (!strncmp(exec_dir, "./", 2)) {
while (!prefixcmp(exec_dir, "./")) {
exec_dir += 2;
while (*exec_dir == '/')
exec_dir++;

View file

@ -133,6 +133,10 @@ Format of STDIN stream:
#define PACK_ID_BITS 16
#define MAX_PACK_ID ((1<<PACK_ID_BITS)-1)
#ifndef PRIuMAX
#define PRIuMAX "llu"
#endif
struct object_entry
{
struct object_entry *next;
@ -475,7 +479,7 @@ static struct object_entry *find_mark(uintmax_t idnum)
oe = s->data.marked[idnum];
}
if (!oe)
die("mark :%ju not declared", orig_idnum);
die("mark :%" PRIuMAX " not declared", orig_idnum);
return oe;
}
@ -1361,7 +1365,7 @@ static void dump_marks_helper(FILE *f,
} else {
for (k = 0; k < 1024; k++) {
if (m->data.marked[k])
fprintf(f, ":%ju %s\n", base + k,
fprintf(f, ":%" PRIuMAX " %s\n", base + k,
sha1_to_hex(m->data.marked[k]->sha1));
}
}
@ -1388,7 +1392,7 @@ static void read_next_command(void)
static void cmd_mark(void)
{
if (!strncmp("mark :", command_buf.buf, 6)) {
if (!prefixcmp(command_buf.buf, "mark :")) {
next_mark = strtoumax(command_buf.buf + 6, NULL, 10);
read_next_command();
}
@ -1401,10 +1405,10 @@ static void *cmd_data (size_t *size)
size_t length;
char *buffer;
if (strncmp("data ", command_buf.buf, 5))
if (prefixcmp(command_buf.buf, "data "))
die("Expected 'data n' command, found: %s", command_buf.buf);
if (!strncmp("<<", command_buf.buf + 5, 2)) {
if (!prefixcmp(command_buf.buf + 5, "<<")) {
char *term = xstrdup(command_buf.buf + 5 + 2);
size_t sz = 8192, term_len = command_buf.len - 5 - 2;
length = 0;
@ -1591,7 +1595,7 @@ static void file_change_m(struct branch *b)
oe = find_mark(strtoumax(p + 1, &x, 10));
hashcpy(sha1, oe->sha1);
p = x;
} else if (!strncmp("inline", p, 6)) {
} else if (!prefixcmp(p, "inline")) {
inline_data = 1;
p += 6;
} else {
@ -1664,7 +1668,7 @@ static void cmd_from(struct branch *b)
const char *from;
struct branch *s;
if (strncmp("from ", command_buf.buf, 5))
if (prefixcmp(command_buf.buf, "from "))
return;
if (b->branch_tree.tree) {
@ -1687,7 +1691,7 @@ static void cmd_from(struct branch *b)
unsigned long size;
char *buf;
if (oe->type != OBJ_COMMIT)
die("Mark :%ju not a commit", idnum);
die("Mark :%" PRIuMAX " not a commit", idnum);
hashcpy(b->sha1, oe->sha1);
buf = gfi_unpack_entry(oe, &size);
if (!buf || size < 46)
@ -1730,7 +1734,7 @@ static struct hash_list *cmd_merge(unsigned int *count)
struct branch *s;
*count = 0;
while (!strncmp("merge ", command_buf.buf, 6)) {
while (!prefixcmp(command_buf.buf, "merge ")) {
from = strchr(command_buf.buf, ' ') + 1;
n = xmalloc(sizeof(*n));
s = lookup_branch(from);
@ -1740,7 +1744,7 @@ static struct hash_list *cmd_merge(unsigned int *count)
uintmax_t idnum = strtoumax(from + 1, NULL, 10);
struct object_entry *oe = find_mark(idnum);
if (oe->type != OBJ_COMMIT)
die("Mark :%ju not a commit", idnum);
die("Mark :%" PRIuMAX " not a commit", idnum);
hashcpy(n->sha1, oe->sha1);
} else if (get_sha1(from, n->sha1))
die("Invalid ref name or SHA1 expression: %s", from);
@ -1776,11 +1780,11 @@ static void cmd_new_commit(void)
read_next_command();
cmd_mark();
if (!strncmp("author ", command_buf.buf, 7)) {
if (!prefixcmp(command_buf.buf, "author ")) {
author = parse_ident(command_buf.buf + 7);
read_next_command();
}
if (!strncmp("committer ", command_buf.buf, 10)) {
if (!prefixcmp(command_buf.buf, "committer ")) {
committer = parse_ident(command_buf.buf + 10);
read_next_command();
}
@ -1801,9 +1805,9 @@ static void cmd_new_commit(void)
for (;;) {
if (1 == command_buf.len)
break;
else if (!strncmp("M ", command_buf.buf, 2))
else if (!prefixcmp(command_buf.buf, "M "))
file_change_m(b);
else if (!strncmp("D ", command_buf.buf, 2))
else if (!prefixcmp(command_buf.buf, "D "))
file_change_d(b);
else if (!strcmp("deleteall", command_buf.buf))
file_change_deleteall(b);
@ -1873,7 +1877,7 @@ static void cmd_new_tag(void)
read_next_command();
/* from ... */
if (strncmp("from ", command_buf.buf, 5))
if (prefixcmp(command_buf.buf, "from "))
die("Expected from command, got %s", command_buf.buf);
from = strchr(command_buf.buf, ' ') + 1;
s = lookup_branch(from);
@ -1884,7 +1888,7 @@ static void cmd_new_tag(void)
from_mark = strtoumax(from + 1, NULL, 10);
oe = find_mark(from_mark);
if (oe->type != OBJ_COMMIT)
die("Mark :%ju not a commit", from_mark);
die("Mark :%" PRIuMAX " not a commit", from_mark);
hashcpy(sha1, oe->sha1);
} else if (!get_sha1(from, sha1)) {
unsigned long size;
@ -1900,7 +1904,7 @@ static void cmd_new_tag(void)
read_next_command();
/* tagger ... */
if (strncmp("tagger ", command_buf.buf, 7))
if (prefixcmp(command_buf.buf, "tagger "))
die("Expected tagger command, got %s", command_buf.buf);
tagger = parse_ident(command_buf.buf + 7);
@ -1977,7 +1981,7 @@ int main(int argc, const char **argv)
if (*a != '-' || !strcmp(a, "--"))
break;
else if (!strncmp(a, "--date-format=", 14)) {
else if (!prefixcmp(a, "--date-format=")) {
const char *fmt = a + 14;
if (!strcmp(fmt, "raw"))
whenspec = WHENSPEC_RAW;
@ -1988,15 +1992,15 @@ int main(int argc, const char **argv)
else
die("unknown --date-format argument %s", fmt);
}
else if (!strncmp(a, "--max-pack-size=", 16))
else if (!prefixcmp(a, "--max-pack-size="))
max_packsize = strtoumax(a + 16, NULL, 0) * 1024 * 1024;
else if (!strncmp(a, "--depth=", 8))
else if (!prefixcmp(a, "--depth="))
max_depth = strtoul(a + 8, NULL, 0);
else if (!strncmp(a, "--active-branches=", 18))
else if (!prefixcmp(a, "--active-branches="))
max_active_branches = strtoul(a + 18, NULL, 0);
else if (!strncmp(a, "--export-marks=", 15))
else if (!prefixcmp(a, "--export-marks="))
mark_file = a + 15;
else if (!strncmp(a, "--export-pack-edges=", 20)) {
else if (!prefixcmp(a, "--export-pack-edges=")) {
if (pack_edges)
fclose(pack_edges);
pack_edges = fopen(a + 20, "a");
@ -2029,11 +2033,11 @@ int main(int argc, const char **argv)
break;
else if (!strcmp("blob", command_buf.buf))
cmd_new_blob();
else if (!strncmp("commit ", command_buf.buf, 7))
else if (!prefixcmp(command_buf.buf, "commit "))
cmd_new_commit();
else if (!strncmp("tag ", command_buf.buf, 4))
else if (!prefixcmp(command_buf.buf, "tag "))
cmd_new_tag();
else if (!strncmp("reset ", command_buf.buf, 6))
else if (!prefixcmp(command_buf.buf, "reset "))
cmd_reset_branch();
else if (!strcmp("checkpoint", command_buf.buf))
cmd_checkpoint();
@ -2059,18 +2063,18 @@ int main(int argc, const char **argv)
fprintf(stderr, "%s statistics:\n", argv[0]);
fprintf(stderr, "---------------------------------------------------------------------\n");
fprintf(stderr, "Alloc'd objects: %10ju\n", alloc_count);
fprintf(stderr, "Total objects: %10ju (%10ju duplicates )\n", total_count, duplicate_count);
fprintf(stderr, " blobs : %10ju (%10ju duplicates %10ju deltas)\n", object_count_by_type[OBJ_BLOB], duplicate_count_by_type[OBJ_BLOB], delta_count_by_type[OBJ_BLOB]);
fprintf(stderr, " trees : %10ju (%10ju duplicates %10ju deltas)\n", object_count_by_type[OBJ_TREE], duplicate_count_by_type[OBJ_TREE], delta_count_by_type[OBJ_TREE]);
fprintf(stderr, " commits: %10ju (%10ju duplicates %10ju deltas)\n", object_count_by_type[OBJ_COMMIT], duplicate_count_by_type[OBJ_COMMIT], delta_count_by_type[OBJ_COMMIT]);
fprintf(stderr, " tags : %10ju (%10ju duplicates %10ju deltas)\n", object_count_by_type[OBJ_TAG], duplicate_count_by_type[OBJ_TAG], delta_count_by_type[OBJ_TAG]);
fprintf(stderr, "Alloc'd objects: %10" PRIuMAX "\n", alloc_count);
fprintf(stderr, "Total objects: %10" PRIuMAX " (%10" PRIuMAX " duplicates )\n", total_count, duplicate_count);
fprintf(stderr, " blobs : %10" PRIuMAX " (%10" PRIuMAX " duplicates %10" PRIuMAX " deltas)\n", object_count_by_type[OBJ_BLOB], duplicate_count_by_type[OBJ_BLOB], delta_count_by_type[OBJ_BLOB]);
fprintf(stderr, " trees : %10" PRIuMAX " (%10" PRIuMAX " duplicates %10" PRIuMAX " deltas)\n", object_count_by_type[OBJ_TREE], duplicate_count_by_type[OBJ_TREE], delta_count_by_type[OBJ_TREE]);
fprintf(stderr, " commits: %10" PRIuMAX " (%10" PRIuMAX " duplicates %10" PRIuMAX " deltas)\n", object_count_by_type[OBJ_COMMIT], duplicate_count_by_type[OBJ_COMMIT], delta_count_by_type[OBJ_COMMIT]);
fprintf(stderr, " tags : %10" PRIuMAX " (%10" PRIuMAX " duplicates %10" PRIuMAX " deltas)\n", object_count_by_type[OBJ_TAG], duplicate_count_by_type[OBJ_TAG], delta_count_by_type[OBJ_TAG]);
fprintf(stderr, "Total branches: %10lu (%10lu loads )\n", branch_count, branch_load_count);
fprintf(stderr, " marks: %10ju (%10ju unique )\n", (((uintmax_t)1) << marks->shift) * 1024, marks_set_count);
fprintf(stderr, " marks: %10" PRIuMAX " (%10" PRIuMAX " unique )\n", (((uintmax_t)1) << marks->shift) * 1024, marks_set_count);
fprintf(stderr, " atoms: %10u\n", atom_cnt);
fprintf(stderr, "Memory total: %10ju KiB\n", (total_allocd + alloc_count*sizeof(struct object_entry))/1024);
fprintf(stderr, "Memory total: %10" PRIuMAX " KiB\n", (total_allocd + alloc_count*sizeof(struct object_entry))/1024);
fprintf(stderr, " pools: %10lu KiB\n", (unsigned long)(total_allocd/1024));
fprintf(stderr, " objects: %10ju KiB\n", (alloc_count*sizeof(struct object_entry))/1024);
fprintf(stderr, " objects: %10" PRIuMAX " KiB\n", (alloc_count*sizeof(struct object_entry))/1024);
fprintf(stderr, "---------------------------------------------------------------------\n");
pack_report();
fprintf(stderr, "---------------------------------------------------------------------\n");

View file

@ -198,13 +198,13 @@ static int find_common(int fd[2], unsigned char *result_sha1,
int len;
while ((len = packet_read_line(fd[0], line, sizeof(line)))) {
if (!strncmp("shallow ", line, 8)) {
if (!prefixcmp(line, "shallow ")) {
if (get_sha1_hex(line + 8, sha1))
die("invalid shallow line: %s", line);
register_shallow(sha1);
continue;
}
if (!strncmp("unshallow ", line, 10)) {
if (!prefixcmp(line, "unshallow ")) {
if (get_sha1_hex(line + 10, sha1))
die("invalid unshallow line: %s", line);
if (!lookup_object(sha1))
@ -346,7 +346,7 @@ static void filter_refs(struct ref **refs, int nr_match, char **match)
check_ref_format(ref->name + 5))
; /* trash */
else if (fetch_all &&
(!depth || strncmp(ref->name, "refs/tags/", 10) )) {
(!depth || prefixcmp(ref->name, "refs/tags/") )) {
*newtail = ref;
ref->next = NULL;
newtail = &ref->next;
@ -683,11 +683,11 @@ int main(int argc, char **argv)
char *arg = argv[i];
if (*arg == '-') {
if (!strncmp("--upload-pack=", arg, 14)) {
if (!prefixcmp(arg, "--upload-pack=")) {
uploadpack = arg + 14;
continue;
}
if (!strncmp("--exec=", arg, 7)) {
if (!prefixcmp(arg, "--exec=")) {
uploadpack = arg + 7;
continue;
}
@ -712,7 +712,7 @@ int main(int argc, char **argv)
verbose = 1;
continue;
}
if (!strncmp("--depth=", arg, 8)) {
if (!prefixcmp(arg, "--depth=")) {
depth = strtol(arg + 8, NULL, 0);
if (stat(git_path("shallow"), &st))
st.st_mtime = 0;

View file

@ -66,7 +66,7 @@ fall_back_3way () {
git-update-index -z --index-info <"$dotest/patch-merge-index-info" &&
GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
git-write-tree >"$dotest/patch-merge-base+" ||
cannot_fallback "Patch does not record usable index information."
cannot_fallback "Repository lacks necessary blobs to fall back on 3-way merge."
echo Using index info to reconstruct a base tree...
if GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \

View file

@ -318,6 +318,10 @@ esac
case "$all,$also" in
t,)
if test ! -f "$THIS_INDEX"
then
die 'nothing to commit (use "git add file1 file2" to include for commit)'
fi
save_index &&
(
cd_to_toplevel &&

View file

@ -1,6 +1,8 @@
#ifndef GIT_COMPAT_UTIL_H
#define GIT_COMPAT_UTIL_H
#define _FILE_OFFSET_BITS 64
#ifndef FLEX_ARRAY
#if defined(__GNUC__) && (__GNUC__ < 3)
#define FLEX_ARRAY 0
@ -139,6 +141,11 @@ extern char *gitstrcasestr(const char *haystack, const char *needle);
extern size_t gitstrlcpy(char *, const char *, size_t);
#endif
#ifdef NO_STRTOUMAX
#define strtoumax gitstrtoumax
extern uintmax_t gitstrtoumax(const char *, char **, int);
#endif
extern void release_pack_memory(size_t);
static inline char* xstrdup(const char *str)
@ -274,4 +281,9 @@ static inline int sane_case(int x, int high)
return x;
}
static inline int prefixcmp(const char *str, const char *prefix)
{
return strncmp(str, prefix, strlen(prefix));
}
#endif

View file

@ -15,14 +15,21 @@
die "GIT_DIR is not defined or is unreadable";
}
our ($opt_h, $opt_P, $opt_p, $opt_v, $opt_c, $opt_f, $opt_a, $opt_m );
our ($opt_h, $opt_P, $opt_p, $opt_v, $opt_c, $opt_f, $opt_a, $opt_m, $opt_d);
getopts('hPpvcfam:');
getopts('hPpvcfam:d:');
$opt_h && usage();
die "Need at least one commit identifier!" unless @ARGV;
my @cvs;
if ($opt_d) {
@cvs = ('cvs', '-d', $opt_d);
} else {
@cvs = ('cvs');
}
# setup a tempdir
our ($tmpdir, $tmpdirname) = tempdir('git-cvsapplycommit-XXXXXX',
TMPDIR => 1,
@ -160,7 +167,7 @@
my $p = $1;
next if (grep { $_ eq $p } @dirs);
}
my @status = grep(m/^File/, safe_pipe_capture('cvs', '-q', 'status' ,$f));
my @status = grep(m/^File/, safe_pipe_capture(@cvs, '-q', 'status' ,$f));
if (@status > 1) { warn 'Strange! cvs status returned more than one line?'};
if (-d dirname $f and $status[0] !~ m/Status: Unknown$/
and $status[0] !~ m/^File: no file /) {
@ -173,7 +180,7 @@
foreach my $f (@files) {
next if grep { $_ eq $f } @afiles;
# TODO:we need to handle removed in cvs
my @status = grep(m/^File/, safe_pipe_capture('cvs', '-q', 'status' ,$f));
my @status = grep(m/^File/, safe_pipe_capture(@cvs, '-q', 'status' ,$f));
if (@status > 1) { warn 'Strange! cvs status returned more than one line?'};
unless ($status[0] =~ m/Status: Up-to-date$/) {
$dirty = 1;
@ -194,7 +201,7 @@
print "Patch applied successfully. Adding new files and directories to CVS\n";
my $dirtypatch = 0;
foreach my $d (@dirs) {
if (system('cvs','add',$d)) {
if (system(@cvs,'add',$d)) {
$dirtypatch = 1;
warn "Failed to cvs add directory $d -- you may need to do it manually";
}
@ -202,9 +209,9 @@
foreach my $f (@afiles) {
if (grep { $_ eq $f } @bfiles) {
system('cvs', 'add','-kb',$f);
system(@cvs, 'add','-kb',$f);
} else {
system('cvs', 'add', $f);
system(@cvs, 'add', $f);
}
if ($?) {
$dirtypatch = 1;
@ -213,7 +220,7 @@
}
foreach my $f (@dfiles) {
system('cvs', 'rm', '-f', $f);
system(@cvs, 'rm', '-f', $f);
if ($?) {
$dirtypatch = 1;
warn "Failed to cvs rm -f $f -- you may need to do it manually";
@ -223,7 +230,7 @@
print "Commit to CVS\n";
print "Patch title (first comment line): $title\n";
my @commitfiles = map { unless (m/\s/) { '\''.$_.'\''; } else { $_; }; } (@files);
my $cmd = "cvs commit -F .msg @commitfiles";
my $cmd = join(' ', @cvs)." commit -F .msg @commitfiles";
if ($dirtypatch) {
print "NOTE: One or more hunks failed to apply cleanly.\n";
@ -236,7 +243,7 @@
if ($opt_c) {
print "Autocommit\n $cmd\n";
print safe_pipe_capture('cvs', 'commit', '-F', '.msg', @files);
print safe_pipe_capture(@cvs, 'commit', '-F', '.msg', @files);
if ($?) {
die "Exiting: The commit did not succeed";
}

View file

@ -1171,6 +1171,21 @@ sub req_ci
exit;
}
# Check that this is allowed, just as we would with a receive-pack
my @cmd = ( $ENV{GIT_DIR}.'hooks/update', "refs/heads/$state->{module}",
$parenthash, $commithash );
if( -x $cmd[0] ) {
unless( system( @cmd ) == 0 )
{
$log->warn("Commit failed (update hook declined to update ref)");
print "error 1 Commit failed (update hook declined)\n";
close LOCKFILE;
unlink($lockfile);
chdir "/";
exit;
}
}
print LOCKFILE $commithash;
$updater->update();

View file

@ -243,6 +243,15 @@ then
orig_head=$(git-rev-parse --verify HEAD 2>/dev/null)
fi
# Allow --notags from remote.$1.tagopt
case "$tags$no_tags" in
'')
case "$(git-config --get "remote.$1.tagopt")" in
--no-tags)
no_tags=t ;;
esac
esac
# If --tags (and later --heads or --all) is specified, then we are
# not talking about defaults stored in Pull: line of remotes or
# branches file, and just fetch those and refspecs explicitly given.

1
git-gui/.gitignore vendored
View file

@ -1,3 +1,4 @@
CREDITS-FILE
GIT-VERSION-FILE
git-citool
git-gui

71
git-gui/CREDITS-GEN Executable file
View file

@ -0,0 +1,71 @@
#!/bin/sh
CF=CREDITS-FILE
tip=
tree_search ()
{
head=$1
tree=$2
for p in $(git rev-list --parents --max-count=1 $head 2>/dev/null)
do
test $tree = $(git rev-parse $p^{tree} 2>/dev/null) &&
vn=$(git describe --abbrev=4 $p 2>/dev/null) &&
case "$vn" in
gitgui-[0-9]*) echo $p; break;;
esac
done
}
generate_credits ()
{
tip=$1 &&
rm -f "$2" &&
git shortlog -n -s $tip | sed 's/: .*$//' >"$2" || exit
}
# Always use the tarball credits file if found, just
# in case we are somehow contained in a larger git
# repository that doesn't actually track our state.
# (At least one package manager is doing this.)
#
# We may be a subproject, so try looking for the merge
# commit that supplied this directory content if we are
# not at the toplevel. We probably will always be the
# second parent in the commit, but we shouldn't rely on
# that fact.
#
credits_tmp=/var/tmp/gitgui-credits-$$
trap 'rm -f "$credits_tmp"' 0
orig="$credits_tmp"
if test -f credits
then
orig=credits
elif prefix="$(git rev-parse --show-prefix 2>/dev/null)" &&
test -n "$prefix" &&
head=$(git rev-list --max-count=1 HEAD -- . 2>/dev/null) &&
tree=$(git rev-parse --verify "HEAD:$prefix" 2>/dev/null) &&
tip=$(tree_search $head $tree) &&
test -n "$tip"
then
generate_credits $tip "$orig" || exit
elif tip="$(git rev-parse --verify HEAD 2>/dev/null)" &&
test -n "$tip"
then
generate_credits $tip "$orig" || exit
else
echo "error: Cannot locate authorship information." >&2
exit 1
fi
if test -f "$orig" && cmp -s "$orig" "$CF"
then
: noop
else
rm -f "$CF" &&
cat "$orig" >"$CF"
fi

View file

@ -20,6 +20,11 @@ tree_search ()
done
}
# Always use the tarball version file if found, just
# in case we are somehow contained in a larger git
# repository that doesn't actually track our state.
# (At least one package manager is doing this.)
#
# We may be a subproject, so try looking for the merge
# commit that supplied this directory content if we are
# not at the toplevel. We probably will always be the
@ -27,10 +32,13 @@ tree_search ()
# that fact.
#
# If we are at the toplevel or the merge assumption fails
# try looking for a gitgui-* tag, or fallback onto the
# distributed version file.
# try looking for a gitgui-* tag.
if prefix="$(git rev-parse --show-prefix 2>/dev/null)"
if test -f version &&
VN=$(cat version)
then
: happy
elif prefix="$(git rev-parse --show-prefix 2>/dev/null)"
test -n "$prefix" &&
head=$(git rev-list --max-count=1 HEAD -- . 2>/dev/null) &&
tree=$(git rev-parse --verify "HEAD:$prefix" 2>/dev/null) &&
@ -48,9 +56,6 @@ elif VN=$(git describe --abbrev=4 HEAD 2>/dev/null) &&
esac
then
VN=$(echo "$VN" | sed -e 's/^gitgui-//;s/-/./g');
elif test -f version
then
VN=$(cat version) || VN="$DEF_VER"
else
VN="$DEF_VER"
fi

View file

@ -4,9 +4,8 @@ GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
@$(SHELL_PATH) ./GIT-VERSION-GEN
-include GIT-VERSION-FILE
SCRIPT_SH = git-gui.sh
GITGUI_BUILT_INS = git-citool
ALL_PROGRAMS = $(GITGUI_BUILT_INS) $(patsubst %.sh,%,$(SCRIPT_SH))
ALL_PROGRAMS = git-gui $(GITGUI_BUILT_INS)
ifndef SHELL_PATH
SHELL_PATH = /bin/sh
@ -24,20 +23,24 @@ DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
gitexecdir_SQ = $(subst ','\'',$(gitexecdir))
SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
git-gui: git-gui.sh GIT-VERSION-FILE CREDITS-FILE
rm -f $@ $@+
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
sed -n \
-e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
-e 's/@@GITGUI_VERSION@@/$(GITGUI_VERSION)/g' \
-e '1,/^set gitgui_credits /p' \
$@.sh >$@+
cat CREDITS-FILE >>$@+
sed -e '1,/^set gitgui_credits /d' $@.sh >>$@+
chmod +x $@+
mv $@+ $@
CREDITS-FILE: CREDITS-GEN .FORCE-CREDITS-FILE
$(SHELL_PATH) ./CREDITS-GEN
$(GITGUI_BUILT_INS): git-gui
rm -f $@ && ln git-gui $@
# These can record GITGUI_VERSION
$(patsubst %.sh,%,$(SCRIPT_SH)): GIT-VERSION-FILE
all:: $(ALL_PROGRAMS)
install: all
@ -45,12 +48,14 @@ install: all
$(INSTALL) git-gui '$(DESTDIR_SQ)$(gitexecdir_SQ)'
$(foreach p,$(GITGUI_BUILT_INS), rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;)
dist-version:
dist-version: CREDITS-FILE
@mkdir -p $(TARDIR)
@echo $(GITGUI_VERSION) > $(TARDIR)/version
@cat CREDITS-FILE > $(TARDIR)/credits
clean::
rm -f $(ALL_PROGRAMS) GIT-VERSION-FILE
rm -f $(ALL_PROGRAMS) GIT-VERSION-FILE CREDITS-FILE
.PHONY: all install dist-version clean
.PHONY: .FORCE-GIT-VERSION-FILE
.PHONY: .FORCE-CREDITS-FILE

View file

@ -1,44 +0,0 @@
Items outstanding:
* Add file to .gitignore or info/excludes.
* Populate the pull menu with local branches.
* Make use of the new default merge data stored in repo-config.
* Checkout a different local branch.
* Push any local branch to a remote branch.
* Merge any local branches through a real merge UI.
* Allow user to define keyboard shortcuts for frequently used fetch
or merge operations. Or maybe just define a keyboard shortcut
for default fetch/default merge of current branch is enough;
but I do know a few users who merge a couple of common branches
also into the same branch so one default isn't quite enough.
* Better organize fetch/push/pull console windows.
* Clone UI (to download a new repository).
* Remotes editor (for .git/config format only).
* Show a shortlog of the last couple of commits in the main window,
to give the user warm fuzzy feelings that we have their data
saved. Actually this may be the set of commits not yet in
the upstream (aka default merge branch remote repository).
* GUI configuration editor for options listed in
git.git/Documentation/config.txt. Ideally this would
parse that file and generate the options dialog from
the documentation itself, and include the help text
from the documentation as part of the UI somehow.
Known bugs:
* git-gui sometimes just closes on Windows with no error message.
I'm not sure what the problem is here. I suspect the wish
process is just terminating due to a segfault or something,
as the do_quit proc in git-gui doesn't run. It often seems to
occur while writing a commit message in the buffer. Odd.

View file

@ -4,7 +4,7 @@ exec wish "$0" -- "$@"
set appvers {@@GITGUI_VERSION@@}
set copyright {
Copyright © 2006, 2007 Shawn Pearce, Paul Mackerras.
Copyright © 2006, 2007 Shawn Pearce, et. al.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,6 +19,9 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA}
set gitgui_credits {
Paul Mackerras
}
######################################################################
##
@ -46,7 +49,7 @@ proc gitdir {args} {
proc gitexec {args} {
global _gitexec
if {$_gitexec eq {}} {
if {[catch {set _gitexec [exec git --exec-path]} err]} {
if {[catch {set _gitexec [git --exec-path]} err]} {
error "Git not installed?\n\n$err"
}
}
@ -202,14 +205,14 @@ proc save_config {} {
set value $global_config_new($name)
if {$value ne $global_config($name)} {
if {$value eq $default_config($name)} {
catch {exec git config --global --unset $name}
catch {git config --global --unset $name}
} else {
regsub -all "\[{}\]" $value {"} value
exec git config --global $name $value
git config --global $name $value
}
set global_config($name) $value
if {$value eq $repo_config($name)} {
catch {exec git config --unset $name}
catch {git config --unset $name}
set repo_config($name) $value
}
}
@ -219,16 +222,24 @@ proc save_config {} {
set value $repo_config_new($name)
if {$value ne $repo_config($name)} {
if {$value eq $global_config($name)} {
catch {exec git config --unset $name}
catch {git config --unset $name}
} else {
regsub -all "\[{}\]" $value {"} value
exec git config $name $value
git config $name $value
}
set repo_config($name) $value
}
}
}
######################################################################
##
## handy utils
proc git {args} {
return [eval exec git $args]
}
proc error_popup {msg} {
set title [appname]
if {[reponame] ne {}} {
@ -287,12 +298,44 @@ proc ask_popup {msg} {
-message $msg]
}
######################################################################
##
## version check
set req_maj 1
set req_min 5
if {[catch {set v [git --version]} err]} {
catch {wm withdraw .}
error_popup "Cannot determine Git version:
$err
[appname] requires Git $req_maj.$req_min or later."
exit 1
}
if {[regexp {^git version (\d+)\.(\d+)} $v _junk act_maj act_min]} {
if {$act_maj < $req_maj
|| ($act_maj == $req_maj && $act_min < $req_min)} {
catch {wm withdraw .}
error_popup "[appname] requires Git $req_maj.$req_min or later.
You are using $v."
exit 1
}
} else {
catch {wm withdraw .}
error_popup "Cannot parse Git version string:\n\n$v"
exit 1
}
unset -nocomplain v _junk act_maj act_min req_maj req_min
######################################################################
##
## repository setup
if { [catch {set _gitdir $env(GIT_DIR)}]
&& [catch {set _gitdir [exec git rev-parse --git-dir]} err]} {
&& [catch {set _gitdir [git rev-parse --git-dir]} err]} {
catch {wm withdraw .}
error_popup "Cannot find the git directory:\n\n$err"
exit 1
@ -319,6 +362,24 @@ set _reponame [lindex [file split \
[file normalize [file dirname $_gitdir]]] \
end]
######################################################################
##
## global init
set current_diff_path {}
set current_diff_side {}
set diff_actions [list]
set ui_status_value {Initializing...}
set HEAD {}
set PARENT {}
set MERGE_HEAD [list]
set commit_type {}
set empty_tree {}
set current_branch {}
set current_diff_path {}
set selected_commit_type new
######################################################################
##
## task management
@ -365,7 +426,7 @@ proc repository_state {ctvar hdvar mhvar} {
set mh [list]
if {[catch {set current_branch [exec git symbolic-ref HEAD]}]} {
if {[catch {set current_branch [git symbolic-ref HEAD]}]} {
set current_branch {}
} else {
regsub ^refs/((heads|tags|remotes)/)? \
@ -374,7 +435,7 @@ proc repository_state {ctvar hdvar mhvar} {
current_branch
}
if {[catch {set hd [exec git rev-parse --verify HEAD]}]} {
if {[catch {set hd [git rev-parse --verify HEAD]}]} {
set hd {}
set ct initial
return
@ -402,7 +463,7 @@ proc PARENT {} {
return $p
}
if {$empty_tree eq {}} {
set empty_tree [exec git mktree << {}]
set empty_tree [git mktree << {}]
}
return $empty_tree
}
@ -642,8 +703,9 @@ proc reshow_diff {} {
global current_diff_path current_diff_side
set p $current_diff_path
if {$p eq {}
|| $current_diff_side eq {}
if {$p eq {}} {
# No diff is being shown.
} elseif {$current_diff_side eq {}
|| [catch {set s $file_states($p)}]
|| [lsearch -sorted -exact $file_lists($current_diff_side) $p] == -1} {
clear_diff
@ -1042,7 +1104,7 @@ proc committer_ident {} {
global GIT_COMMITTER_IDENT
if {$GIT_COMMITTER_IDENT eq {}} {
if {[catch {set me [exec git var GIT_COMMITTER_IDENT]} err]} {
if {[catch {set me [git var GIT_COMMITTER_IDENT]} err]} {
error_popup "Unable to obtain your identity:\n\n$err"
return {}
}
@ -1256,14 +1318,6 @@ proc commit_committree {fd_wt curHEAD msg} {
return
}
# -- Make sure our current branch exists.
#
if {$commit_type eq {initial}} {
lappend all_heads $current_branch
set all_heads [lsort -unique $all_heads]
populate_branch_menu
}
# -- Cleanup after ourselves.
#
catch {file delete $msg_p}
@ -1275,7 +1329,7 @@ proc commit_committree {fd_wt curHEAD msg} {
# -- Let rerere do its thing.
#
if {[file isdirectory [gitdir rr-cache]]} {
catch {exec git rerere}
catch {git rerere}
}
# -- Run the post-commit hook.
@ -1299,6 +1353,14 @@ proc commit_committree {fd_wt curHEAD msg} {
if {[is_enabled singlecommit]} do_quit
# -- Make sure our current branch exists.
#
if {$commit_type eq {initial}} {
lappend all_heads $current_branch
set all_heads [lsort -unique $all_heads]
populate_branch_menu
}
# -- Update in memory status
#
set selected_commit_type new
@ -1876,11 +1938,24 @@ proc all_tracking_branches {} {
return [lsort -unique $all_trackings]
}
proc load_all_tags {} {
set all_tags [list]
set fd [open "| git for-each-ref --format=%(refname) refs/tags" r]
while {[gets $fd line] > 0} {
if {![regsub ^refs/tags/ $line {} name]} continue
lappend all_tags $name
}
close $fd
return [lsort $all_tags]
}
proc do_create_branch_action {w} {
global all_heads null_sha1 repo_config
global create_branch_checkout create_branch_revtype
global create_branch_head create_branch_trackinghead
global create_branch_name create_branch_revexp
global create_branch_tag
set newbranch $create_branch_name
if {$newbranch eq {}
@ -1894,7 +1969,7 @@ proc do_create_branch_action {w} {
focus $w.desc.name_t
return
}
if {![catch {exec git show-ref --verify -- "refs/heads/$newbranch"}]} {
if {![catch {git show-ref --verify -- "refs/heads/$newbranch"}]} {
tk_messageBox \
-icon error \
-type ok \
@ -1904,7 +1979,7 @@ proc do_create_branch_action {w} {
focus $w.desc.name_t
return
}
if {[catch {exec git check-ref-format "heads/$newbranch"}]} {
if {[catch {git check-ref-format "heads/$newbranch"}]} {
tk_messageBox \
-icon error \
-type ok \
@ -1919,9 +1994,10 @@ proc do_create_branch_action {w} {
switch -- $create_branch_revtype {
head {set rev $create_branch_head}
tracking {set rev $create_branch_trackinghead}
tag {set rev $create_branch_tag}
expression {set rev $create_branch_revexp}
}
if {[catch {set cmt [exec git rev-parse --verify "${rev}^0"]}]} {
if {[catch {set cmt [git rev-parse --verify "${rev}^0"]}]} {
tk_messageBox \
-icon error \
-type ok \
@ -1964,6 +2040,8 @@ trace add variable create_branch_head write \
[list radio_selector create_branch_revtype head]
trace add variable create_branch_trackinghead write \
[list radio_selector create_branch_revtype tracking]
trace add variable create_branch_tag write \
[list radio_selector create_branch_revtype tag]
trace add variable delete_branch_head write \
[list radio_selector delete_branch_checktype head]
@ -1975,6 +2053,7 @@ proc do_create_branch {} {
global create_branch_checkout create_branch_revtype
global create_branch_head create_branch_trackinghead
global create_branch_name create_branch_revexp
global create_branch_tag
set w .branch_editor
toplevel $w
@ -2038,6 +2117,19 @@ proc do_create_branch {} {
$all_trackings
grid $w.from.tracking_r $w.from.tracking_m -sticky w
}
set all_tags [load_all_tags]
if {$all_tags ne {}} {
set create_branch_tag [lindex $all_tags 0]
radiobutton $w.from.tag_r \
-text {Tag:} \
-value tag \
-variable create_branch_revtype \
-font font_ui
eval tk_optionMenu $w.from.tag_m \
create_branch_tag \
$all_tags
grid $w.from.tag_r $w.from.tag_m -sticky w
}
radiobutton $w.from.exp_r \
-text {Revision Expression:} \
-value expression \
@ -2100,7 +2192,7 @@ proc do_delete_branch_action {w} {
}
if {$check_rev eq {:none}} {
set check_cmt {}
} elseif {[catch {set check_cmt [exec git rev-parse --verify "${check_rev}^0"]}]} {
} elseif {[catch {set check_cmt [git rev-parse --verify "${check_rev}^0"]}]} {
tk_messageBox \
-icon error \
-type ok \
@ -2114,10 +2206,10 @@ proc do_delete_branch_action {w} {
set not_merged [list]
foreach i [$w.list.l curselection] {
set b [$w.list.l get $i]
if {[catch {set o [exec git rev-parse --verify $b]}]} continue
if {[catch {set o [git rev-parse --verify $b]}]} continue
if {$check_cmt ne {}} {
if {$b eq $check_rev} continue
if {[catch {set m [exec git merge-base $o $check_cmt]}]} continue
if {[catch {set m [git merge-base $o $check_cmt]}]} continue
if {$o ne $m} {
lappend not_merged $b
continue
@ -2155,7 +2247,7 @@ Delete the selected branches?}
foreach i $to_delete {
set b [lindex $i 0]
set o [lindex $i 1]
if {[catch {exec git update-ref -d "refs/heads/$b" $o} err]} {
if {[catch {git update-ref -d "refs/heads/$b" $o} err]} {
append failed " - $b: $err\n"
} else {
set x [lsearch -sorted -exact $all_heads $b]
@ -2366,7 +2458,7 @@ Staying on branch '$current_branch'."
# here, it Just Works(tm). If it doesn't we are in some really ugly
# state that is difficult to recover from within git-gui.
#
if {[catch {exec git symbolic-ref HEAD "refs/heads/$new_branch"} err]} {
if {[catch {git symbolic-ref HEAD "refs/heads/$new_branch"} err]} {
error_popup "Failed to set current branch.
This working directory is only partially switched.
@ -2876,14 +2968,16 @@ proc do_local_merge {} {
pack $w.source -fill both -expand 1 -pady 5 -padx 5
set cmd [list git for-each-ref]
lappend cmd {--format=%(objectname) %(refname)}
lappend cmd {--format=%(objectname) %(*objectname) %(refname)}
lappend cmd refs/heads
lappend cmd refs/remotes
lappend cmd refs/tags
set fr_fd [open "| $cmd" r]
fconfigure $fr_fd -translation binary
while {[gets $fr_fd line] > 0} {
set line [split $line { }]
set sha1([lindex $line 0]) [lindex $line 1]
set sha1([lindex $line 0]) [lindex $line 2]
set sha1([lindex $line 1]) [lindex $line 2]
}
close $fr_fd
@ -2891,7 +2985,7 @@ proc do_local_merge {} {
set fr_fd [open "| git rev-list --all --not HEAD"]
while {[gets $fr_fd line] > 0} {
if {[catch {set ref $sha1($line)}]} continue
regsub ^refs/(heads|remotes)/ $ref {} ref
regsub ^refs/(heads|remotes|tags)/ $ref {} ref
lappend to_show $ref
}
close $fr_fd
@ -2972,7 +3066,14 @@ proc new_browser {commit} {
global next_browser_id cursor_ptr M1B
global browser_commit browser_status browser_stack browser_path browser_busy
set w .browser[incr next_browser_id]
if {[winfo ismapped .]} {
set w .browser[incr next_browser_id]
set tl $w
toplevel $w
} else {
set w {}
set tl .
}
set w_list $w.list.l
set browser_commit($w_list) $commit
set browser_status($w_list) {Starting...}
@ -2980,7 +3081,6 @@ proc new_browser {commit} {
set browser_path($w_list) $browser_commit($w_list):
set browser_busy($w_list) 1
toplevel $w
label $w.path -textvariable browser_path($w_list) \
-anchor w \
-justify left \
@ -3030,8 +3130,8 @@ proc new_browser {commit} {
bind $w_list <Left> break
bind $w_list <Right> break
bind $w <Visibility> "focus $w"
bind $w <Destroy> "
bind $tl <Visibility> "focus $w"
bind $tl <Destroy> "
array unset browser_buffer $w_list
array unset browser_files $w_list
array unset browser_status $w_list
@ -3040,7 +3140,7 @@ proc new_browser {commit} {
array unset browser_commit $w_list
array unset browser_busy $w_list
"
wm title $w "[appname] ([reponame]): File Browser"
wm title $tl "[appname] ([reponame]): File Browser"
ls_tree $w_list $browser_commit($w_list) {}
}
@ -4161,7 +4261,7 @@ proc do_quit {} {
set rc_geometry {}
}
if {$cfg_geometry ne $rc_geometry} {
catch {exec git config gui.geometry $cfg_geometry}
catch {git config gui.geometry $cfg_geometry}
}
}
@ -4380,6 +4480,61 @@ proc do_commit {} {
commit_tree
}
proc do_credits {} {
global gitgui_credits
set w .credits_dialog
toplevel $w
wm geometry $w "+[winfo rootx .]+[winfo rooty .]"
label $w.header -text {git-gui Contributors} -font font_uibold
pack $w.header -side top -fill x
frame $w.buttons
button $w.buttons.close -text {Close} \
-font font_ui \
-command [list destroy $w]
pack $w.buttons.close -side right
pack $w.buttons -side bottom -fill x -pady 10 -padx 10
frame $w.credits
text $w.credits.t \
-background [$w.header cget -background] \
-yscrollcommand [list $w.credits.sby set] \
-width 20 \
-height 10 \
-wrap none \
-borderwidth 1 \
-relief solid \
-padx 5 -pady 5 \
-font font_ui
scrollbar $w.credits.sby -command [list $w.credits.t yview]
pack $w.credits.sby -side right -fill y
pack $w.credits.t -fill both -expand 1
pack $w.credits -side top -fill both -expand 1 -padx 5 -pady 5
label $w.desc \
-text "All portions are copyrighted by their respective authors
and are distributed under the GNU General Public License." \
-padx 5 -pady 5 \
-justify left \
-anchor w \
-borderwidth 1 \
-relief solid \
-font font_ui
pack $w.desc -side top -fill x -padx 5 -pady 5
$w.credits.t insert end "[string trim $gitgui_credits]\n"
$w.credits.t conf -state disabled
$w.credits.t see 1.0
bind $w <Visibility> "grab $w; focus $w"
bind $w <Key-Escape> [list destroy $w]
wm title $w [$w.header cget -text]
tkwait window $w
}
proc do_about {} {
global appvers copyright
global tcl_patchLevel tk_patchLevel
@ -4396,11 +4551,15 @@ proc do_about {} {
button $w.buttons.close -text {Close} \
-font font_ui \
-command [list destroy $w]
button $w.buttons.credits -text {Contributors} \
-font font_ui \
-command do_credits
pack $w.buttons.credits -side left
pack $w.buttons.close -side right
pack $w.buttons -side bottom -fill x -pady 10 -padx 10
label $w.desc \
-text "[appname] - a commit creation tool for Git.
-text "git-gui - a graphical user interface for Git.
$copyright" \
-padx 5 -pady 5 \
-justify left \
@ -4411,8 +4570,8 @@ $copyright" \
pack $w.desc -side top -fill x -padx 5 -pady 5
set v {}
append v "[appname] version $appvers\n"
append v "[exec git version]\n"
append v "git-gui version $appvers\n"
append v "[git version]\n"
append v "\n"
if {$tcl_patchLevel eq $tk_patchLevel} {
append v "Tcl/Tk version $tcl_patchLevel"
@ -4471,7 +4630,7 @@ proc do_options {} {
toplevel $w
wm geometry $w "+[winfo rootx .]+[winfo rooty .]"
label $w.header -text "[appname] Options" \
label $w.header -text "Options" \
-font font_uibold
pack $w.header -side top -fill x
@ -4945,6 +5104,9 @@ enable_option branch
enable_option transport
switch -- $subcommand {
--version -
version -
browser -
blame {
disable_option multicommit
disable_option branch
@ -5177,7 +5339,7 @@ if {[is_MacOSX]} {
.mbar.apple add command -label "About [appname]" \
-command do_about \
-font font_ui
.mbar.apple add command -label "[appname] Options..." \
.mbar.apple add command -label "Options..." \
-command do_options \
-font font_ui
} else {
@ -5236,7 +5398,7 @@ set doc_path [file dirname [gitexec]]
set doc_path [file join $doc_path Documentation index.html]
if {[is_Cygwin]} {
set doc_path [exec cygpath --windows $doc_path]
set doc_path [exec cygpath --mixed $doc_path]
}
if {$browser eq {}} {
@ -5280,6 +5442,20 @@ bind all <$M1B-Key-W> {destroy [winfo toplevel %W]}
# -- Not a normal commit type invocation? Do that instead!
#
switch -- $subcommand {
--version -
version {
puts "git-gui version $appvers"
exit
}
browser {
if {[llength $argv] != 1} {
puts stderr "usage: $argv0 browser commit"
exit 1
}
set current_branch [lindex $argv 0]
new_browser $current_branch
return
}
blame {
if {[llength $argv] != 2} {
puts stderr "usage: $argv0 blame commit path"
@ -5302,7 +5478,7 @@ gui {
# fall through to setup UI for commits
}
default {
puts stderr "usage: $argv0 \[{blame|citool}\]"
puts stderr "usage: $argv0 \[{blame|browser|citool}\]"
exit 1
}
}
@ -5552,9 +5728,6 @@ bind_button3 $ui_comm "tk_popup $ctxm %X %Y"
# -- Diff Header
#
set current_diff_path {}
set current_diff_side {}
set diff_actions [list]
proc trace_current_diff_path {varname args} {
global current_diff_path diff_actions file_states
if {$current_diff_path eq {}} {
@ -5747,7 +5920,6 @@ unset ui_diff_applyhunk
# -- Status Bar
#
set ui_status_value {Initializing...}
label .status -textvariable ui_status_value \
-anchor w \
-justify left \
@ -5821,15 +5993,6 @@ unset i
set file_lists($ui_index) [list]
set file_lists($ui_workdir) [list]
set HEAD {}
set PARENT {}
set MERGE_HEAD [list]
set commit_type {}
set empty_tree {}
set current_branch {}
set current_diff_path {}
set selected_commit_type new
wm title . "[appname] ([file normalize [file dirname [gitdir]]])"
focus -force $ui_comm
@ -5904,7 +6067,7 @@ if {[is_enabled transport]} {
if {[is_enabled multicommit]} {
set object_limit 2000
if {[is_Windows]} {set object_limit 200}
regexp {^([0-9]+) objects,} [exec git count-objects] _junk objects_current
regexp {^([0-9]+) objects,} [git count-objects] _junk objects_current
if {$objects_current >= $object_limit} {
if {[ask_popup \
"This repository currently has $objects_current loose objects.

View file

@ -67,7 +67,7 @@ sub list_remote {
$git->command(qw(config --get-regexp), '^remote\.');
};
for (@remotes) {
if (/^remote\.([^.]*)\.(\S*)\s+(.*)$/) {
if (/^remote\.(\S+?)\.([^.\s]+)\s+(.*)$/) {
add_remote_config(\%seen, $1, $2, $3);
}
}
@ -274,6 +274,31 @@ sub add_remote {
}
}
sub update_remote {
my ($name) = @_;
my $conf = $git->config("remotes." . $name);
if (defined($conf)) {
@remotes = split(' ', $conf);
} elsif ($name eq 'default') {
undef @remotes;
for (sort keys %$remote) {
my $do_fetch = $git->config_boolean("remote." . $_ .
".skipDefaultUpdate");
if (!defined($do_fetch) || $do_fetch ne "true") {
push @remotes, $_;
}
}
} else {
print STDERR "Remote group $name does not exists.\n";
exit(1);
}
for (@remotes) {
print "Updating $_\n";
$git->command('fetch', "$_");
}
}
sub add_usage {
print STDERR "Usage: git remote add [-f] [-t track]* [-m master] <name> <url>\n";
exit(1);
@ -303,6 +328,15 @@ sub add_usage {
show_remote($ARGV[$i], $ls_remote);
}
}
elsif ($ARGV[0] eq 'update') {
if (@ARGV <= 1) {
update_remote("default");
exit(1);
}
for ($i = 1; $i < @ARGV; $i++) {
update_remote($ARGV[$i]);
}
}
elsif ($ARGV[0] eq 'prune') {
my $ls_remote = 1;
my $i;
@ -360,5 +394,6 @@ sub add_usage {
print STDERR " git remote add <name> <url>\n";
print STDERR " git remote show <name>\n";
print STDERR " git remote prune <name>\n";
print STDERR " git remote update [group]\n";
exit(1);
}

File diff suppressed because it is too large Load diff

12
git.c
View file

@ -48,7 +48,7 @@ static int handle_options(const char*** argv, int* argc)
/*
* Check remaining flags.
*/
if (!strncmp(cmd, "--exec-path", 11)) {
if (!prefixcmp(cmd, "--exec-path")) {
cmd += 11;
if (*cmd == '=')
git_set_exec_path(cmd + 1);
@ -66,7 +66,7 @@ static int handle_options(const char*** argv, int* argc)
setenv(GIT_DIR_ENVIRONMENT, (*argv)[1], 1);
(*argv)++;
(*argc)--;
} else if (!strncmp(cmd, "--git-dir=", 10)) {
} else if (!prefixcmp(cmd, "--git-dir=")) {
setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1);
} else if (!strcmp(cmd, "--bare")) {
static char git_dir[PATH_MAX+1];
@ -88,7 +88,7 @@ static char *alias_string;
static int git_alias_config(const char *var, const char *value)
{
if (!strncmp(var, "alias.", 6) && !strcmp(var + 6, alias_command)) {
if (!prefixcmp(var, "alias.") && !strcmp(var + 6, alias_command)) {
alias_string = xstrdup(value);
}
return 0;
@ -247,7 +247,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
{ "fsck", cmd_fsck, RUN_SETUP },
{ "fsck-objects", cmd_fsck, RUN_SETUP },
{ "get-tar-commit-id", cmd_get_tar_commit_id },
{ "grep", cmd_grep, RUN_SETUP },
{ "grep", cmd_grep, RUN_SETUP | USE_PAGER },
{ "help", cmd_help },
{ "init", cmd_init_db },
{ "init-db", cmd_init_db },
@ -348,7 +348,7 @@ int main(int argc, const char **argv, char **envp)
* So we just directly call the internal command handler, and
* die if that one cannot handle it.
*/
if (!strncmp(cmd, "git-", 4)) {
if (!prefixcmp(cmd, "git-")) {
cmd += 4;
argv[0] = cmd;
handle_internal_command(argc, argv, envp);
@ -360,7 +360,7 @@ int main(int argc, const char **argv, char **envp)
argc--;
handle_options(&argv, &argc);
if (argc > 0) {
if (!strncmp(argv[0], "--", 2))
if (!prefixcmp(argv[0], "--"))
argv[0] += 2;
} else {
/* Default command: "help" */

4
help.c
View file

@ -130,7 +130,7 @@ static void list_commands(const char *exec_path, const char *pattern)
struct stat st;
int entlen;
if (strncmp(de->d_name, "git-", 4))
if (prefixcmp(de->d_name, "git-"))
continue;
strcpy(path+dirlen, de->d_name);
if (stat(path, &st) || /* stat, not lstat */
@ -179,7 +179,7 @@ static void show_man_page(const char *git_cmd)
{
const char *page;
if (!strncmp(git_cmd, "git", 3))
if (!prefixcmp(git_cmd, "git"))
page = git_cmd;
else {
int page_len = strlen(git_cmd) + 4;

View file

@ -717,8 +717,8 @@ static int fetch_indices(struct alt_base *repo)
case 'P':
i++;
if (i + 52 <= buffer.posn &&
!strncmp(data + i, " pack-", 6) &&
!strncmp(data + i + 46, ".pack\n", 6)) {
!prefixcmp(data + i, " pack-") &&
!prefixcmp(data + i + 46, ".pack\n")) {
get_sha1_hex(data + i + 6, sha1);
setup_index(repo, sha1);
i += 51;

View file

@ -1060,8 +1060,8 @@ static int fetch_indices(void)
case 'P':
i++;
if (i + 52 < buffer.posn &&
!strncmp(data + i, " pack-", 6) &&
!strncmp(data + i + 46, ".pack\n", 6)) {
!prefixcmp(data + i, " pack-") &&
!prefixcmp(data + i + 46, ".pack\n")) {
get_sha1_hex(data + i + 6, sha1);
setup_index(sha1);
i += 51;
@ -1206,11 +1206,11 @@ static void handle_new_lock_ctx(struct xml_ctx *ctx, int tag_closed)
lock->owner = xmalloc(strlen(ctx->cdata) + 1);
strcpy(lock->owner, ctx->cdata);
} else if (!strcmp(ctx->name, DAV_ACTIVELOCK_TIMEOUT)) {
if (!strncmp(ctx->cdata, "Second-", 7))
if (!prefixcmp(ctx->cdata, "Second-"))
lock->timeout =
strtol(ctx->cdata + 7, NULL, 10);
} else if (!strcmp(ctx->name, DAV_ACTIVELOCK_TOKEN)) {
if (!strncmp(ctx->cdata, "opaquelocktoken:", 16)) {
if (!prefixcmp(ctx->cdata, "opaquelocktoken:")) {
lock->token = xmalloc(strlen(ctx->cdata) - 15);
strcpy(lock->token, ctx->cdata + 16);
}
@ -2168,7 +2168,7 @@ static void fetch_symref(const char *path, char **symref, unsigned char *sha1)
return;
/* If it's a symref, set the refname; otherwise try for a sha1 */
if (!strncmp((char *)buffer.buffer, "ref: ", 5)) {
if (!prefixcmp((char *)buffer.buffer, "ref: ")) {
*symref = xmalloc(buffer.posn - 5);
strlcpy(*symref, (char *)buffer.buffer + 5, buffer.posn - 5);
} else {

View file

@ -1192,7 +1192,7 @@ count_messages( msg_data_t *msg )
char *p = msg->data;
while (1) {
if (!strncmp( "From ", p, 5 )) {
if (!prefixcmp(p, "From ")) {
count++;
p += 5;
}
@ -1216,7 +1216,7 @@ split_msg( msg_data_t *all_msgs, msg_data_t *msg, int *ofs )
data = &all_msgs->data[ *ofs ];
msg->len = all_msgs->len - *ofs;
if (msg->len < 5 || strncmp( data, "From ", 5 ))
if (msg->len < 5 || prefixcmp(data, "From "))
return 0;
p = strchr( data, '\n' );
@ -1267,12 +1267,12 @@ git_imap_config(const char *key, const char *val)
imap_folder = xstrdup( val );
} else if (!strcmp( "host", key )) {
{
if (!strncmp( "imap:", val, 5 ))
if (!prefixcmp(val, "imap:"))
val += 5;
if (!server.port)
server.port = 143;
}
if (!strncmp( "//", val, 2 ))
if (!prefixcmp(val, "//"))
val += 2;
server.host = xstrdup( val );
}

View file

@ -849,9 +849,9 @@ int main(int argc, char **argv)
fix_thin_pack = 1;
} else if (!strcmp(arg, "--keep")) {
keep_msg = "";
} else if (!strncmp(arg, "--keep=", 7)) {
} else if (!prefixcmp(arg, "--keep=")) {
keep_msg = arg + 7;
} else if (!strncmp(arg, "--pack_header=", 14)) {
} else if (!prefixcmp(arg, "--pack_header=")) {
struct pack_header *hdr;
char *c;

View file

@ -60,7 +60,7 @@ static int merge_entry(int pos, const char *path)
break;
found++;
strcpy(hexbuf[stage], sha1_to_hex(ce->sha1));
sprintf(ownbuf[stage], "%o", ntohl(ce->ce_mode) & (~S_IFMT));
sprintf(ownbuf[stage], "%o", ntohl(ce->ce_mode));
arguments[stage] = hexbuf[stage];
arguments[stage + 4] = ownbuf[stage];
} while (++pos < active_nr);

View file

@ -589,7 +589,7 @@ static void update_file_flags(const unsigned char *sha,
memcpy(lnk, buf, size);
lnk[size] = '\0';
mkdir_p(path, 0777);
unlink(lnk);
unlink(path);
symlink(lnk, path);
} else
die("do not know what to do with %06o %s '%s'",

View file

@ -35,11 +35,11 @@ int main(int argc, char **argv)
char *arg = argv[i];
if (*arg == '-') {
if (!strncmp("--upload-pack=", arg, 14)) {
if (!prefixcmp(arg, "--upload-pack=")) {
uploadpack = arg + 14;
continue;
}
if (!strncmp("--exec=", arg, 7)) {
if (!prefixcmp(arg, "--exec=")) {
uploadpack = arg + 7;
continue;
}

View file

@ -516,6 +516,36 @@ sub config {
}
=item config_boolean ( VARIABLE )
Retrieve the boolean configuration C<VARIABLE>.
Must be called on a repository instance.
This currently wraps command('config') so it is not so fast.
=cut
sub config_boolean {
my ($self, $var) = @_;
$self->repo_path()
or throw Error::Simple("not a repository");
try {
return $self->command_oneline('config', '--bool', '--get',
$var);
} catch Git::Error::Command with {
my $E = shift;
if ($E->value() == 1) {
# Key not found.
return undef;
} else {
throw $E;
}
};
}
=item ident ( TYPE | IDENTSTR )
=item ident_person ( TYPE | IDENTSTR | IDENTARRAY )

View file

@ -109,7 +109,7 @@ static int update(struct command *cmd)
struct ref_lock *lock;
cmd->error_string = NULL;
if (!strncmp(name, "refs/", 5) && check_ref_format(name + 5)) {
if (!prefixcmp(name, "refs/") && check_ref_format(name + 5)) {
cmd->error_string = "funny refname";
return error("refusing to create funny ref '%s' locally",
name);
@ -125,7 +125,7 @@ static int update(struct command *cmd)
}
if (deny_non_fast_forwards && !is_null_sha1(new_sha1) &&
!is_null_sha1(old_sha1) &&
!strncmp(name, "refs/heads/", 11)) {
!prefixcmp(name, "refs/heads/")) {
struct commit *old_commit, *new_commit;
struct commit_list *bases, *ent;

8
refs.c
View file

@ -828,8 +828,8 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)
goto rollback;
}
if (!strncmp(oldref, "refs/heads/", 11) &&
!strncmp(newref, "refs/heads/", 11)) {
if (!prefixcmp(oldref, "refs/heads/") &&
!prefixcmp(newref, "refs/heads/")) {
char oldsection[1024], newsection[1024];
snprintf(oldsection, 1024, "branch.%s", oldref + 11);
@ -894,8 +894,8 @@ static int log_ref_write(const char *ref_name, const unsigned char *old_sha1,
log_file = git_path("logs/%s", ref_name);
if (log_all_ref_updates &&
(!strncmp(ref_name, "refs/heads/", 11) ||
!strncmp(ref_name, "refs/remotes/", 13) ||
(!prefixcmp(ref_name, "refs/heads/") ||
!prefixcmp(ref_name, "refs/remotes/") ||
!strcmp(ref_name, "HEAD"))) {
if (safe_create_leading_directories(log_file) < 0)
return error("unable to create directory for %s",

View file

@ -813,11 +813,11 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
const char *arg = argv[i];
if (*arg == '-') {
int opts;
if (!strncmp(arg, "--max-count=", 12)) {
if (!prefixcmp(arg, "--max-count=")) {
revs->max_count = atoi(arg + 12);
continue;
}
if (!strncmp(arg, "--skip=", 7)) {
if (!prefixcmp(arg, "--skip=")) {
revs->skip_count = atoi(arg + 7);
continue;
}
@ -832,31 +832,31 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
revs->max_count = atoi(argv[++i]);
continue;
}
if (!strncmp(arg,"-n",2)) {
if (!prefixcmp(arg, "-n")) {
revs->max_count = atoi(arg + 2);
continue;
}
if (!strncmp(arg, "--max-age=", 10)) {
if (!prefixcmp(arg, "--max-age=")) {
revs->max_age = atoi(arg + 10);
continue;
}
if (!strncmp(arg, "--since=", 8)) {
if (!prefixcmp(arg, "--since=")) {
revs->max_age = approxidate(arg + 8);
continue;
}
if (!strncmp(arg, "--after=", 8)) {
if (!prefixcmp(arg, "--after=")) {
revs->max_age = approxidate(arg + 8);
continue;
}
if (!strncmp(arg, "--min-age=", 10)) {
if (!prefixcmp(arg, "--min-age=")) {
revs->min_age = atoi(arg + 10);
continue;
}
if (!strncmp(arg, "--before=", 9)) {
if (!prefixcmp(arg, "--before=")) {
revs->min_age = approxidate(arg + 9);
continue;
}
if (!strncmp(arg, "--until=", 8)) {
if (!prefixcmp(arg, "--until=")) {
revs->min_age = approxidate(arg + 8);
continue;
}
@ -944,7 +944,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
revs->num_ignore_packed = 0;
continue;
}
if (!strncmp(arg, "--unpacked=", 11)) {
if (!prefixcmp(arg, "--unpacked=")) {
revs->unpacked = 1;
add_ignore_packed(revs, arg+11);
continue;
@ -980,7 +980,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
revs->verbose_header = 1;
continue;
}
if (!strncmp(arg, "--pretty", 8)) {
if (!prefixcmp(arg, "--pretty")) {
revs->verbose_header = 1;
revs->commit_format = get_commit_format(arg+8);
continue;
@ -1005,7 +1005,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
revs->abbrev = DEFAULT_ABBREV;
continue;
}
if (!strncmp(arg, "--abbrev=", 9)) {
if (!prefixcmp(arg, "--abbrev=")) {
revs->abbrev = strtoul(arg + 9, NULL, 10);
if (revs->abbrev < MINIMUM_ABBREV)
revs->abbrev = MINIMUM_ABBREV;
@ -1034,15 +1034,15 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
/*
* Grepping the commit log
*/
if (!strncmp(arg, "--author=", 9)) {
if (!prefixcmp(arg, "--author=")) {
add_header_grep(revs, "author", arg+9);
continue;
}
if (!strncmp(arg, "--committer=", 12)) {
if (!prefixcmp(arg, "--committer=")) {
add_header_grep(revs, "committer", arg+12);
continue;
}
if (!strncmp(arg, "--grep=", 7)) {
if (!prefixcmp(arg, "--grep=")) {
add_message_grep(revs, arg+7);
continue;
}
@ -1050,7 +1050,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
all_match = 1;
continue;
}
if (!strncmp(arg, "--encoding=", 11)) {
if (!prefixcmp(arg, "--encoding=")) {
arg += 11;
if (strcmp(arg, "none"))
git_log_output_encoding = strdup(arg);
@ -1233,9 +1233,15 @@ static struct commit *get_revision_1(struct rev_info *revs)
*/
if (!revs->limited) {
if (revs->max_age != -1 &&
(commit->date < revs->max_age))
continue;
add_parents_to_list(revs, commit, &revs->commits);
(commit->date < revs->max_age)) {
if (revs->boundary)
commit->object.flags |=
BOUNDARY_SHOW | BOUNDARY;
else
continue;
} else
add_parents_to_list(revs, commit,
&revs->commits);
}
if (commit->object.flags & SHOWN)
continue;
@ -1336,7 +1342,18 @@ struct commit *get_revision(struct rev_info *revs)
case -1:
break;
case 0:
return NULL;
if (revs->boundary) {
struct commit_list *list = revs->commits;
while (list) {
list->item->object.flags |=
BOUNDARY_SHOW | BOUNDARY;
list = list->next;
}
/* all remaining commits are boundary commits */
revs->max_count = -1;
revs->limited = 1;
} else
return NULL;
default:
revs->max_count--;
}

View file

@ -379,11 +379,11 @@ int main(int argc, char **argv)
char *arg = *argv;
if (*arg == '-') {
if (!strncmp(arg, "--receive-pack=", 15)) {
if (!prefixcmp(arg, "--receive-pack=")) {
receivepack = arg + 15;
continue;
}
if (!strncmp(arg, "--exec=", 7)) {
if (!prefixcmp(arg, "--exec=")) {
receivepack = arg + 7;
continue;
}

View file

@ -251,7 +251,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
offset++;
cwd[len++] = '/';
cwd[len] = 0;
inside_git_dir = !strncmp(cwd + offset, ".git/", 5);
inside_git_dir = !prefixcmp(cwd + offset, ".git/");
return cwd + offset;
}

View file

@ -2082,7 +2082,7 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, con
{
unsigned long size = st->st_size;
void *buf;
int ret;
int ret, re_allocated = 0;
buf = "";
if (size)
@ -2091,11 +2091,30 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, con
if (!type)
type = blob_type;
/* FIXME: CRLF -> LF conversion here for blobs! We'll need the path! */
/*
* Convert blobs to git internal format
*/
if (!strcmp(type, blob_type)) {
unsigned long nsize = size;
char *nbuf = buf;
if (convert_to_git(NULL, &nbuf, &nsize)) {
if (size)
munmap(buf, size);
size = nsize;
buf = nbuf;
re_allocated = 1;
}
}
if (write_object)
ret = write_sha1_file(buf, size, type, sha1);
else
ret = hash_sha1_file(buf, size, type, sha1);
if (re_allocated) {
free(buf);
return ret;
}
if (size)
munmap(buf, size);
return ret;

View file

@ -8,7 +8,7 @@ static int do_generic_cmd(const char *me, char *arg)
if (!arg || !(arg = sq_dequote(arg)))
die("bad argument");
if (strncmp(me, "git-", 4))
if (prefixcmp(me, "git-"))
die("bad command");
my_argv[0] = me + 4;

View file

@ -42,9 +42,9 @@ then
exit
fi
rawsvnrepo="$svnrepo"
svnrepo="file://$svnrepo"
poke() {
perl -e '@x = stat($ARGV[0]); utime($x[8], $x[9] + 1, $ARGV[0])' "$1"
test-chmtime +1 "$1"
}

217
t/t0020-crlf.sh Executable file
View file

@ -0,0 +1,217 @@
#!/bin/sh
test_description='CRLF conversion'
. ./test-lib.sh
append_cr () {
sed -e 's/$/Q/' | tr Q '\015'
}
remove_cr () {
tr '\015' Q <"$1" | grep Q >/dev/null &&
tr '\015' Q <"$1" | sed -ne 's/Q$//p'
}
test_expect_success setup '
git repo-config core.autocrlf false &&
for w in Hello world how are you; do echo $w; done >one &&
mkdir dir &&
for w in I am very very fine thank you; do echo $w; done >dir/two &&
git add . &&
git commit -m initial &&
one=`git rev-parse HEAD:one` &&
dir=`git rev-parse HEAD:dir` &&
two=`git rev-parse HEAD:dir/two` &&
for w in Some extra lines here; do echo $w; done >>one &&
git diff >patch.file &&
patched=`git hash-object --stdin <one` &&
git read-tree --reset -u HEAD &&
echo happy.
'
test_expect_success 'update with autocrlf=input' '
rm -f tmp one dir/two &&
git read-tree --reset -u HEAD &&
git repo-config core.autocrlf input &&
for f in one dir/two
do
append_cr <$f >tmp && mv -f tmp $f &&
git update-index -- $f || {
echo Oops
false
break
}
done &&
differs=`git diff-index --cached HEAD` &&
test -z "$differs" || {
echo Oops "$differs"
false
}
'
test_expect_success 'update with autocrlf=true' '
rm -f tmp one dir/two &&
git read-tree --reset -u HEAD &&
git repo-config core.autocrlf true &&
for f in one dir/two
do
append_cr <$f >tmp && mv -f tmp $f &&
git update-index -- $f || {
echo "Oops $f"
false
break
}
done &&
differs=`git diff-index --cached HEAD` &&
test -z "$differs" || {
echo Oops "$differs"
false
}
'
test_expect_success 'checkout with autocrlf=true' '
rm -f tmp one dir/two &&
git repo-config core.autocrlf true &&
git read-tree --reset -u HEAD &&
for f in one dir/two
do
remove_cr "$f" >tmp && mv -f tmp $f &&
git update-index -- $f || {
echo "Eh? $f"
false
break
}
done &&
test "$one" = `git hash-object --stdin <one` &&
test "$two" = `git hash-object --stdin <dir/two` &&
differs=`git diff-index --cached HEAD` &&
test -z "$differs" || {
echo Oops "$differs"
false
}
'
test_expect_success 'checkout with autocrlf=input' '
rm -f tmp one dir/two &&
git repo-config core.autocrlf input &&
git read-tree --reset -u HEAD &&
for f in one dir/two
do
if remove_cr "$f" >/dev/null
then
echo "Eh? $f"
false
break
else
git update-index -- $f
fi
done &&
test "$one" = `git hash-object --stdin <one` &&
test "$two" = `git hash-object --stdin <dir/two` &&
differs=`git diff-index --cached HEAD` &&
test -z "$differs" || {
echo Oops "$differs"
false
}
'
test_expect_success 'apply patch (autocrlf=input)' '
rm -f tmp one dir/two &&
git repo-config core.autocrlf input &&
git read-tree --reset -u HEAD &&
git apply patch.file &&
test "$patched" = "`git hash-object --stdin <one`" || {
echo "Eh? apply without index"
false
}
'
test_expect_success 'apply patch --cached (autocrlf=input)' '
rm -f tmp one dir/two &&
git repo-config core.autocrlf input &&
git read-tree --reset -u HEAD &&
git apply --cached patch.file &&
test "$patched" = `git rev-parse :one` || {
echo "Eh? apply with --cached"
false
}
'
test_expect_success 'apply patch --index (autocrlf=input)' '
rm -f tmp one dir/two &&
git repo-config core.autocrlf input &&
git read-tree --reset -u HEAD &&
git apply --index patch.file &&
test "$patched" = `git rev-parse :one` &&
test "$patched" = `git hash-object --stdin <one` || {
echo "Eh? apply with --index"
false
}
'
test_expect_success 'apply patch (autocrlf=true)' '
rm -f tmp one dir/two &&
git repo-config core.autocrlf true &&
git read-tree --reset -u HEAD &&
git apply patch.file &&
test "$patched" = "`remove_cr one | git hash-object --stdin`" || {
echo "Eh? apply without index"
false
}
'
test_expect_success 'apply patch --cached (autocrlf=true)' '
rm -f tmp one dir/two &&
git repo-config core.autocrlf true &&
git read-tree --reset -u HEAD &&
git apply --cached patch.file &&
test "$patched" = `git rev-parse :one` || {
echo "Eh? apply without index"
false
}
'
test_expect_success 'apply patch --index (autocrlf=true)' '
rm -f tmp one dir/two &&
git repo-config core.autocrlf true &&
git read-tree --reset -u HEAD &&
git apply --index patch.file &&
test "$patched" = `git rev-parse :one` &&
test "$patched" = "`remove_cr one | git hash-object --stdin`" || {
echo "Eh? apply with --index"
false
}
'
test_done

View file

@ -13,6 +13,10 @@ P1='pathname with HT'
P2='pathname with SP'
P3='pathname
with LF'
: >"$P1" 2>&1 && test -f "$P1" && rm -f "$P1" || {
echo >&2 'Filesystem does not support tabs in names'
test_done
}
test_expect_success setup '
echo P0.0 >"$P0.0" &&

162
t/t4119-apply-config.sh Executable file
View file

@ -0,0 +1,162 @@
#!/bin/sh
#
# Copyright (c) 2007 Junio C Hamano
#
test_description='git-apply --whitespace=strip and configuration file.
'
. ./test-lib.sh
test_expect_success setup '
mkdir sub &&
echo A >sub/file1 &&
cp sub/file1 saved &&
git add sub/file1 &&
echo "B " >sub/file1 &&
git diff >patch.file
'
# Also handcraft GNU diff output; note this has trailing whitespace.
cat >gpatch.file <<\EOF &&
--- file1 2007-02-21 01:04:24.000000000 -0800
+++ file1+ 2007-02-21 01:07:44.000000000 -0800
@@ -1 +1 @@
-A
+B
EOF
sed -e 's|file1|sub/&|' gpatch.file >gpatch-sub.file &&
sed -e '
/^--- /s|file1|a/sub/&|
/^+++ /s|file1|b/sub/&|
' gpatch.file >gpatch-ab-sub.file &&
check_result () {
if grep " " "$1"
then
echo "Eh?"
false
elif grep B "$1"
then
echo Happy
else
echo "Huh?"
false
fi
}
test_expect_success 'apply --whitespace=strip' '
rm -f sub/file1 &&
cp saved sub/file1 &&
git update-index --refresh &&
git apply --whitespace=strip patch.file &&
check_result sub/file1
'
test_expect_success 'apply --whitespace=strip from config' '
rm -f sub/file1 &&
cp saved sub/file1 &&
git update-index --refresh &&
git config apply.whitespace strip &&
git apply patch.file &&
check_result sub/file1
'
D=`pwd`
test_expect_success 'apply --whitespace=strip in subdir' '
cd "$D" &&
git config --unset-all apply.whitespace
rm -f sub/file1 &&
cp saved sub/file1 &&
git update-index --refresh &&
cd sub &&
git apply --whitespace=strip ../patch.file &&
check_result file1
'
test_expect_success 'apply --whitespace=strip from config in subdir' '
cd "$D" &&
git config apply.whitespace strip &&
rm -f sub/file1 &&
cp saved sub/file1 &&
git update-index --refresh &&
cd sub &&
git apply ../patch.file &&
check_result file1
'
test_expect_success 'same in subdir but with traditional patch input' '
cd "$D" &&
git config apply.whitespace strip &&
rm -f sub/file1 &&
cp saved sub/file1 &&
git update-index --refresh &&
cd sub &&
git apply ../gpatch.file &&
check_result file1
'
test_expect_success 'same but with traditional patch input of depth 1' '
cd "$D" &&
git config apply.whitespace strip &&
rm -f sub/file1 &&
cp saved sub/file1 &&
git update-index --refresh &&
cd sub &&
git apply ../gpatch-sub.file &&
check_result file1
'
test_expect_success 'same but with traditional patch input of depth 2' '
cd "$D" &&
git config apply.whitespace strip &&
rm -f sub/file1 &&
cp saved sub/file1 &&
git update-index --refresh &&
cd sub &&
git apply ../gpatch-ab-sub.file &&
check_result file1
'
test_expect_success 'same but with traditional patch input of depth 1' '
cd "$D" &&
git config apply.whitespace strip &&
rm -f sub/file1 &&
cp saved sub/file1 &&
git update-index --refresh &&
git apply -p0 gpatch-sub.file &&
check_result sub/file1
'
test_expect_success 'same but with traditional patch input of depth 2' '
cd "$D" &&
git config apply.whitespace strip &&
rm -f sub/file1 &&
cp saved sub/file1 &&
git update-index --refresh &&
git apply gpatch-ab-sub.file &&
check_result sub/file1
'
test_done

View file

@ -112,39 +112,26 @@ rr2=.git/rr-cache/$sha2
mkdir $rr2
echo Hello > $rr2/preimage
case "$(date -d @11111111 +%s 2>/dev/null)" in
11111111)
# 'date' must be able to take arbitrary input with @11111111 notation.
# for this test to succeed. We should fix this part using more
# portable script someday.
almost_15_days_ago=$((60-15*86400))
just_over_15_days_ago=$((-1-15*86400))
almost_60_days_ago=$((60-60*86400))
just_over_60_days_ago=$((-1-60*86400))
now=$(date +%s)
almost_15_days_ago=$(($now+60-15*86400))
just_over_15_days_ago=$(($now-1-15*86400))
almost_60_days_ago=$(($now+60-60*86400))
just_over_60_days_ago=$(($now-1-60*86400))
predate1="$(date -d "@$almost_60_days_ago" +%Y%m%d%H%M.%S)"
predate2="$(date -d "@$almost_15_days_ago" +%Y%m%d%H%M.%S)"
postdate1="$(date -d "@$just_over_60_days_ago" +%Y%m%d%H%M.%S)"
postdate2="$(date -d "@$just_over_15_days_ago" +%Y%m%d%H%M.%S)"
test-chmtime =$almost_60_days_ago $rr/preimage
test-chmtime =$almost_15_days_ago $rr2/preimage
touch -m -t "$predate1" $rr/preimage
touch -m -t "$predate2" $rr2/preimage
test_expect_success 'garbage collection (part1)' 'git rerere gc'
test_expect_success 'garbage collection (part1)' 'git rerere gc'
test_expect_success 'young records still live' \
"test -f $rr/preimage && test -f $rr2/preimage"
test_expect_success 'young records still live' \
"test -f $rr/preimage -a -f $rr2/preimage"
test-chmtime =$just_over_60_days_ago $rr/preimage
test-chmtime =$just_over_15_days_ago $rr2/preimage
touch -m -t "$postdate1" $rr/preimage
touch -m -t "$postdate2" $rr2/preimage
test_expect_success 'garbage collection (part2)' 'git rerere gc'
test_expect_success 'garbage collection (part2)' 'git rerere gc'
test_expect_success 'old records rest in peace' \
"test ! -f $rr/preimage -a ! -f $rr2/preimage"
;;
esac
test_expect_success 'old records rest in peace' \
"test ! -f $rr/preimage && test ! -f $rr2/preimage"
test_done

View file

@ -211,8 +211,58 @@ tree d667270a1f7b109f5eb3aaea21ede14b56bfdd6e
tree 8f51f74cf0163afc9ad68a4b1537288c4558b5a4
EOF
echo tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904 >> expected
test_expect_success "$name" "diff -u a expected"
test_expect_failure 'exit if remote refs are ambigious' "
git-config --add svn-remote.svn.fetch \
bar:refs/remotes/git-svn &&
git-svn migrate
"
test_expect_failure 'exit if init-ing a would clobber a URL' "
svnadmin create ${PWD}/svnrepo2 &&
svn mkdir -m 'mkdir bar' ${svnrepo}2/bar &&
git-config --unset svn-remote.svn.fetch \
'^bar:refs/remotes/git-svn$' &&
git-svn init ${svnrepo}2/bar
"
test_expect_success \
'init allows us to connect to another directory in the same repo' "
git-svn init -i bar $svnrepo/bar &&
git config --get svn-remote.svn.fetch \
'^bar:refs/remotes/bar$' &&
git config --get svn-remote.svn.fetch \
'^:refs/remotes/git-svn$'
"
test_expect_success 'able to dcommit to a subdirectory' "
git-svn fetch -i bar &&
git checkout -b my-bar refs/remotes/bar &&
echo abc > d &&
git update-index --add d &&
git commit -m '/bar/d should be in the log' &&
git-svn dcommit -i bar &&
test -z \"\`git diff refs/heads/my-bar refs/remotes/bar\`\" &&
mkdir newdir &&
echo new > newdir/dir &&
git update-index --add newdir/dir &&
git commit -m 'add a new directory' &&
git-svn dcommit -i bar &&
test -z \"\`git diff refs/heads/my-bar refs/remotes/bar\`\" &&
echo foo >> newdir/dir &&
git update-index newdir/dir &&
git commit -m 'modify a file in new directory' &&
git-svn dcommit -i bar &&
test -z \"\`git diff refs/heads/my-bar refs/remotes/bar\`\"
"
test_expect_success 'able to set-tree to a subdirectory' "
echo cba > d &&
git update-index d &&
git commit -m 'update /bar/d' &&
git-svn set-tree -i bar HEAD &&
test -z \"\`git diff refs/heads/my-bar refs/remotes/bar\`\"
"
test_done

View file

@ -121,4 +121,30 @@ b_ne_cr="`git-hash-object ne_cr`"
test_expect_success 'CRLF + $Id$' "test '$a_cr' = '$b_cr'"
test_expect_success 'CRLF + $Id$ (no newline)' "test '$a_ne_cr' = '$b_ne_cr'"
cat > show-ignore.expect <<\EOF
# /
/no-such-file*
# deeply
/deeply/no-such-file*
# deeply/nested
/deeply/nested/no-such-file*
# deeply/nested/directory
/deeply/nested/directory/no-such-file*
EOF
test_expect_success 'test show-ignore' "
cd test_wc &&
mkdir -p deeply/nested/directory &&
svn add deeply &&
svn propset -R svn:ignore 'no-such-file*' .
svn commit -m 'propset svn:ignore'
cd .. &&
git-svn show-ignore > show-ignore.got &&
cmp show-ignore.expect show-ignore.got
"
test_done

View file

@ -1,61 +0,0 @@
#!/bin/sh
test_description='git-svn graft-branches'
. ./lib-git-svn.sh
svnrepo="$svnrepo/test-git-svn"
test_expect_success 'initialize repo' "
mkdir import &&
cd import &&
mkdir -p trunk branches tags &&
echo hello > trunk/readme &&
svn import -m 'import for git-svn' . $svnrepo &&
cd .. &&
svn cp -m 'tag a' $svnrepo/trunk $svnrepo/tags/a &&
svn cp -m 'branch a' $svnrepo/trunk $svnrepo/branches/a &&
svn co $svnrepo wc &&
cd wc &&
echo feedme >> branches/a/readme &&
poke branches/a/readme &&
svn commit -m hungry &&
cd trunk &&
svn merge -r3:4 $svnrepo/branches/a &&
svn commit -m 'merge with a' &&
cd ../.. &&
git-svn multi-init $svnrepo -T trunk -b branches -t tags &&
git-svn multi-fetch
"
r1=`git-rev-list remotes/trunk | tail -n1`
r2=`git-rev-list remotes/tags/a | tail -n1`
r3=`git-rev-list remotes/a | tail -n1`
r4=`git-rev-parse remotes/a`
r5=`git-rev-parse remotes/trunk`
test_expect_success 'test graft-branches regexes and copies' "
test -n "$r1" &&
test -n "$r2" &&
test -n "$r3" &&
test -n "$r4" &&
test -n "$r5" &&
git-svn graft-branches &&
grep '^$r2 $r1' $GIT_DIR/info/grafts &&
grep '^$r3 $r1' $GIT_DIR/info/grafts &&
grep '^$r5 ' $GIT_DIR/info/grafts | grep '$r4' | grep '$r1'
"
test_debug 'gitk --all & sleep 1'
test_expect_success 'test graft-branches with tree-joins' "
rm $GIT_DIR/info/grafts &&
git-svn graft-branches --no-default-regex --no-graft-copy -B &&
grep '^$r3 ' $GIT_DIR/info/grafts | grep '$r1' | grep '$r2' &&
grep '^$r2 $r1' $GIT_DIR/info/grafts &&
grep '^$r5 ' $GIT_DIR/info/grafts | grep '$r1' | grep '$r4'
"
# the result of this is kinda funky, we have a strange history and
# this is just a test :)
test_debug 'gitk --all &'
test_done

View file

@ -3,7 +3,7 @@
# Copyright (c) 2006 Eric Wong
#
test_description='git-svn --follow-parent fetching'
test_description='git-svn fetching'
. ./lib-git-svn.sh
test_expect_success 'initialize repo' "
@ -27,11 +27,141 @@ test_expect_success 'initialize repo' "
cd ..
"
test_expect_success 'init and fetch --follow-parent a moved directory' "
test_expect_success 'init and fetch a moved directory' "
git-svn init -i thunk $svnrepo/thunk &&
git-svn fetch --follow-parent -i thunk &&
git-rev-parse --verify refs/remotes/trunk &&
test '$?' -eq '0'
git-svn fetch -i thunk &&
test \"\`git-rev-parse --verify refs/remotes/thunk@2\`\" \
= \"\`git-rev-parse --verify refs/remotes/thunk~1\`\" &&
test \"\`git-cat-file blob refs/remotes/thunk:readme |\
sed -n -e '3p'\`\" = goodbye &&
test -z \"\`git-config --get svn-remote.svn.fetch \
'^trunk:refs/remotes/thunk@2$'\`\"
"
test_expect_success 'init and fetch from one svn-remote' "
git-config svn-remote.svn.url $svnrepo &&
git-config --add svn-remote.svn.fetch \
trunk:refs/remotes/svn/trunk &&
git-config --add svn-remote.svn.fetch \
thunk:refs/remotes/svn/thunk &&
git-svn fetch -i svn/thunk &&
test \"\`git-rev-parse --verify refs/remotes/svn/trunk\`\" \
= \"\`git-rev-parse --verify refs/remotes/svn/thunk~1\`\" &&
test \"\`git-cat-file blob refs/remotes/svn/thunk:readme |\
sed -n -e '3p'\`\" = goodbye
"
test_expect_success 'follow deleted parent' "
svn cp -m 'resurrecting trunk as junk' \
-r2 $svnrepo/trunk $svnrepo/junk &&
git-config --add svn-remote.svn.fetch \
junk:refs/remotes/svn/junk &&
git-svn fetch -i svn/thunk &&
git-svn fetch -i svn/junk &&
test -z \"\`git diff svn/junk svn/trunk\`\" &&
test \"\`git merge-base svn/junk svn/trunk\`\" \
= \"\`git rev-parse svn/trunk\`\"
"
test_expect_success 'follow larger parent' "
mkdir -p import/trunk/thunk/bump/thud &&
echo hi > import/trunk/thunk/bump/thud/file &&
svn import -m 'import a larger parent' import $svnrepo/larger-parent &&
svn cp -m 'hi' $svnrepo/larger-parent $svnrepo/another-larger &&
git-svn init -i larger $svnrepo/another-larger/trunk/thunk/bump/thud &&
git-svn fetch -i larger &&
git-rev-parse --verify refs/remotes/larger &&
git-rev-parse --verify \
refs/remotes/larger-parent/trunk/thunk/bump/thud &&
test \"\`git-merge-base \
refs/remotes/larger-parent/trunk/thunk/bump/thud \
refs/remotes/larger\`\" = \
\"\`git-rev-parse refs/remotes/larger\`\"
true
"
test_expect_success 'follow higher-level parent' "
svn mkdir -m 'follow higher-level parent' $svnrepo/blob &&
svn co $svnrepo/blob blob &&
cd blob &&
echo hi > hi &&
svn add hi &&
svn commit -m 'hihi' &&
cd ..
svn mkdir -m 'new glob at top level' $svnrepo/glob &&
svn mv -m 'move blob down a level' $svnrepo/blob $svnrepo/glob/blob &&
git-svn init -i blob $svnrepo/glob/blob &&
git-svn fetch -i blob
"
test_expect_success 'follow deleted directory' "
svn mv -m 'bye!' $svnrepo/glob/blob/hi $svnrepo/glob/blob/bye &&
svn rm -m 'remove glob' $svnrepo/glob &&
git-svn init -i glob $svnrepo/glob &&
git-svn fetch -i glob &&
test \"\`git cat-file blob refs/remotes/glob:blob/bye\`\" = hi &&
test \"\`git ls-tree refs/remotes/glob | wc -l \`\" -eq 1
"
# ref: r9270 of the Subversion repository: (http://svn.collab.net/repos/svn)
# in trunk/subversion/bindings/swig/perl
test_expect_success 'follow-parent avoids deleting relevant info' "
mkdir -p import/trunk/subversion/bindings/swig/perl/t &&
for i in a b c ; do \
echo \$i > import/trunk/subversion/bindings/swig/perl/\$i.pm &&
echo _\$i > import/trunk/subversion/bindings/swig/perl/t/\$i.t; \
done &&
echo 'bad delete test' > \
import/trunk/subversion/bindings/swig/perl/t/larger-parent &&
echo 'bad delete test 2' > \
import/trunk/subversion/bindings/swig/perl/another-larger &&
cd import &&
svn import -m 'r9270 test' . $svnrepo/r9270 &&
cd .. &&
svn co $svnrepo/r9270/trunk/subversion/bindings/swig/perl r9270 &&
cd r9270 &&
svn mkdir native &&
svn mv t native/t &&
for i in a b c; do svn mv \$i.pm native/\$i.pm; done &&
echo z >> native/t/c.t &&
poke native/t/c.t &&
svn commit -m 'reorg test' &&
cd .. &&
git-svn init -i r9270-t \
$svnrepo/r9270/trunk/subversion/bindings/swig/perl/native/t &&
git-svn fetch -i r9270-t &&
test \`git rev-list r9270-t | wc -l\` -eq 2 &&
test \"\`git ls-tree --name-only r9270-t~1\`\" = \
\"\`git ls-tree --name-only r9270-t\`\"
"
test_expect_success "track initial change if it was only made to parent" "
svn cp -m 'wheee!' $svnrepo/r9270/trunk $svnrepo/r9270/drunk &&
git-svn init -i r9270-d \
$svnrepo/r9270/drunk/subversion/bindings/swig/perl/native/t &&
git-svn fetch -i r9270-d &&
test \`git rev-list r9270-d | wc -l\` -eq 3 &&
test \"\`git ls-tree --name-only r9270-t\`\" = \
\"\`git ls-tree --name-only r9270-d\`\" &&
test \"\`git rev-parse r9270-t\`\" = \
\"\`git rev-parse r9270-d~1\`\"
"
test_expect_success "track multi-parent paths" "
svn cp -m 'resurrect /glob' $svnrepo/r9270 $svnrepo/glob &&
git-svn multi-fetch &&
test \`git cat-file commit refs/remotes/glob | \
grep '^parent ' | wc -l\` -eq 2
"
test_expect_success "multi-fetch continues to work" "
git-svn multi-fetch
"
test_expect_success "multi-fetch works off a 'clean' repository" "
rm -r $GIT_DIR/svn $GIT_DIR/refs/remotes $GIT_DIR/logs &&
mkdir $GIT_DIR/svn &&
git-svn multi-fetch
"
test_debug 'gitk --all &'

View file

@ -31,4 +31,13 @@ test_expect_success 'test the commit-diff command' "
cmp readme wc/readme
"
test_expect_success 'commit-diff to a sub-directory (with git-svn config)' "
svn import -m 'sub-directory' import $svnrepo/subdir &&
git-svn init $svnrepo/subdir &&
git-svn fetch &&
git-svn commit-diff -r3 '$prev' '$head' &&
svn cat $svnrepo/subdir/readme > readme.2 &&
cmp readme readme.2
"
test_done

112
t/t9107-git-svn-migrate.sh Executable file
View file

@ -0,0 +1,112 @@
#!/bin/sh
# Copyright (c) 2006 Eric Wong
test_description='git-svn metadata migrations from previous versions'
. ./lib-git-svn.sh
test_expect_success 'setup old-looking metadata' "
cp $GIT_DIR/config $GIT_DIR/config-old-git-svn &&
mkdir import &&
cd import &&
for i in trunk branches/a branches/b \
tags/0.1 tags/0.2 tags/0.3; do
mkdir -p \$i && \
echo hello >> \$i/README || exit 1
done && \
svn import -m test . $svnrepo
cd .. &&
git-svn init $svnrepo &&
git-svn fetch &&
mv $GIT_DIR/svn/* $GIT_DIR/ &&
mv $GIT_DIR/svn/.metadata $GIT_DIR/ &&
rmdir $GIT_DIR/svn &&
git-update-ref refs/heads/git-svn-HEAD refs/remotes/git-svn &&
git-update-ref refs/heads/svn-HEAD refs/remotes/git-svn &&
git-update-ref -d refs/remotes/git-svn refs/remotes/git-svn
"
head=`git rev-parse --verify refs/heads/git-svn-HEAD^0`
test_expect_success 'git-svn-HEAD is a real HEAD' "test -n '$head'"
test_expect_success 'initialize old-style (v0) git-svn layout' "
mkdir -p $GIT_DIR/git-svn/info $GIT_DIR/svn/info &&
echo $svnrepo > $GIT_DIR/git-svn/info/url &&
echo $svnrepo > $GIT_DIR/svn/info/url &&
git-svn migrate &&
! test -d $GIT_DIR/git-svn &&
git-rev-parse --verify refs/remotes/git-svn^0 &&
git-rev-parse --verify refs/remotes/svn^0 &&
test \`git config --get svn-remote.svn.url\` = '$svnrepo' &&
test \`git config --get svn-remote.svn.fetch\` = \
':refs/remotes/git-svn'
"
test_expect_success 'initialize a multi-repository repo' "
git-svn init $svnrepo -T trunk -t tags -b branches &&
git-config --get-all svn-remote.svn.fetch > fetch.out &&
grep '^trunk:refs/remotes/trunk$' fetch.out &&
test -n \"\`git-config --get svn-remote.svn.branches \
'^branches/\*:refs/remotes/\*$'\`\" &&
test -n \"\`git-config --get svn-remote.svn.tags \
'^tags/\*:refs/remotes/tags/\*$'\`\" &&
git config --unset svn-remote.svn.branches \
'^branches/\*:refs/remotes/\*$' &&
git config --unset svn-remote.svn.tags \
'^tags/\*:refs/remotes/tags/\*$' &&
git-config --add svn-remote.svn.fetch 'branches/a:refs/remotes/a' &&
git-config --add svn-remote.svn.fetch 'branches/b:refs/remotes/b' &&
for i in tags/0.1 tags/0.2 tags/0.3; do
git-config --add svn-remote.svn.fetch \
\$i:refs/remotes/\$i || exit 1; done
"
# refs should all be different, but the trees should all be the same:
test_expect_success 'multi-fetch works on partial urls + paths' "
git-svn multi-fetch &&
for i in trunk a b tags/0.1 tags/0.2 tags/0.3; do
git rev-parse --verify refs/remotes/\$i^0 >> refs.out || exit 1;
done &&
test -z \"\`sort < refs.out | uniq -d\`\" &&
for i in trunk a b tags/0.1 tags/0.2 tags/0.3; do
for j in trunk a b tags/0.1 tags/0.2 tags/0.3; do
if test \$j != \$i; then continue; fi
test -z \"\`git diff refs/remotes/\$i \
refs/remotes/\$j\`\" ||exit 1; done; done
"
test_expect_success 'migrate --minimize on old inited layout' "
git config --unset-all svn-remote.svn.fetch &&
git config --unset-all svn-remote.svn.url &&
rm -rf $GIT_DIR/svn &&
for i in \`cat fetch.out\`; do
path=\`expr \$i : '\\([^:]*\\):.*$'\`
ref=\`expr \$i : '[^:]*:refs/remotes/\\(.*\\)$'\`
if test -z \"\$ref\"; then continue; fi
if test -n \"\$path\"; then path=\"/\$path\"; fi
( mkdir -p $GIT_DIR/svn/\$ref/info/ &&
echo $svnrepo\$path > $GIT_DIR/svn/\$ref/info/url ) || exit 1;
done &&
git-svn migrate --minimize &&
test -z \"\`git-config -l |grep -v '^svn-remote\.git-svn\.'\`\" &&
git-config --get-all svn-remote.svn.fetch > fetch.out &&
grep '^trunk:refs/remotes/trunk$' fetch.out &&
grep '^branches/a:refs/remotes/a$' fetch.out &&
grep '^branches/b:refs/remotes/b$' fetch.out &&
grep '^tags/0\.1:refs/remotes/tags/0\.1$' fetch.out &&
grep '^tags/0\.2:refs/remotes/tags/0\.2$' fetch.out &&
grep '^tags/0\.3:refs/remotes/tags/0\.3$' fetch.out
grep '^:refs/remotes/git-svn' fetch.out
"
test_expect_success ".rev_db auto-converted to .rev_db.UUID" "
git-svn fetch -i trunk &&
expect=$GIT_DIR/svn/trunk/.rev_db.* &&
test -n \"\$expect\" &&
mv \$expect $GIT_DIR/svn/trunk/.rev_db &&
git-svn fetch -i trunk &&
test -L $GIT_DIR/svn/trunk/.rev_db &&
test -f \$expect &&
cmp \$expect $GIT_DIR/svn/trunk/.rev_db
"
test_done

Some files were not shown because too many files have changed in this diff Show more