summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/config.txt24
-rw-r--r--Documentation/cvs-migration.txt11
-rw-r--r--Documentation/fetch-options.txt11
-rw-r--r--Documentation/git-branch.txt9
-rw-r--r--Documentation/git-clone.txt29
-rw-r--r--Documentation/git-pull.txt69
-rw-r--r--Documentation/git-svn.txt87
-rw-r--r--Documentation/git-svnimport.txt10
-rw-r--r--Documentation/git-tag.txt7
-rw-r--r--Documentation/glossary.txt7
-rw-r--r--Documentation/hooks.txt4
-rw-r--r--Documentation/pull-fetch-param.txt4
-rw-r--r--Documentation/technical/send-pack-pipeline.txt63
-rw-r--r--Documentation/tutorial.txt76
-rw-r--r--Documentation/urls.txt26
-rw-r--r--Makefile4
-rw-r--r--archive-tar.c7
-rw-r--r--builtin-branch.c85
-rw-r--r--builtin-prune.c2
-rw-r--r--builtin-rerere.c7
-rw-r--r--cache.h2
-rw-r--r--commit.c15
-rw-r--r--contrib/emacs/git.el21
-rw-r--r--diff-lib.c9
-rw-r--r--diff.c6
-rw-r--r--diff.h4
-rw-r--r--diffcore.h4
-rw-r--r--fetch-pack.c3
-rwxr-xr-xgenerate-cmdlist.sh1
-rwxr-xr-xgit-am.sh7
-rwxr-xr-xgit-clean.sh4
-rwxr-xr-xgit-commit.sh1
-rwxr-xr-xgit-fetch.sh23
-rwxr-xr-xgit-instaweb.sh13
-rwxr-xr-xgit-merge.sh3
-rwxr-xr-xgit-parse-remote.sh23
-rwxr-xr-xgit-pull.sh3
-rwxr-xr-xgit-remote.perl277
-rwxr-xr-xgit-reset.sh6
-rwxr-xr-xgit-svn.perl90
-rwxr-xr-xgit-svnimport.perl36
-rwxr-xr-xgit-tag.sh11
-rwxr-xr-xgit-verify-tag.sh3
-rwxr-xr-xgitweb/gitweb.perl41
-rw-r--r--lockfile.c9
-rw-r--r--merge-recursive.c27
-rw-r--r--refs.c1
-rw-r--r--send-pack.c163
-rw-r--r--t/lib-git-svn.sh39
-rwxr-xr-xt/t5401-update-hooks.sh81
-rwxr-xr-xt/t9100-git-svn-basic.sh84
-rwxr-xr-xt/t9101-git-svn-props.sh11
-rwxr-xr-xt/t9103-git-svn-graft-branches.sh14
-rwxr-xr-xt/t9104-git-svn-follow-parent.sh1
-rwxr-xr-xt/test-lib.sh6
-rw-r--r--tree-walk.c1
-rw-r--r--write_or_die.c23
-rw-r--r--wt-status.c49
-rw-r--r--wt-status.h1
59 files changed, 1114 insertions, 544 deletions
diff --git a/Documentation/config.txt b/Documentation/config.txt
index b24d9dff62..b4aae0d0ae 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -173,6 +173,21 @@ branch.<name>.merge::
this option, `git pull` defaults to merge the first refspec fetched.
Specify multiple values to get an octopus merge.
+color.branch::
+ A boolean to enable/disable color in the output of
+ gitlink:git-branch[1]. May be set to `true` (or `always`),
+ `false` (or `never`) or `auto`, in which case colors are used
+ only when the output is to a terminal. Defaults to false.
+
+color.branch.<slot>::
+ Use customized color for branch coloration. `<slot>` is one of
+ `current` (the current branch), `local` (a local branch),
+ `remote` (a tracking branch in refs/remotes/), `plain` (other
+ refs), or `reset` (the normal terminal color). The value for
+ these configuration variables can be one of: `normal`, `bold`,
+ `dim`, `ul`, `blink`, `reverse`, `reset`, `black`, `red`,
+ `green`, `yellow`, `blue`, `magenta`, `cyan`, or `white`.
+
color.diff::
When true (or `always`), always use colors in patch.
When false (or `never`), never. When set to `auto`, use
@@ -183,11 +198,8 @@ color.diff.<slot>::
specifies which part of the patch to use the specified
color, and is one of `plain` (context text), `meta`
(metainformation), `frag` (hunk header), `old` (removed
- lines), or `new` (added lines). The value for these
- configuration variables can be one of: `normal`, `bold`,
- `dim`, `ul`, `blink`, `reverse`, `reset`, `black`,
- `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, or
- `white`.
+ lines), or `new` (added lines). The values of these
+ variables may be specified as in color.branch.<slot>.
color.pager::
A boolean to enable/disable colored output when the pager is in
@@ -205,7 +217,7 @@ color.status.<slot>::
`added` or `updated` (files which are added but not committed),
`changed` (files which are changed but not added in the index),
or `untracked` (files which are not tracked by git). The values of
- these variables may be specified as in color.diff.<slot>.
+ these variables may be specified as in color.branch.<slot>.
diff.renameLimit::
The number of files to consider when performing the copy/rename
diff --git a/Documentation/cvs-migration.txt b/Documentation/cvs-migration.txt
index b657f4589f..8e09beaa79 100644
--- a/Documentation/cvs-migration.txt
+++ b/Documentation/cvs-migration.txt
@@ -34,13 +34,10 @@ them first before running git pull.
[NOTE]
================================
-The first `git clone` places the following in the
-`my-project/.git/remotes/origin` file, and that's why the previous step
-and the next step both work.
-------------
-URL: foo.com:/pub/project.git/
-Pull: refs/heads/master:refs/remotes/origin/master
-------------
+The `pull` command knows where to get updates from because of certain
+configuration variables that were set by the first `git clone`
+command; see `git repo-config -l` and the gitlink:git-repo-config[1] man
+page for details.
================================
You can update the shared repository with your changes by first committing
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index 13f34d3ca2..5b4d184a73 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -36,6 +36,13 @@
-u, \--update-head-ok::
By default `git-fetch` refuses to update the head which
corresponds to the current branch. This flag disables the
- check. Note that fetching into the current branch will not
- update the index and working directory, so use it with care.
+ check. This is purely for the internal use for `git-pull`
+ to communicate with `git-fetch`, and unless you are
+ implementing your own Porcelain you are not supposed to
+ use it.
+
+\--depth=<depth>::
+ Deepen the history of a 'shallow' repository created by
+ `git clone` with `--depth=<depth>` option (see gitlink:git-clone[1])
+ by the specified number of commits.
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index c464bd2fda..e872fc89fc 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -8,7 +8,7 @@ git-branch - List, create, or delete branches.
SYNOPSIS
--------
[verse]
-'git-branch' [-r | -a] [-v [--abbrev=<length>]]
+'git-branch' [--color | --no-color] [-r | -a] [-v [--abbrev=<length>]]
'git-branch' [-l] [-f] <branchname> [<start-point>]
'git-branch' (-m | -M) [<oldbranch>] <newbranch>
'git-branch' (-d | -D) [-r] <branchname>...
@@ -60,6 +60,13 @@ OPTIONS
-M::
Move/rename a branch even if the new branchname already exists.
+--color::
+ Color branches to highlight current, local, and remote branches.
+
+--no-color::
+ Turn off branch colors, even when the configuration file gives the
+ default to color output.
+
-r::
List or delete (if used with -d) the remote-tracking branches.
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 874934a332..a78207461d 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -11,26 +11,27 @@ SYNOPSIS
[verse]
'git-clone' [--template=<template_directory>] [-l [-s]] [-q] [-n] [--bare]
[-o <name>] [-u <upload-pack>] [--reference <repository>]
- <repository> [<directory>]
+ [--depth=<depth>] <repository> [<directory>]
DESCRIPTION
-----------
Clones a repository into a newly created directory, creates
remote-tracking branches for each branch in the cloned repository
-(visible using `git branch -r`), and creates and checks out a master
-branch equal to the cloned repository's master branch.
+(visible using `git branch -r`), and creates and checks out an initial
+branch equal to the cloned repository's currently active branch.
After the clone, a plain `git fetch` without arguments will update
all the remote-tracking branches, and a `git pull` without
arguments will in addition merge the remote master branch into the
-current branch.
+current master branch, if any.
This default configuration is achieved by creating references to
the remote branch heads under `$GIT_DIR/refs/remotes/origin` and
by initializing `remote.origin.url` and `remote.origin.fetch`
configuration variables.
+
OPTIONS
-------
--local::
@@ -75,16 +76,13 @@ OPTIONS
Also the branch heads at the remote are copied directly
to corresponding local branch heads, without mapping
them to `refs/remotes/origin/`. When this option is
- used, neither the `origin` branch nor the default
- `remotes/origin` file is created.
+ used, neither remote-tracking branches nor the related
+ configuration variables are created.
--origin <name>::
-o <name>::
- Instead of using the branch name 'origin' to keep track
- of the upstream repository, use <name> instead. Note
- that the shorthand name stored in `remotes/origin` is
- not affected, but the local branch name to pull the
- remote `master` branch into is.
+ Instead of using the remote name 'origin' to keep track
+ of the upstream repository, use <name> instead.
--upload-pack <upload-pack>::
-u <upload-pack>::
@@ -98,6 +96,15 @@ OPTIONS
if unset the templates are taken from the installation
defined default, typically `/usr/share/git-core/templates`.
+--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
+ it, nor push from nor into it), but is adequate if you
+ want to only look at near the tip of a large project
+ with a long history, and would want to send in a fixes
+ as patches.
+
<repository>::
The (possibly remote) repository to clone from. It can
be any URL git-fetch supports.
diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index 2a5aea73ba..13be992006 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -37,17 +37,27 @@ EXAMPLES
--------
git pull, git pull origin::
- Fetch the default head from the repository you cloned
- from and merge it into your current branch.
-
-git pull -s ours . obsolete::
- Merge local branch `obsolete` into the current branch,
- using `ours` merge strategy.
+ Update the remote-tracking branches for the repository
+ you cloned from, then merge one of them into your
+ current branch. Normally the branch merged in is
+ the HEAD of the remote repository, but the choice is
+ determined by the branch.<name>.remote and
+ branch.<name>.merge options; see gitlink:git-repo-config[1]
+ for details.
+
+git pull origin next::
+ Merge into the current branch the remote branch `next`;
+ leaves a copy of `next` temporarily in FETCH_HEAD, but
+ does not update any remote-tracking branches.
git pull . fixes enhancements::
Bundle local branch `fixes` and `enhancements` on top of
the current branch, making an Octopus merge.
+git pull -s ours . obsolete::
+ Merge local branch `obsolete` into the current branch,
+ using `ours` merge strategy.
+
git pull --no-commit . maint::
Merge local branch `maint` into the current branch, but
do not make a commit automatically. This can be used
@@ -61,48 +71,19 @@ release/version name would be acceptable.
Command line pull of multiple branches from one repository::
+
------------------------------------------------
-$ cat .git/remotes/origin
-URL: git://git.kernel.org/pub/scm/git/git.git
-Pull: master:origin
-
$ git checkout master
-$ git fetch origin master:origin +pu:pu maint:maint
-$ git pull . origin
+$ git fetch origin +pu:pu maint:tmp
+$ git pull . tmp
------------------------------------------------
+
-Here, a typical `.git/remotes/origin` file from a
-`git-clone` operation is used in combination with
-command line options to `git-fetch` to first update
-multiple branches of the local repository and then
-to merge the remote `origin` branch into the local
-`master` branch. The local `pu` branch is updated
-even if it does not result in a fast forward update.
-Here, the pull can obtain its objects from the local
-repository using `.`, as the previous `git-fetch` is
-known to have already obtained and made available
-all the necessary objects.
-
-
-Pull of multiple branches from one repository using `.git/remotes` file::
+This updates (or creates, as necessary) branches `pu` and `tmp`
+in the local repository by fetching from the branches
+(respectively) `pu` and `maint` from the remote repository.
+
-------------------------------------------------
-$ cat .git/remotes/origin
-URL: git://git.kernel.org/pub/scm/git/git.git
-Pull: master:origin
-Pull: +pu:pu
-Pull: maint:maint
-
-$ git checkout master
-$ git pull origin
-------------------------------------------------
+The `pu` branch will be updated even if it is does not
+fast-forward; the others will not be.
+
-Here, a typical `.git/remotes/origin` file from a
-`git-clone` operation has been hand-modified to include
-the branch-mapping of additional remote and local
-heads directly. A single `git-pull` operation while
-in the `master` branch will fetch multiple heads and
-merge the remote `origin` head into the current,
-local `master` branch.
+The final command then merges the newly fetched `tmp` into master.
If you tried a pull which resulted in a complex conflicts and
@@ -112,7 +93,7 @@ gitlink:git-reset[1].
SEE ALSO
--------
-gitlink:git-fetch[1], gitlink:git-merge[1]
+gitlink:git-fetch[1], gitlink:git-merge[1], gitlink:git-repo-config[1]
Author
diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt
index f5f57e8f87..ce63defffd 100644
--- a/Documentation/git-svn.txt
+++ b/Documentation/git-svn.txt
@@ -3,7 +3,7 @@ git-svn(1)
NAME
----
-git-svn - bidirectional operation between a single Subversion branch and git
+git-svn - bidirectional operation between Subversion and git
SYNOPSIS
--------
@@ -11,24 +11,20 @@ SYNOPSIS
DESCRIPTION
-----------
-git-svn is a simple conduit for changesets between a single Subversion
-branch and git. It is not to be confused with gitlink:git-svnimport[1].
-They were designed with very different goals in mind.
+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.
-git-svn is designed for an individual developer who wants a
+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. git-svnimport is designed
-for read-only operation on repositories that match a particular layout
-(albeit the recommended one by SVN developers).
+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.
-For importing svn, git-svnimport is potentially more powerful when
-operating on repositories organized under the recommended
-trunk/branch/tags structure, and should be faster, too.
-
-git-svn mostly ignores the very limited view of branching that
-Subversion has. This allows git-svn to be much easier to use,
-especially on repositories that are not organized in a manner that
-git-svnimport is designed for.
+git-svn is especially useful when it comes to tracking repositories
+not organized in the way Subversion developers recommend (trunk,
+branches, tags directories).
COMMANDS
--------
@@ -57,11 +53,13 @@ See '<<fetch-args,Additional Fetch Arguments>>' if you are interested in
manually joining branches on commit.
'dcommit'::
- Commit all diffs from a specified head directly to the SVN
+ Commit each diff from a specified head directly to the SVN
repository, and then rebase or reset (depending on whether or
- not there is a diff between SVN and head). It is recommended
- that you run git-svn fetch and rebase (not pull) your commits
- against the latest changes in the SVN repository.
+ not there is a diff between SVN and head). This will create
+ a revision in SVN for each commit in git.
+ It is recommended that you run git-svn fetch and rebase (not
+ pull or merge) your commits against the latest changes in the
+ SVN repository.
An optional command-line argument may be specified as an
alternative to HEAD.
This is advantageous over 'set-tree' (below) because it produces
@@ -370,7 +368,7 @@ SVN was very wrong.
Basic Examples
~~~~~~~~~~~~~~
-Tracking and contributing to a Subversion-managed project:
+Tracking and contributing to a the trunk of a Subversion-managed project:
------------------------------------------------------------------------
# Initialize a repo (like git init-db):
@@ -388,19 +386,44 @@ Tracking and contributing to a Subversion-managed project:
git-svn show-ignore >> .git/info/exclude
------------------------------------------------------------------------
-REBASE VS. PULL
----------------
+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-db):
+ 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
+------------------------------------------------------------------------
+
+REBASE VS. PULL/MERGE
+---------------------
Originally, git-svn recommended that the remotes/git-svn branch be
-pulled from. This is because the author favored 'git-svn set-tree B'
-to commit a single head rather than the 'git-svn set-tree A..B' notation
-to commit multiple commits.
-
-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'. 'pull'
-can cause non-linear history to be flattened when committing into SVN,
-which can lead to merge commits reversing previous commits in SVN.
+pulled or merged from. This is because the author favored
+'git-svn set-tree B' to commit a single head rather than the
+'git-svn set-tree A..B' notation to commit multiple commits.
+
+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
+'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.
DESIGN PHILOSOPHY
-----------------
diff --git a/Documentation/git-svnimport.txt b/Documentation/git-svnimport.txt
index 2c7c7dad54..b166cf3327 100644
--- a/Documentation/git-svnimport.txt
+++ b/Documentation/git-svnimport.txt
@@ -15,7 +15,7 @@ SYNOPSIS
[ -b branch_subdir ] [ -T trunk_subdir ] [ -t tag_subdir ]
[ -s start_chg ] [ -m ] [ -r ] [ -M regex ]
[ -I <ignorefile_name> ] [ -A <author_file> ]
- [ -P <path_from_trunk> ]
+ [ -R <repack_each_revs>] [ -P <path_from_trunk> ]
<SVN_repository_URL> [ <path> ]
@@ -108,6 +108,14 @@ repository without -A.
Formerly, this option controlled how many revisions to pull,
due to SVN memory leaks. (These have been worked around.)
+-R <repack_each_revs>::
+ Specify how often git repository should be repacked.
++
+The default value is 1000. git-svnimport will do import in chunks of 1000
+revisions, after each chunk git repository will be repacked. To disable
+this behavior specify some big value here which is mote than number of
+revisions to import.
+
-P <path_from_trunk>::
Partial import of the SVN tree.
+
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 48b82b86f8..80bece0775 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -9,7 +9,7 @@ git-tag - Create a tag object signed with GPG
SYNOPSIS
--------
[verse]
-'git-tag' [-a | -s | -u <key-id>] [-f | -d] [-m <msg> | -F <file>]
+'git-tag' [-a | -s | -u <key-id>] [-f | -d | -v] [-m <msg> | -F <file>]
<name> [<head>]
'git-tag' -l [<pattern>]
@@ -35,6 +35,8 @@ GnuPG key for signing.
`-d <tag>` deletes the tag.
+`-v <tag>` verifies the gpg signature of the tag.
+
`-l <pattern>` lists tags that match the given pattern (or all
if no pattern is given).
@@ -55,6 +57,9 @@ OPTIONS
-d::
Delete an existing tag with the given name
+-v::
+ Verify the gpg signature of given the tag
+
-l <pattern>::
List tags that match the given pattern (or all if no pattern is given).
diff --git a/Documentation/glossary.txt b/Documentation/glossary.txt
index 894883d7b6..7c1a6592c1 100644
--- a/Documentation/glossary.txt
+++ b/Documentation/glossary.txt
@@ -188,11 +188,12 @@ octopus::
predator.
origin::
- The default upstream tracking branch. Most projects have at
+ The default upstream repository. Most projects have at
least one upstream project which they track. By default
'origin' is used for that purpose. New upstream updates
- will be fetched into this branch; you should never commit
- to it yourself.
+ will be fetched into remote tracking branches named
+ origin/name-of-upstream-branch, which you can see using
+ "git branch -r".
pack::
A set of objects which have been compressed into one file (to save
diff --git a/Documentation/hooks.txt b/Documentation/hooks.txt
index 517f49b5cc..161123f142 100644
--- a/Documentation/hooks.txt
+++ b/Documentation/hooks.txt
@@ -126,9 +126,9 @@ Another use suggested on the mailing list is to use this hook to
implement access control which is finer grained than the one
based on filesystem group.
-The standard output of this hook is sent to `/dev/null`; if you
+The standard output of this hook is sent to `stderr`, so if you
want to report something to the `git-send-pack` on the other end,
-you can redirect your output to your `stderr`.
+you can simply `echo` your messages.
post-update
diff --git a/Documentation/pull-fetch-param.txt b/Documentation/pull-fetch-param.txt
index e852f41a32..8d4e950abc 100644
--- a/Documentation/pull-fetch-param.txt
+++ b/Documentation/pull-fetch-param.txt
@@ -39,10 +39,6 @@ checkout -b my-B remote-B`). Run `git fetch` to keep track of
the progress of the remote side, and when you see something new
on the remote branch, merge it into your development branch with
`git pull . remote-B`, while you are on `my-B` branch.
-The common `Pull: master:origin` mapping of a remote `master`
-branch to a local `origin` branch, which is then merged to a
-local development branch, again typically named `master`, is made
-when you run `git clone` for you to follow this pattern.
+
[NOTE]
There is a difference between listing multiple <refspec>
diff --git a/Documentation/technical/send-pack-pipeline.txt b/Documentation/technical/send-pack-pipeline.txt
new file mode 100644
index 0000000000..681efe4219
--- /dev/null
+++ b/Documentation/technical/send-pack-pipeline.txt
@@ -0,0 +1,63 @@
+git-send-pack
+=============
+
+Overall operation
+-----------------
+
+. Connects to the remote side and invokes git-receive-pack.
+
+. Learns what refs the remote has and what commit they point at.
+ Matches them to the refspecs we are pushing.
+
+. Checks if there are non-fast-forwards. Unlike fetch-pack,
+ the repository send-pack runs in is supposed to be a superset
+ of the recipient in fast-forward cases, so there is no need
+ for want/have exchanges, and fast-forward check can be done
+ locally. Tell the result to the other end.
+
+. Calls pack_objects() which generates a packfile and sends it
+ over to the other end.
+
+. If the remote side is new enough (v1.1.0 or later), wait for
+ the unpack and hook status from the other end.
+
+. Exit with appropriate error codes.
+
+
+Pack_objects pipeline
+---------------------
+
+This function gets one file descriptor (`fd`) which is either a
+socket (over the network) or a pipe (local). What's written to
+this fd goes to git-receive-pack to be unpacked.
+
+ send-pack ---> fd ---> receive-pack
+
+The function pack_objects creates a pipe and then forks. The
+forked child execs pack-objects with --revs to receive revision
+parameters from its standard input. This process will write the
+packfile to the other end.
+
+ send-pack
+ |
+ pack_objects() ---> fd ---> receive-pack
+ | ^ (pipe)
+ v |
+ (child)
+
+The child dup2's to arrange its standard output to go back to
+the other end, and read its standard input to come from the
+pipe. After that it exec's pack-objects. On the other hand,
+the parent process, before starting to feed the child pipeline,
+closes the reading side of the pipe and fd to receive-pack.
+
+ send-pack
+ |
+ pack_objects(parent)
+ |
+ v [0]
+ pack-objects [0] ---> receive-pack
+
+
+[jc: the pipeline was much more complex and needed documentation before
+ I understood an earlier bug, but now it is trivial and straightforward.]
diff --git a/Documentation/tutorial.txt b/Documentation/tutorial.txt
index cb808d924b..01d4a47a97 100644
--- a/Documentation/tutorial.txt
+++ b/Documentation/tutorial.txt
@@ -43,8 +43,7 @@ Initialized empty Git repository in .git/
You've now initialized the working directory--you may notice a new
directory created, named ".git". Tell git that you want it to track
-every file under the current directory with (notice the dot '.'
-that means the current directory):
+every file under the current directory (note the '.') with:
------------------------------------------------
$ git add .
@@ -59,32 +58,40 @@ $ git commit
will prompt you for a commit message, then record the current state
of all the files to the repository.
+Making changes
+--------------
+
Try modifying some files, then run
------------------------------------------------
$ git diff
------------------------------------------------
-to review your changes. When you're done,
+to review your changes. When you're done, tell git that you
+want the updated contents of these files in the commit and then
+make a commit, like this:
------------------------------------------------
-$ git commit file1 file2...
+$ git add file1 file2 file3
+$ git commit
------------------------------------------------
-will again prompt your for a message describing the change, and then
-record the new versions of the files you listed. It is cumbersome
-to list all files and you can say `-a` (which stands for 'all')
-instead.
+This will again prompt your for a message describing the change, and then
+record the new versions of the files you listed.
+
+Alternatively, instead of running `git add` beforehand, you can use
------------------------------------------------
$ git commit -a
------------------------------------------------
+which will automatically notice modified (but not new) files.
+
A note on commit messages: Though not required, it's a good idea to
begin the commit message with a single short (less than 50 character)
line summarizing the change, followed by a blank line and then a more
thorough description. Tools that turn commits into email, for
-example, use the first line on the Subject line and the rest of the
+example, use the first line on the Subject: line and the rest of the
commit in the body.
@@ -142,6 +149,13 @@ If you also want to see complete diffs at each step, use
$ git log -p
------------------------------------------------
+Often the overview of the change is useful to get a feel of
+each step
+
+------------------------------------------------
+$ git log --stat --summary
+------------------------------------------------
+
Managing branches
-----------------
@@ -222,6 +236,15 @@ $ gitk
will show a nice graphical representation of the resulting history.
+At this point you could delete the experimental branch with
+
+------------------------------------------------
+$ git branch -d experimental
+------------------------------------------------
+
+This command ensures that the changes in the experimental branch are
+already in the current branch.
+
If you develop on a branch crazy-idea, then regret it, you can always
delete the branch with
@@ -323,20 +346,25 @@ $ git pull
Note that he doesn't need to give the path to Alice's repository;
when Bob cloned Alice's repository, git stored the location of her
-repository in the file .git/remotes/origin, and that location is used
-as the default for pulls.
-
-Bob may also notice a branch in his repository that he didn't create:
+repository in the repository configuration, and that location is
+used for pulls:
-------------------------------------
-$ git branch
-* master
- origin
+$ git repo-config --get remote.origin.url
+/home/bob/myrepo
-------------------------------------
-The "origin" branch, which was created automatically by "git clone",
-is a pristine copy of Alice's master branch; Bob should never commit
-to it.
+(The complete configuration created by git-clone is visible using
+"git repo-config -l", and the gitlink:git-repo-config[1] man page
+explains the meaning of each option.)
+
+Git also keeps a pristine copy of Alice's master branch under the
+name "origin/master":
+
+-------------------------------------
+$ git branch -r
+ origin/master
+-------------------------------------
If Bob later decides to work from a different host, he can still
perform clones and pulls using the ssh protocol:
@@ -376,7 +404,7 @@ commit.
$ git show c82a22c39cbc32576f64f5c6b3f24b99ea8149c7
-------------------------------------
-But there other ways to refer to commits. You can use any initial
+But there are other ways to refer to commits. You can use any initial
part of the name that is long enough to uniquely identify the commit:
-------------------------------------
@@ -386,8 +414,8 @@ $ git show HEAD # the tip of the current branch
$ git show experimental # the tip of the "experimental" branch
-------------------------------------
-Every commit has at least one "parent" commit, which points to the
-previous state of the project:
+Every commit usually has one "parent" commit
+which points to the previous state of the project:
-------------------------------------
$ git show HEAD^ # to see the parent of HEAD
@@ -505,10 +533,10 @@ of the file:
$ git diff v2.5:Makefile HEAD:Makefile.in
-------------------------------------
-You can also use "git cat-file -p" to see any such file:
+You can also use "git show" to see any such file:
-------------------------------------
-$ git cat-file -p v2.5:Makefile
+$ git show v2.5:Makefile
-------------------------------------
Next Steps
diff --git a/Documentation/urls.txt b/Documentation/urls.txt
index 870c95073b..745f9677d0 100644
--- a/Documentation/urls.txt
+++ b/Documentation/urls.txt
@@ -41,9 +41,10 @@ file in `$GIT_DIR/remotes` directory can be given; the
named file should be in the following format:
------------
-URL: one of the above URL format
-Push: <refspec>
-Pull: <refspec>
+ URL: one of the above URL format
+ Push: <refspec>
+ Pull: <refspec>
+
------------
Then such a short-hand is specified in place of
@@ -57,10 +58,11 @@ Or, equivalently, in the `$GIT_DIR/config` (note the use
of `fetch` instead of `Pull:`):
------------
-[remote "<remote>"]
- url = <url>
- push = <refspec>
- fetch = <refspec>
+ [remote "<remote>"]
+ url = <url>
+ push = <refspec>
+ fetch = <refspec>
+
------------
The name of a file in `$GIT_DIR/branches` directory can be
@@ -73,14 +75,14 @@ without the fragment is equivalent to have this in the
corresponding file in the `$GIT_DIR/remotes/` directory.
------------
-URL: <url>
-Pull: refs/heads/master:<remote>
-------------
+ URL: <url>
+ Pull: refs/heads/master:<remote>
+------------
while having `<url>#<head>` is equivalent to
------------
-URL: <url>
-Pull: refs/heads/<head>:<remote>
+ URL: <url>
+ Pull: refs/heads/<head>:<remote>
------------
diff --git a/Makefile b/Makefile
index fa1a02289c..5c712b94c1 100644
--- a/Makefile
+++ b/Makefile
@@ -179,7 +179,7 @@ SCRIPT_SH = \
SCRIPT_PERL = \
git-add--interactive.perl \
git-archimport.perl git-cvsimport.perl git-relink.perl \
- git-cvsserver.perl \
+ git-cvsserver.perl git-remote.perl \
git-svnimport.perl git-cvsexportcommit.perl \
git-send-email.perl git-svn.perl
@@ -818,7 +818,7 @@ test-sha1$X: test-sha1.o $(GITLIBS)
check-sha1:: test-sha1$X
./test-sha1.sh
-check:
+check: common-cmds.h
for i in *.c; do sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; done
diff --git a/archive-tar.c b/archive-tar.c
index af47fdc955..7d52a061f4 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -15,7 +15,7 @@ static char block[BLOCKSIZE];
static unsigned long offset;
static time_t archive_time;
-static int tar_umask;
+static int tar_umask = 002;
static int verbose;
/* writes out the whole block, but only if it is full */
@@ -210,11 +210,10 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,
sprintf(header.size, "%011lo", S_ISREG(mode) ? size : 0);
sprintf(header.mtime, "%011lo", archive_time);
- /* XXX: should we provide more meaningful info here? */
sprintf(header.uid, "%07o", 0);
sprintf(header.gid, "%07o", 0);
- strlcpy(header.uname, "git", sizeof(header.uname));
- strlcpy(header.gname, "git", sizeof(header.gname));
+ strlcpy(header.uname, "root", sizeof(header.uname));
+ strlcpy(header.gname, "root", sizeof(header.gname));
sprintf(header.devmajor, "%07o", 0);
sprintf(header.devminor, "%07o", 0);
diff --git a/builtin-branch.c b/builtin-branch.c
index 745ee04d6e..d3df5a57f1 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -12,7 +12,7 @@
#include "builtin.h"
static const char builtin_branch_usage[] =
- "git-branch [-r] (-d | -D) <branchname> | [-l] [-f] <branchname> [<start-point>] | (-m | -M) [<oldbranch>] <newbranch> | [-r | -a] [-v [--abbrev=<length>]]";
+ "git-branch [-r] (-d | -D) <branchname> | [-l] [-f] <branchname> [<start-point>] | (-m | -M) [<oldbranch>] <newbranch> | [--color | --no-color] [-r | -a] [-v [--abbrev=<length>]]";
#define REF_UNKNOWN_TYPE 0x00
#define REF_LOCAL_BRANCH 0x01
@@ -231,29 +231,54 @@ static int ref_cmp(const void *r1, const void *r2)
return strcmp(c1->name, c2->name);
}
-static void print_ref_info(const unsigned char *sha1, int abbrev)
+static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
+ int abbrev, int current)
{
+ char c;
+ int color;
struct commit *commit;
char subject[256];
+ switch (item->kind) {
+ case REF_LOCAL_BRANCH:
+ color = COLOR_BRANCH_LOCAL;
+ break;
+ case REF_REMOTE_BRANCH:
+ color = COLOR_BRANCH_REMOTE;
+ break;
+ default:
+ color = COLOR_BRANCH_PLAIN;
+ break;
+ }
- commit = lookup_commit(sha1);
- if (commit && !parse_commit(commit))
- pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,
- subject, sizeof(subject), 0,
- NULL, NULL, 0);
- else
- strcpy(subject, " **** invalid ref ****");
+ c = ' ';
+ if (current) {
+ c = '*';
+ color = COLOR_BRANCH_CURRENT;
+ }
- printf(" %s %s\n", find_unique_abbrev(sha1, abbrev), subject);
+ if (verbose) {
+ commit = lookup_commit(item->sha1);
+ if (commit && !parse_commit(commit))
+ pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,
+ subject, sizeof(subject), 0,
+ NULL, NULL, 0);
+ else
+ strcpy(subject, " **** invalid ref ****");
+ printf("%c %s%-*s%s %s %s\n", c, branch_get_color(color),
+ maxwidth, item->name,
+ branch_get_color(COLOR_BRANCH_RESET),
+ find_unique_abbrev(item->sha1, abbrev), subject);
+ } else {
+ printf("%c %s%s%s\n", c, branch_get_color(color), item->name,
+ branch_get_color(COLOR_BRANCH_RESET));
+ }
}
static void print_ref_list(int kinds, int verbose, int abbrev)
{
int i;
- char c;
struct ref_list ref_list;
- int color;
memset(&ref_list, 0, sizeof(ref_list));
ref_list.kinds = kinds;
@@ -262,38 +287,10 @@ static void print_ref_list(int kinds, int verbose, int abbrev)
qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp);
for (i = 0; i < ref_list.index; i++) {
- switch( ref_list.list[i].kind ) {
- case REF_LOCAL_BRANCH:
- color = COLOR_BRANCH_LOCAL;
- break;
- case REF_REMOTE_BRANCH:
- color = COLOR_BRANCH_REMOTE;
- break;
- default:
- color = COLOR_BRANCH_PLAIN;
- break;
- }
-
- c = ' ';
- if (ref_list.list[i].kind == REF_LOCAL_BRANCH &&
- !strcmp(ref_list.list[i].name, head)) {
- c = '*';
- color = COLOR_BRANCH_CURRENT;
- }
-
- if (verbose) {
- printf("%c %s%-*s%s", c,
- branch_get_color(color),
- ref_list.maxwidth,
- ref_list.list[i].name,
- branch_get_color(COLOR_BRANCH_RESET));
- print_ref_info(ref_list.list[i].sha1, abbrev);
- }
- else
- printf("%c %s%s%s\n", c,
- branch_get_color(color),
- ref_list.list[i].name,
- branch_get_color(COLOR_BRANCH_RESET));
+ int current = (ref_list.list[i].kind == REF_LOCAL_BRANCH) &&
+ !strcmp(ref_list.list[i].name, head);
+ print_ref_item(&ref_list.list[i], ref_list.maxwidth, verbose,
+ abbrev, current);
}
free_ref_list(&ref_list);
diff --git a/builtin-prune.c b/builtin-prune.c
index 00a53b3647..b469c43bc5 100644
--- a/builtin-prune.c
+++ b/builtin-prune.c
@@ -253,6 +253,8 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
usage(prune_usage);
}
+ save_commit_buffer = 0;
+
/*
* Set up revision parsing, and mark us as being interested
* in all object types, not just commits.
diff --git a/builtin-rerere.c b/builtin-rerere.c
index 7442498dee..079c0bdf36 100644
--- a/builtin-rerere.c
+++ b/builtin-rerere.c
@@ -350,11 +350,10 @@ static int do_plain_rerere(struct path_list *rr, int fd)
fprintf(stderr, "Recorded resolution for '%s'.\n", path);
copy_file(path, rr_path(name, "postimage"));
tail_optimization:
- if (i < rr->nr - 1) {
+ if (i < rr->nr - 1)
memmove(rr->items + i,
- rr->items + i + 1,
- rr->nr - i - 1);
- }
+ rr->items + i + 1,
+ sizeof(rr->items[0]) * (rr->nr - i - 1));
rr->nr--;
i--;
}
diff --git a/cache.h b/cache.h
index a5fc23235e..36be64e386 100644
--- a/cache.h
+++ b/cache.h
@@ -179,6 +179,7 @@ extern int refresh_cache(unsigned int flags);
struct lock_file {
struct lock_file *next;
+ char on_list;
char filename[PATH_MAX];
};
extern int hold_lock_file_for_update(struct lock_file *, const char *path, int);
@@ -432,6 +433,7 @@ extern char *git_log_output_encoding;
extern int copy_fd(int ifd, int ofd);
extern void read_or_die(int fd, void *buf, size_t count);
+extern int write_in_full(int fd, const void *buf, size_t count, const char *);
extern void write_or_die(int fd, const void *buf, size_t count);
extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg);
diff --git a/commit.c b/commit.c
index afdf27eece..2a58175aca 100644
--- a/commit.c
+++ b/commit.c
@@ -679,11 +679,13 @@ static char *logmsg_reencode(const struct commit *commit)
else if (!*output_encoding)
return NULL;
encoding = get_header(commit, "encoding");
- if (!encoding || !strcmp(encoding, output_encoding)) {
- free(encoding);
+ if (!encoding)
return NULL;
- }
- out = reencode_string(commit->buffer, output_encoding, encoding);
+ if (!strcmp(encoding, output_encoding))
+ out = strdup(commit->buffer);
+ else
+ out = reencode_string(commit->buffer,
+ output_encoding, encoding);
if (out)
out = replace_encoding_header(out, output_encoding);
@@ -701,7 +703,7 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,
const char *after_subject,
int relative_date)
{
- int hdr = 1, body = 0;
+ int hdr = 1, body = 0, seen_title = 0;
unsigned long offset = 0;
int indent = 4;
int parents_shown = 0;
@@ -807,6 +809,8 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,
body = 1;
if (is_empty_line(line, &linelen)) {
+ if (!seen_title)
+ continue;
if (!body)
continue;
if (subject)
@@ -815,6 +819,7 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,
break;
}
+ seen_title = 1;
if (subject) {
int slen = strlen(subject);
memcpy(buf + offset, subject, slen);
diff --git a/contrib/emacs/git.el b/contrib/emacs/git.el
index 972c402ea0..ede3ab2bd8 100644
--- a/contrib/emacs/git.el
+++ b/contrib/emacs/git.el
@@ -49,6 +49,7 @@
(eval-when-compile (require 'cl))
(require 'ewoc)
+(require 'log-edit)
;;;; Customizations
@@ -147,6 +148,13 @@ if there is already one that displays the same directory."
(defconst git-log-msg-separator "--- log message follows this line ---")
+(defvar git-log-edit-font-lock-keywords
+ `(("^\\(Author:\\|Date:\\|Parent:\\|Signed-off-by:\\)\\(.*\\)$"
+ (1 font-lock-keyword-face)
+ (2 font-lock-function-name-face))
+ (,(concat "^\\(" (regexp-quote git-log-msg-separator) "\\)$")
+ (1 font-lock-comment-face))))
+
(defun git-get-env-strings (env)
"Build a list of NAME=VALUE strings from a list of environment strings."
(mapcar (lambda (entry) (concat (car entry) "=" (cdr entry))) env))
@@ -777,7 +785,7 @@ and returns the process output as a string."
(interactive)
(let ((files (git-marked-files-state 'unmerged)))
(when files
- (apply #'git-run-command nil nil "update-index" "--info-only" "--" (git-get-filenames files))
+ (apply #'git-run-command nil nil "update-index" "--" (git-get-filenames files))
(git-set-files-state files 'modified)
(git-refresh-files))))
@@ -894,14 +902,9 @@ and returns the process output as a string."
(sign-off
(insert (format "\n\nSigned-off-by: %s <%s>\n"
(git-get-committer-name) (git-get-committer-email)))))))
- (let ((log-edit-font-lock-keywords
- `(("^\\(Author:\\|Date:\\|Parent:\\|Signed-off-by:\\)\\(.*\\)"
- (1 font-lock-keyword-face)
- (2 font-lock-function-name-face))
- (,(concat "^\\(" (regexp-quote git-log-msg-separator) "\\)$")
- (1 font-lock-comment-face)))))
- (log-edit #'git-do-commit nil #'git-log-edit-files buffer)
- (re-search-forward (regexp-quote (concat git-log-msg-separator "\n")) nil t))))
+ (log-edit #'git-do-commit nil #'git-log-edit-files buffer)
+ (setq font-lock-keywords (font-lock-compile-keywords git-log-edit-font-lock-keywords))
+ (re-search-forward (regexp-quote (concat git-log-msg-separator "\n")) nil t)))
(defun git-find-file ()
"Visit the current file in its own buffer."
diff --git a/diff-lib.c b/diff-lib.c
index fc69fb92a5..2c9be60ed9 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -97,7 +97,7 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed)
* Show the diff for the 'ce' if we found the one
* from the desired stage.
*/
- diff_unmerge(&revs->diffopt, ce->name);
+ diff_unmerge(&revs->diffopt, ce->name, 0, null_sha1);
if (ce_stage(ce) != diff_unmerged_stage)
continue;
}
@@ -297,9 +297,12 @@ static int diff_cache(struct rev_info *revs,
!show_modified(revs, ce, ac[1], 0,
cached, match_missing))
break;
- /* fallthru */
+ diff_unmerge(&revs->diffopt, ce->name,
+ ntohl(ce->ce_mode), ce->sha1);
+ break;
case 3:
- diff_unmerge(&revs->diffopt, ce->name);
+ diff_unmerge(&revs->diffopt, ce->name,
+ 0, null_sha1);
break;
default:
diff --git a/diff.c b/diff.c
index 244292a70c..e1b016f47f 100644
--- a/diff.c
+++ b/diff.c
@@ -2873,10 +2873,12 @@ void diff_change(struct diff_options *options,
}
void diff_unmerge(struct diff_options *options,
- const char *path)
+ const char *path,
+ unsigned mode, const unsigned char *sha1)
{
struct diff_filespec *one, *two;
one = alloc_filespec(path);
two = alloc_filespec(path);
- diff_queue(&diff_queued_diff, one, two);
+ fill_filespec(one, sha1, mode);
+ diff_queue(&diff_queued_diff, one, two)->is_unmerged = 1;
}
diff --git a/diff.h b/diff.h
index eff445596d..7a347cf77d 100644
--- a/diff.h
+++ b/diff.h
@@ -144,7 +144,9 @@ extern void diff_change(struct diff_options *,
const char *base, const char *path);
extern void diff_unmerge(struct diff_options *,
- const char *path);
+ const char *path,
+ unsigned mode,
+ const unsigned char *sha1);
extern int diff_scoreopt_parse(const char *opt);
diff --git a/diffcore.h b/diffcore.h
index 2249bc2c05..1ea80671e3 100644
--- a/diffcore.h
+++ b/diffcore.h
@@ -54,9 +54,9 @@ struct diff_filepair {
unsigned source_stays : 1; /* all of R/C are copies */
unsigned broken_pair : 1;
unsigned renamed_pair : 1;
+ unsigned is_unmerged : 1;
};
-#define DIFF_PAIR_UNMERGED(p) \
- (!DIFF_FILE_VALID((p)->one) && !DIFF_FILE_VALID((p)->two))
+#define DIFF_PAIR_UNMERGED(p) ((p)->is_unmerged)
#define DIFF_PAIR_RENAME(p) ((p)->renamed_pair)
diff --git a/fetch-pack.c b/fetch-pack.c
index c527bf9e96..1530a94794 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -625,6 +625,8 @@ static int remove_duplicates(int nr_heads, char **heads)
return dst;
}
+static struct lock_file lock;
+
int main(int argc, char **argv)
{
int i, ret, nr_heads;
@@ -632,7 +634,6 @@ int main(int argc, char **argv)
int fd[2];
pid_t pid;
struct stat st;
- struct lock_file lock;
setup_git_directory();
diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh
index 06c42b042d..1de14ea82f 100755
--- a/generate-cmdlist.sh
+++ b/generate-cmdlist.sh
@@ -37,7 +37,6 @@ show
show-branch
status
tag
-verify-tag
EOF
while read cmd
do
diff --git a/git-am.sh b/git-am.sh
index c3bbd78eab..7c0bb6084b 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -88,10 +88,12 @@ It does not apply to blobs recorded in its index."
# This is not so wrong. Depending on which base we picked,
# orig_tree may be wildly different from ours, but his_tree
# has the same set of wildly different changes in parts the
- # patch did not touch, so resolve ends up canceling them,
+ # patch did not touch, so recursive ends up canceling them,
# saying that we reverted all those changes.
- git-merge-resolve $orig_tree -- HEAD $his_tree || {
+ eval GITHEAD_$his_tree='"$SUBJECT"'
+ export GITHEAD_$his_tree
+ git-merge-recursive $orig_tree -- HEAD $his_tree || {
if test -d "$GIT_DIR/rr-cache"
then
git-rerere
@@ -99,6 +101,7 @@ It does not apply to blobs recorded in its index."
echo Failed to merge in the changes.
exit 1
}
+ unset GITHEAD_$his_tree
}
prec=4
diff --git a/git-clean.sh b/git-clean.sh
index 3834323bcf..071b974f49 100755
--- a/git-clean.sh
+++ b/git-clean.sh
@@ -18,7 +18,6 @@ SUBDIRECTORY_OK=Yes
ignored=
ignoredonly=
cleandir=
-quiet=
rmf="rm -f --"
rmrf="rm -rf --"
rm_refuse="echo Not removing"
@@ -31,14 +30,13 @@ do
cleandir=1
;;
-n)
- quiet=1
rmf="echo Would remove"
rmrf="echo Would remove"
rm_refuse="echo Would not remove"
echo1=":"
;;
-q)
- quiet=1
+ echo1=":"
;;
-x)
ignored=1
diff --git a/git-commit.sh b/git-commit.sh
index 6bce41af4d..04aad5e5da 100755
--- a/git-commit.sh
+++ b/git-commit.sh
@@ -8,7 +8,6 @@ SUBDIRECTORY_OK=Yes
. git-sh-setup
git-rev-parse --verify HEAD >/dev/null 2>&1 || initial_commit=t
-branch=$(GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD)
case "$0" in
*status)
diff --git a/git-fetch.sh b/git-fetch.sh
index 8bd11f8b60..466fe59e35 100755
--- a/git-fetch.sh
+++ b/git-fetch.sh
@@ -382,13 +382,22 @@ fetch_main () {
;; # we are already done.
*)
( : subshell because we muck with IFS
- pack_lockfile=
IFS=" $LF"
(
- git-fetch-pack --thin $exec $keep $shallow_depth "$remote" $rref || echo failed "$remote"
+ git-fetch-pack --thin $exec $keep $shallow_depth "$remote" $rref ||
+ echo failed "$remote"
) |
- while read sha1 remote_name
- do
+ (
+ trap '
+ if test -n "$keepfile" && test -f "$keepfile"
+ then
+ rm -f "$keepfile"
+ fi
+ ' 0
+
+ keepfile=
+ while read sha1 remote_name
+ do
case "$sha1" in
failed)
echo >&2 "Fetch failure: $remote"
@@ -397,7 +406,7 @@ fetch_main () {
pack)
continue ;;
keep)
- pack_lockfile="$GIT_OBJECT_DIRECTORY/pack/pack-$remote_name.keep"
+ keepfile="$GIT_OBJECT_DIRECTORY/pack/pack-$remote_name.keep"
continue ;;
esac
found=
@@ -429,8 +438,8 @@ fetch_main () {
append_fetch_head "$sha1" "$remote" \
"$remote_name" "$remote_nick" "$local_name" \
"$not_for_merge" || exit
- done &&
- if [ "$pack_lockfile" ]; then rm -f "$pack_lockfile"; fi
+ done
+ )
) || exit ;;
esac
diff --git a/git-instaweb.sh b/git-instaweb.sh
index 16cd351f7f..80adc8307b 100755
--- a/git-instaweb.sh
+++ b/git-instaweb.sh
@@ -53,6 +53,9 @@ start_httpd () {
return
fi
done
+ echo "$httpd_only not found. Install $httpd_only or use" \
+ "--httpd to specify another http daemon."
+ exit 1
fi
if test $? != 0; then
echo "Could not execute http daemon $httpd."
@@ -160,10 +163,20 @@ apache2_conf () {
test "$local" = true && bind='127.0.0.1:'
echo 'text/css css' > $fqgitdir/mime.types
cat > "$conf" <<EOF
+ServerName "git-instaweb"
ServerRoot "$fqgitdir/gitweb"
DocumentRoot "$fqgitdir/gitweb"
PidFile "$fqgitdir/pid"
Listen $bind$port
+EOF
+
+ for mod in mime dir; do
+ if test -e $module_path/mod_${mod}.so; then
+ echo "LoadModule ${mod}_module " \
+ "$module_path/mod_${mod}.so" >> "$conf"
+ fi
+ done
+ cat >> "$conf" <<EOF
TypesConfig $fqgitdir/mime.types
DirectoryIndex gitweb.cgi
EOF
diff --git a/git-merge.sh b/git-merge.sh
index ba42260426..477002910e 100755
--- a/git-merge.sh
+++ b/git-merge.sh
@@ -8,6 +8,9 @@ USAGE='[-n] [--no-commit] [--squash] [-s <strategy>] [-m=<merge-message>] <commi
. git-sh-setup
set_reflog_action "merge $*"
+test -z "$(git ls-files -u)" ||
+ die "You are in a middle of conflicted merge."
+
LF='
'
diff --git a/git-parse-remote.sh b/git-parse-remote.sh
index 144f170155..d2e4c2b9ae 100755
--- a/git-parse-remote.sh
+++ b/git-parse-remote.sh
@@ -76,16 +76,32 @@ get_remote_default_refs_for_push () {
# from get_remote_refs_for_fetch when it deals with refspecs
# supplied on the command line. $ls_remote_result has the list
# of refs available at remote.
+#
+# The first token returned is either "explicit" or "glob"; this
+# is to help prevent randomly "globbed" ref from being chosen as
+# a merge candidate
expand_refs_wildcard () {
+ first_one=yes
for ref
do
lref=${ref#'+'}
# a non glob pattern is given back as-is.
expr "z$lref" : 'zrefs/.*/\*:refs/.*/\*$' >/dev/null || {
+ if test -n "$first_one"
+ then
+ echo "explicit"
+ first_one=
+ fi
echo "$ref"
continue
}
+ # glob
+ if test -n "$first_one"
+ then
+ echo "glob"
+ first_one=
+ fi
from=`expr "z$lref" : 'z\(refs/.*/\)\*:refs/.*/\*$'`
to=`expr "z$lref" : 'zrefs/.*/\*:\(refs/.*/\)\*$'`
local_force=
@@ -116,7 +132,8 @@ canon_refs_list_for_fetch () {
if test "$1" = "-d"
then
shift ; remote="$1" ; shift
- set x $(expand_refs_wildcard "$@")
+ set $(expand_refs_wildcard "$@")
+ is_explicit="$1"
shift
if test "$remote" = "$(get_default_remote)"
then
@@ -125,6 +142,10 @@ canon_refs_list_for_fetch () {
merge_branches=$(git-repo-config \
--get-all "branch.${curr_branch}.merge")
fi
+ if test -z "$merge_branches" && test $is_explicit != explicit
+ then
+ merge_branches=..this.will.never.match.any.ref..
+ fi
fi
for ref
do
diff --git a/git-pull.sh b/git-pull.sh
index 28d08195f0..c184fb81a4 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -9,6 +9,9 @@ LONG_USAGE='Fetch one or more remote refs and merge it/them into the current HEA
. git-sh-setup
set_reflog_action "pull $*"
+test -z "$(git ls-files -u)" ||
+ die "You are in a middle of conflicted merge."
+
strategy_args= no_summary= no_commit= squash=
while case "$#,$1" in 0) break ;; *,-*) ;; *) break ;; esac
do
diff --git a/git-remote.perl b/git-remote.perl
new file mode 100755
index 0000000000..059c141b68
--- /dev/null
+++ b/git-remote.perl
@@ -0,0 +1,277 @@
+#!/usr/bin/perl -w
+
+use Git;
+my $git = Git->repository();
+
+sub add_remote_config {
+ my ($hash, $name, $what, $value) = @_;
+ if ($what eq 'url') {
+ if (exists $hash->{$name}{'URL'}) {
+ print STDERR "Warning: more than one remote.$name.url\n";
+ }
+ $hash->{$name}{'URL'} = $value;
+ }
+ elsif ($what eq 'fetch') {
+ $hash->{$name}{'FETCH'} ||= [];
+ push @{$hash->{$name}{'FETCH'}}, $value;
+ }
+ if (!exists $hash->{$name}{'SOURCE'}) {
+ $hash->{$name}{'SOURCE'} = 'config';
+ }
+}
+
+sub add_remote_remotes {
+ my ($hash, $file, $name) = @_;
+
+ if (exists $hash->{$name}) {
+ $hash->{$name}{'WARNING'} = 'ignored due to config';
+ return;
+ }
+
+ my $fh;
+ if (!open($fh, '<', $file)) {
+ print STDERR "Warning: cannot open $file\n";
+ return;
+ }
+ my $it = { 'SOURCE' => 'remotes' };
+ $hash->{$name} = $it;
+ while (<$fh>) {
+ chomp;
+ if (/^URL:\s*(.*)$/) {
+ # Having more than one is Ok -- it is used for push.
+ if (! exists $it->{'URL'}) {
+ $it->{'URL'} = $1;
+ }
+ }
+ elsif (/^Push:\s*(.*)$/) {
+ ; # later
+ }
+ elsif (/^Pull:\s*(.*)$/) {
+ $it->{'FETCH'} ||= [];
+ push @{$it->{'FETCH'}}, $1;
+ }
+ elsif (/^\#/) {
+ ; # ignore
+ }
+ else {
+ print STDERR "Warning: funny line in $file: $_\n";
+ }
+ }
+ close($fh);
+}
+
+sub list_remote {
+ my ($git) = @_;
+ my %seen = ();
+ my @remotes = eval {
+ $git->command(qw(repo-config --get-regexp), '^remote\.');
+ };
+ for (@remotes) {
+ if (/^remote\.([^.]*)\.(\S*)\s+(.*)$/) {
+ add_remote_config(\%seen, $1, $2, $3);
+ }
+ }
+
+ my $dir = $git->repo_path() . "/remotes";
+ if (opendir(my $dh, $dir)) {
+ local $_;
+ while ($_ = readdir($dh)) {
+ chomp;
+ next if (! -f "$dir/$_" || ! -r _);
+ add_remote_remotes(\%seen, "$dir/$_", $_);
+ }
+ }
+
+ return \%seen;
+}
+
+sub add_branch_config {
+ my ($hash, $name, $what, $value) = @_;
+ if ($what eq 'remote') {
+ if (exists $hash->{$name}{'REMOTE'}) {
+ print STDERR "Warning: more than one branch.$name.remote\n";
+ }
+ $hash->{$name}{'REMOTE'} = $value;
+ }
+ elsif ($what eq 'merge') {
+ $hash->{$name}{'MERGE'} ||= [];
+ push @{$hash->{$name}{'MERGE'}}, $value;
+ }
+}
+
+sub list_branch {
+ my ($git) = @_;
+ my %seen = ();
+ my @branches = eval {
+ $git->command(qw(repo-config --get-regexp), '^branch\.');
+ };
+ for (@branches) {
+ if (/^branch\.([^.]*)\.(\S*)\s+(.*)$/) {
+ add_branch_config(\%seen, $1, $2, $3);
+ }
+ }
+
+ return \%seen;
+}
+
+my $remote = list_remote($git);
+my $branch = list_branch($git);
+
+sub update_ls_remote {
+ my ($harder, $info) = @_;
+
+ return if (($harder == 0) ||
+ (($harder == 1) && exists $info->{'LS_REMOTE'}));
+
+ my @ref = map {
+ s|^[0-9a-f]{40}\s+refs/heads/||;
+ $_;
+ } $git->command(qw(ls-remote --heads), $info->{'URL'});
+ $info->{'LS_REMOTE'} = \@ref;
+}
+
+sub show_wildcard_mapping {
+ my ($forced, $ours, $ls) = @_;
+ my %refs;
+ for (@$ls) {
+ $refs{$_} = 01; # bit #0 to say "they have"
+ }
+ for ($git->command('for-each-ref', "refs/remotes/$ours")) {
+ chomp;
+ next unless (s|^[0-9a-f]{40}\s[a-z]+\srefs/remotes/$ours/||);
+ next if ($_ eq 'HEAD');
+ $refs{$_} ||= 0;
+ $refs{$_} |= 02; # bit #1 to say "we have"
+ }
+ my (@new, @stale, @tracked);
+ for (sort keys %refs) {
+ my $have = $refs{$_};
+ if ($have == 1) {
+ push @new, $_;
+ }
+ elsif ($have == 2) {
+ push @stale, $_;
+ }
+ elsif ($have == 3) {
+ push @tracked, $_;
+ }
+ }
+ if (@new) {
+ print " New remote branches (next fetch will store in remotes/$ours)\n";
+ print " @new\n";
+ }
+ if (@stale) {
+ print " Stale tracking branches in remotes/$ours (you'd better remove them)\n";
+ print " @stale\n";
+ }
+ if (@tracked) {
+ print " Tracked remote branches\n";
+ print " @tracked\n";
+ }
+}
+
+sub show_mapping {
+ my ($name, $info) = @_;
+ my $fetch = $info->{'FETCH'};
+ my $ls = $info->{'LS_REMOTE'};
+ my (@stale, @tracked);
+
+ for (@$fetch) {
+ next unless (/(\+)?([^:]+):(.*)/);
+ my ($forced, $theirs, $ours) = ($1, $2, $3);
+ if ($theirs eq 'refs/heads/*' &&
+ $ours =~ /^refs\/remotes\/(.*)\/\*$/) {
+ # wildcard mapping
+ show_wildcard_mapping($forced, $1, $ls);
+ }
+ elsif ($theirs =~ /\*/ || $ours =~ /\*/) {
+ print STDERR "Warning: unrecognized mapping in remotes.$name.fetch: $_\n";
+ }
+ elsif ($theirs =~ s|^refs/heads/||) {
+ if (!grep { $_ eq $theirs } @$ls) {
+ push @stale, $theirs;
+ }
+ elsif ($ours ne '') {
+ push @tracked, $theirs;
+ }
+ }
+ }
+ if (@stale) {
+ print " Stale tracking branches in remotes/$name (you'd better remove them)\n";
+ print " @stale\n";
+ }
+ if (@tracked) {
+ print " Tracked remote branches\n";
+ print " @tracked\n";
+ }
+}
+
+sub show_remote {
+ my ($name, $ls_remote) = @_;
+ if (!exists $remote->{$name}) {
+ print STDERR "No such remote $name\n";
+ return;
+ }
+ my $info = $remote->{$name};
+ update_ls_remote($ls_remote, $info);
+
+ print "* remote $name\n";
+ print " URL: $info->{'URL'}\n";
+ for my $branchname (sort keys %$branch) {
+ next if ($branch->{$branchname}{'REMOTE'} ne $name);
+ my @merged = map {
+ s|^refs/heads/||;
+ $_;
+ } split(' ',"@{$branch->{$branchname}{'MERGE'}}");
+ next unless (@merged);
+ print " Remote branch(es) merged with 'git pull' while on branch $branchname\n";
+ print " @merged\n";
+ }
+ if ($info->{'LS_REMOTE'}) {
+ show_mapping($name, $info);
+ }
+}
+
+sub add_remote {
+ my ($name, $url) = @_;
+ if (exists $remote->{$name}) {
+ print STDERR "remote $name already exists.\n";
+ exit(1);
+ }
+ $git->command('repo-config', "remote.$name.url", $url);
+ $git->command('repo-config', "remote.$name.fetch",
+ "+refs/heads/*:refs/remotes/$name/*");
+}
+
+if (!@ARGV) {
+ for (sort keys %$remote) {
+ print "$_\n";
+ }
+}
+elsif ($ARGV[0] eq 'show') {
+ my $ls_remote = 1;
+ my $i;
+ for ($i = 1; $i < @ARGV; $i++) {
+ if ($ARGV[$i] eq '-n') {
+ $ls_remote = 0;
+ }
+ else {
+ last;
+ }
+ }
+ if ($i >= @ARGV) {
+ print STDERR "Usage: git remote show <remote>\n";
+ exit(1);
+ }
+ for (; $i < @ARGV; $i++) {
+ show_remote($ARGV[$i], $ls_remote);
+ }
+}
+elsif ($ARGV[0] eq 'add') {
+ if (@ARGV != 3) {
+ print STDERR "Usage: git remote add <name> <url>\n";
+ exit(1);
+ }
+ add_remote($ARGV[1], $ARGV[2]);
+}
+
diff --git a/git-reset.sh b/git-reset.sh
index a9693701a3..76c8a818d4 100755
--- a/git-reset.sh
+++ b/git-reset.sh
@@ -44,8 +44,10 @@ if test $# != 0
then
test "$reset_type" == "--mixed" ||
die "Cannot do partial $reset_type reset."
- git ls-tree -r --full-name $rev -- "$@" |
- git update-index --add --index-info || exit
+
+ git-diff-index --cached $rev -- "$@" |
+ sed -e 's/^:\([0-7][0-7]*\) [0-7][0-7]* \([0-9a-f][0-9a-f]*\) [0-9a-f][0-9a-f]* [A-Z] \(.*\)$/\1 \2 \3/' |
+ git update-index --add --remove --index-info || exit
git update-index --refresh
exit
fi
diff --git a/git-svn.perl b/git-svn.perl
index b28c5bbc72..1da31fdc7c 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -102,7 +102,7 @@ my %cmt_opts = ( 'edit|e' => \$_edit,
);
my %cmd = (
- fetch => [ \&fetch, "Download new revisions from SVN",
+ fetch => [ \&cmd_fetch, "Download new revisions from SVN",
{ 'revision|r=s' => \$_revision, %fc_opts } ],
init => [ \&init, "Initialize a repo for tracking" .
" (requires URL argument)",
@@ -293,6 +293,10 @@ sub init {
setup_git_svn();
}
+sub cmd_fetch {
+ fetch_child_id($GIT_SVN, @_);
+}
+
sub fetch {
check_upgrade_needed();
$SVN_URL ||= file_to_s("$GIT_SVN_DIR/info/url");
@@ -532,7 +536,7 @@ sub show_ignore {
my $repo;
$SVN ||= libsvn_connect($SVN_URL);
my $r = defined $_revision ? $_revision : $SVN->get_latest_revnum;
- libsvn_traverse_ignore(\*STDOUT, $SVN->{svn_path}, $r);
+ libsvn_traverse_ignore(\*STDOUT, '', $r);
}
sub graft_branches {
@@ -571,28 +575,25 @@ sub graft_branches {
sub multi_init {
my $url = shift;
- $_trunk ||= 'trunk';
- $_trunk =~ s#/+$##;
- $url =~ s#/+$## if $url;
- if ($_trunk !~ m#^[a-z\+]+://#) {
- $_trunk = '/' . $_trunk if ($_trunk !~ m#^/#);
- unless ($url) {
- print STDERR "E: '$_trunk' is not a complete URL ",
- "and a separate URL is not specified\n";
- exit 1;
- }
- $_trunk = $url . $_trunk;
+ unless (defined $_trunk || defined $_branches || defined $_tags) {
+ usage(1);
}
- my $ch_id;
- if ($GIT_SVN eq 'git-svn') {
- $ch_id = 1;
- $GIT_SVN = $ENV{GIT_SVN_ID} = 'trunk';
- }
- init_vars();
- unless (-d $GIT_SVN_DIR) {
- print "GIT_SVN_ID set to 'trunk' for $_trunk\n" if $ch_id;
- init($_trunk);
- command_noisy('repo-config', 'svn.trunk', $_trunk);
+ if (defined $_trunk) {
+ my $trunk_url = complete_svn_url($url, $_trunk);
+ my $ch_id;
+ if ($GIT_SVN eq 'git-svn') {
+ $ch_id = 1;
+ $GIT_SVN = $ENV{GIT_SVN_ID} = 'trunk';
+ }
+ init_vars();
+ unless (-d $GIT_SVN_DIR) {
+ if ($ch_id) {
+ print "GIT_SVN_ID set to 'trunk' for ",
+ "$trunk_url ($_trunk)\n";
+ }
+ init($trunk_url);
+ command_noisy('repo-config', 'svn.trunk', $trunk_url);
+ }
}
complete_url_ls_init($url, $_branches, '--branches/-b', '');
complete_url_ls_init($url, $_tags, '--tags/-t', 'tags/');
@@ -839,7 +840,6 @@ sub fetch_child_id {
my $ref = "$GIT_DIR/refs/remotes/$id";
defined(my $pid = open my $fh, '-|') or croak $!;
if (!$pid) {
- $_repack = undef;
$GIT_SVN = $ENV{GIT_SVN_ID} = $id;
init_vars();
fetch(@_);
@@ -847,7 +847,7 @@ sub fetch_child_id {
}
while (<$fh>) {
print $_;
- check_repack() if (/^r\d+ = $sha1/);
+ check_repack() if (/^r\d+ = $sha1/o);
}
close $fh or croak $?;
}
@@ -872,29 +872,34 @@ sub rec_fetch {
}
}
+sub complete_svn_url {
+ my ($url, $path) = @_;
+ $path =~ s#/+$##;
+ $url =~ s#/+$## if $url;
+ if ($path !~ m#^[a-z\+]+://#) {
+ $path = '/' . $path if ($path !~ m#^/#);
+ if (!defined $url || $url !~ m#^[a-z\+]+://#) {
+ fatal("E: '$path' is not a complete URL ",
+ "and a separate URL is not specified\n");
+ }
+ $path = $url . $path;
+ }
+ return $path;
+}
+
sub complete_url_ls_init {
- my ($url, $var, $switch, $pfx) = @_;
- unless ($var) {
+ my ($url, $path, $switch, $pfx) = @_;
+ unless ($path) {
print STDERR "W: $switch not specified\n";
return;
}
- $var =~ s#/+$##;
- if ($var !~ m#^[a-z\+]+://#) {
- $var = '/' . $var if ($var !~ m#^/#);
- unless ($url) {
- print STDERR "E: '$var' is not a complete URL ",
- "and a separate URL is not specified\n";
- exit 1;
- }
- $var = $url . $var;
- }
- my @ls = libsvn_ls_fullurl($var);
- my $old = $GIT_SVN;
+ my $full_url = complete_svn_url($url, $path);
+ my @ls = libsvn_ls_fullurl($full_url);
defined(my $pid = fork) or croak $!;
if (!$pid) {
- foreach my $u (map { "$var/$_" } (grep m!/$!, @ls)) {
+ foreach my $u (map { "$full_url/$_" } (grep m!/$!, @ls)) {
$u =~ s#/+$##;
- if ($u !~ m!\Q$var\E/(.+)$!) {
+ if ($u !~ m!\Q$full_url\E/(.+)$!) {
print STDERR "W: Unrecognized URL: $u\n";
die "This should never happen\n";
}
@@ -912,7 +917,7 @@ sub complete_url_ls_init {
waitpid $pid, 0;
croak $? if $?;
my ($n) = ($switch =~ /^--(\w+)/);
- command_noisy('repo-config', "svn.$n", $var);
+ command_noisy('repo-config', "svn.$n", $full_url);
}
sub common_prefix {
@@ -1405,7 +1410,6 @@ sub git_commit {
# this output is read via pipe, do not change:
print "r$log_msg->{revision} = $commit\n";
- check_repack();
return $commit;
}
diff --git a/git-svnimport.perl b/git-svnimport.perl
index cbaa8ab37c..afbbe63c62 100755
--- a/git-svnimport.perl
+++ b/git-svnimport.perl
@@ -31,12 +31,13 @@ $SIG{'PIPE'}="IGNORE";
$ENV{'TZ'}="UTC";
our($opt_h,$opt_o,$opt_v,$opt_u,$opt_C,$opt_i,$opt_m,$opt_M,$opt_t,$opt_T,
- $opt_b,$opt_r,$opt_I,$opt_A,$opt_s,$opt_l,$opt_d,$opt_D,$opt_S,$opt_F,$opt_P);
+ $opt_b,$opt_r,$opt_I,$opt_A,$opt_s,$opt_l,$opt_d,$opt_D,$opt_S,$opt_F,
+ $opt_P,$opt_R);
sub usage() {
print STDERR <<END;
Usage: ${\basename $0} # fetch/update GIT from SVN
- [-o branch-for-HEAD] [-h] [-v] [-l max_rev]
+ [-o branch-for-HEAD] [-h] [-v] [-l max_rev] [-R repack_each_revs]
[-C GIT_repository] [-t tagname] [-T trunkname] [-b branchname]
[-d|-D] [-i] [-u] [-r] [-I ignorefilename] [-s start_chg]
[-m] [-M regex] [-A author_file] [-S] [-F] [-P project_name] [SVN_URL]
@@ -44,7 +45,7 @@ END
exit(1);
}
-getopts("A:b:C:dDFhiI:l:mM:o:rs:t:T:SP:uv") or usage();
+getopts("A:b:C:dDFhiI:l:mM:o:rs:t:T:SP:R:uv") or usage();
usage if $opt_h;
my $tag_name = $opt_t || "tags";
@@ -52,6 +53,7 @@ my $trunk_name = $opt_T || "trunk";
my $branch_name = $opt_b || "branches";
my $project_name = $opt_P || "";
$project_name = "/" . $project_name if ($project_name);
+my $repack_after = $opt_R || 1000;
@ARGV == 1 or @ARGV == 2 or usage();
@@ -146,6 +148,7 @@ sub file {
print "... $rev $path ...\n" if $opt_v;
my (undef, $properties);
my $pool = SVN::Pool->new();
+ $path =~ s#^/*##;
eval { (undef, $properties)
= $self->{'svn'}->get_file($path,$rev,$fh,$pool); };
$pool->clear;
@@ -181,6 +184,7 @@ sub ignore {
my($self,$path,$rev) = @_;
print "... $rev $path ...\n" if $opt_v;
+ $path =~ s#^/*##;
my (undef,undef,$properties)
= $self->{'svn'}->get_dir($path,$rev,undef);
if (exists $properties->{'svn:ignore'}) {
@@ -197,6 +201,7 @@ sub ignore {
sub dir_list {
my($self,$path,$rev) = @_;
+ $path =~ s#^/*##;
my ($dirents,undef,$properties)
= $self->{'svn'}->get_dir($path,$rev,undef);
return $dirents;
@@ -354,6 +359,7 @@ open BRANCHES,">>", "$git_dir/svn2git";
sub node_kind($$) {
my ($svnpath, $revision) = @_;
my $pool=SVN::Pool->new;
+ $svnpath =~ s#^/*##;
my $kind = $svn->{'svn'}->check_path($svnpath,$revision,$pool);
$pool->clear;
return $kind;
@@ -934,11 +940,27 @@ if ($opt_l < $current_rev) {
exit;
}
-print "Fetching from $current_rev to $opt_l ...\n" if $opt_v;
+print "Processing from $current_rev to $opt_l ...\n" if $opt_v;
-my $pool=SVN::Pool->new;
-$svn->{'svn'}->get_log("/",$current_rev,$opt_l,0,1,1,\&commit_all,$pool);
-$pool->clear;
+my $from_rev;
+my $to_rev = $current_rev;
+
+while ($to_rev < $opt_l) {
+ $from_rev = $to_rev;
+ $to_rev = $from_rev + $repack_after;
+ $to_rev = $opt_l if $opt_l < $to_rev;
+ print "Fetching from $from_rev to $to_rev ...\n" if $opt_v;
+ my $pool=SVN::Pool->new;
+ $svn->{'svn'}->get_log("/",$from_rev,$to_rev,0,1,1,\&commit_all,$pool);
+ $pool->clear;
+ my $pid = fork();
+ die "Fork: $!\n" unless defined $pid;
+ unless($pid) {
+ exec("git-repack", "-d")
+ or die "Cannot repack: $!\n";
+ }
+ waitpid($pid, 0);
+}
unlink($git_index);
diff --git a/git-tag.sh b/git-tag.sh
index e1bfa82f1e..ecb9100e4b 100755
--- a/git-tag.sh
+++ b/git-tag.sh
@@ -1,7 +1,7 @@
#!/bin/sh
# Copyright (c) 2005 Linus Torvalds
-USAGE='-l [<pattern>] | [-a | -s | -u <key-id>] [-f | -d] [-m <msg>] <tagname> [<head>]'
+USAGE='-l [<pattern>] | [-a | -s | -u <key-id>] [-f | -d | -v] [-m <msg>] <tagname> [<head>]'
SUBDIRECTORY_OK='Yes'
. git-sh-setup
@@ -12,6 +12,7 @@ force=
message=
username=
list=
+verify=
while case "$#" in 0) break ;; esac
do
case "$1" in
@@ -69,6 +70,14 @@ do
echo "Deleted tag $tag_name."
exit $?
;;
+ -v)
+ shift
+ tag_name="$1"
+ tag=$(git-show-ref --verify --hash -- "refs/tags/$tag_name") ||
+ die "Seriously, what tag are you talking about?"
+ git-verify-tag -v "$tag"
+ exit $?
+ ;;
-*)
usage
;;
diff --git a/git-verify-tag.sh b/git-verify-tag.sh
index 36f171b302..8db7dd0b7d 100755
--- a/git-verify-tag.sh
+++ b/git-verify-tag.sh
@@ -34,7 +34,10 @@ t)
;;
esac
+trap 'rm -f "$GIT_DIR/.tmp-vtag"' 0
+
git-cat-file tag "$1" >"$GIT_DIR/.tmp-vtag" || exit 1
+
cat "$GIT_DIR/.tmp-vtag" |
sed '/-----BEGIN PGP/Q' |
gpg --verify "$GIT_DIR/.tmp-vtag" - || exit 1
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index d845e91e20..f46a42296d 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -2274,7 +2274,7 @@ sub git_difftree_body {
my $mode_chnge = "";
if ($diff{'from_mode'} != $diff{'to_mode'}) {
$mode_chnge = "<span class=\"file_status mode_chnge\">[changed";
- if ($from_file_type != $to_file_type) {
+ if ($from_file_type ne $to_file_type) {
$mode_chnge .= " from $from_file_type to $to_file_type";
}
if (($from_mode_oct & 0777) != ($to_mode_oct & 0777)) {
@@ -2378,7 +2378,6 @@ sub git_patchset_body {
my $patch_line;
my $diffinfo;
my (%from, %to);
- my ($from_id, $to_id);
print "<div class=\"patchset\">\n";
@@ -2392,6 +2391,7 @@ sub git_patchset_body {
PATCH:
while ($patch_line) {
my @diff_header;
+ my ($from_id, $to_id);
# git diff header
#assert($patch_line =~ m/^diff /) if DEBUG;
@@ -2403,7 +2403,7 @@ sub git_patchset_body {
while ($patch_line = <$fd>) {
chomp $patch_line;
- last EXTENDED_HEADER if ($patch_line =~ m/^--- /);
+ last EXTENDED_HEADER if ($patch_line =~ m/^--- |^diff /);
if ($patch_line =~ m/^index ([0-9a-fA-F]{40})..([0-9a-fA-F]{40})/) {
$from_id = $1;
@@ -2439,11 +2439,15 @@ sub git_patchset_body {
$from{'href'} = href(action=>"blob", hash_base=>$hash_parent,
hash=>$diffinfo->{'from_id'},
file_name=>$from{'file'});
+ } else {
+ delete $from{'href'};
}
if ($diffinfo->{'status'} ne "D") { # not deleted file
$to{'href'} = href(action=>"blob", hash_base=>$hash,
hash=>$diffinfo->{'to_id'},
file_name=>$to{'file'});
+ } else {
+ delete $to{'href'};
}
# this is first patch for raw difftree line with $patch_idx index
# we index @$difftree array from 0, but number patches from 1
@@ -2475,11 +2479,11 @@ sub git_patchset_body {
# match <path>
if ($patch_line =~ s!^((copy|rename) from ).*$!$1! && $from{'href'}) {
$patch_line .= $cgi->a({-href=>$from{'href'}, -class=>"path"},
- esc_path($from{'file'}));
+ esc_path($from{'file'}));
}
if ($patch_line =~ s!^((copy|rename) to ).*$!$1! && $to{'href'}) {
- $patch_line = $cgi->a({-href=>$to{'href'}, -class=>"path"},
- esc_path($to{'file'}));
+ $patch_line .= $cgi->a({-href=>$to{'href'}, -class=>"path"},
+ esc_path($to{'file'}));
}
# match <mode>
if ($patch_line =~ m/\s(\d{6})$/) {
@@ -2518,8 +2522,10 @@ sub git_patchset_body {
# from-file/to-file diff header
$patch_line = $last_patch_line;
+ last PATCH unless $patch_line;
+ next PATCH if ($patch_line =~ m/^diff /);
#assert($patch_line =~ m/^---/) if DEBUG;
- if ($from{'href'}) {
+ if ($from{'href'} && $patch_line =~ m!^--- "?a/!) {
$patch_line = '--- a/' .
$cgi->a({-href=>$from{'href'}, -class=>"path"},
esc_path($from{'file'}));
@@ -2531,7 +2537,7 @@ sub git_patchset_body {
chomp $patch_line;
#assert($patch_line =~ m/^+++/) if DEBUG;
- if ($to{'href'}) {
+ if ($to{'href'} && $patch_line =~ m!^\+\+\+ "?b/!) {
$patch_line = '+++ b/' .
$cgi->a({-href=>$to{'href'}, -class=>"path"},
esc_path($to{'file'}));
@@ -2813,8 +2819,12 @@ sub git_tags_body {
print "<tr class=\"light\">\n";
}
$alternate ^= 1;
- print "<td><i>$tag{'age'}</i></td>\n" .
- "<td>" .
+ if (defined $tag{'age'}) {
+ print "<td><i>$tag{'age'}</i></td>\n";
+ } else {
+ print "<td></td>\n";
+ }
+ print "<td>" .
$cgi->a({-href => href(action=>$tag{'reftype'}, hash=>$tag{'refid'}),
-class => "list name"}, esc_html($tag{'name'})) .
"</td>\n" .
@@ -2995,7 +3005,7 @@ sub git_project_index {
foreach my $pr (@projects) {
if (!exists $pr->{'owner'}) {
- $pr->{'owner'} = get_file_owner("$projectroot/$project");
+ $pr->{'owner'} = get_file_owner("$projectroot/$pr->{'path'}");
}
my ($path, $owner) = ($pr->{'path'}, $pr->{'owner'});
@@ -3208,9 +3218,14 @@ HTML
esc_html($rev));
print "</td>\n";
}
+ open (my $dd, "-|", git_cmd(), "rev-parse", "$full_rev^")
+ or die_error("could not open git-rev-parse");
+ my $parent_commit = <$dd>;
+ close $dd;
+ chomp($parent_commit);
my $blamed = href(action => 'blame',
file_name => $meta->{'filename'},
- hash_base => $full_rev);
+ hash_base => $parent_commit);
print "<td class=\"linenr\">";
print $cgi->a({ -href => "$blamed#l$orig_lineno",
-id => "l$lineno",
@@ -4423,7 +4438,7 @@ sub git_shortlog {
}
my $refs = git_get_references();
- my @commitlist = parse_commits($head, 101, (100 * $page));
+ my @commitlist = parse_commits($hash, 101, (100 * $page));
my $paging_nav = format_paging_nav('shortlog', $hash, $head, $page, (100 * ($page+1)));
my $next_link = '';
diff --git a/lockfile.c b/lockfile.c
index 261baff049..4824f4dc02 100644
--- a/lockfile.c
+++ b/lockfile.c
@@ -27,9 +27,12 @@ static int lock_file(struct lock_file *lk, const char *path)
sprintf(lk->filename, "%s.lock", path);
fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666);
if (0 <= fd) {
- if (!lk->next) {
+ if (!lk->on_list) {
lk->next = lock_file_list;
lock_file_list = lk;
+ lk->on_list = 1;
+ }
+ if (lock_file_list) {
signal(SIGINT, remove_lock_file_on_signal);
atexit(remove_lock_file);
}
@@ -37,6 +40,8 @@ static int lock_file(struct lock_file *lk, const char *path)
return error("cannot fix permission bits on %s",
lk->filename);
}
+ else
+ lk->filename[0] = 0;
return fd;
}
@@ -44,7 +49,7 @@ int hold_lock_file_for_update(struct lock_file *lk, const char *path, int die_on
{
int fd = lock_file(lk, path);
if (fd < 0 && die_on_error)
- die("unable to create '%s': %s", path, strerror(errno));
+ die("unable to create '%s.lock': %s", path, strerror(errno));
return fd;
}
diff --git a/merge-recursive.c b/merge-recursive.c
index ca4f19e34d..bac16f577c 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -1248,6 +1248,18 @@ static int merge(struct commit *h1,
return clean;
}
+static const char *better_branch_name(const char *branch)
+{
+ static char githead_env[8 + 40 + 1];
+ char *name;
+
+ if (strlen(branch) != 40)
+ return branch;
+ sprintf(githead_env, "GITHEAD_%s", branch);
+ name = getenv(githead_env);
+ return name ? name : branch;
+}
+
static struct commit *get_ref(const char *ref)
{
unsigned char sha1[20];
@@ -1256,6 +1268,9 @@ static struct commit *get_ref(const char *ref)
if (get_sha1(ref, sha1))
die("Could not resolve ref '%s'", ref);
object = deref_tag(parse_object(sha1), ref, strlen(ref));
+ if (object->type == OBJ_TREE)
+ return make_virtual_commit((struct tree*)object,
+ better_branch_name(ref));
if (object->type != OBJ_COMMIT)
return NULL;
if (parse_commit((struct commit *)object))
@@ -1263,18 +1278,6 @@ static struct commit *get_ref(const char *ref)
return (struct commit *)object;
}
-static const char *better_branch_name(const char *branch)
-{
- static char githead_env[8 + 40 + 1];
- char *name;
-
- if (strlen(branch) != 40)
- return branch;
- sprintf(githead_env, "GITHEAD_%s", branch);
- name = getenv(githead_env);
- return name ? name : branch;
-}
-
int main(int argc, char *argv[])
{
static const char *bases[2];
diff --git a/refs.c b/refs.c
index 121774cb32..52057455a2 100644
--- a/refs.c
+++ b/refs.c
@@ -726,7 +726,6 @@ static int repack_without_ref(const char *refname)
}
if (!found)
return 0;
- memset(&packlock, 0, sizeof(packlock));
fd = hold_lock_file_for_update(&packlock, git_path("packed-refs"), 0);
if (fd < 0)
return error("cannot delete '%s' from packed refs", refname);
diff --git a/send-pack.c b/send-pack.c
index cc884f3b2d..c195d080db 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -14,114 +14,49 @@ static int send_all;
static int force_update;
static int use_thin_pack;
-static int is_zero_sha1(const unsigned char *sha1)
-{
- int i;
-
- for (i = 0; i < 20; i++) {
- if (*sha1++)
- return 0;
- }
- return 1;
-}
-
-static void exec_pack_objects(void)
-{
- static const char *args[] = {
- "pack-objects",
- "--all-progress",
- "--stdout",
- NULL
- };
- execv_git_cmd(args);
- die("git-pack-objects exec failed (%s)", strerror(errno));
-}
-
-static void exec_rev_list(struct ref *refs)
-{
- static const char *args[4];
- int i = 0;
-
- args[i++] = "rev-list"; /* 0 */
- if (use_thin_pack) /* 1 */
- args[i++] = "--objects-edge";
- else
- args[i++] = "--objects";
-
- args[i++] = "--stdin";
-
- args[i] = NULL;
- execv_git_cmd(args);
- die("git-rev-list exec failed (%s)", strerror(errno));
-}
-
-/*
- * Run "rev-list --stdin | pack-objects" pipe.
- */
-static void rev_list(int fd, struct ref *refs)
-{
- int pipe_fd[2];
- pid_t pack_objects_pid;
-
- if (pipe(pipe_fd) < 0)
- die("rev-list setup: pipe failed");
- pack_objects_pid = fork();
- if (!pack_objects_pid) {
- /* The child becomes pack-objects; reads from pipe
- * and writes to the original fd
- */
- dup2(pipe_fd[0], 0);
- dup2(fd, 1);
- close(pipe_fd[0]);
- close(pipe_fd[1]);
- close(fd);
- exec_pack_objects();
- die("pack-objects setup failed");
- }
- if (pack_objects_pid < 0)
- die("pack-objects fork failed");
-
- /* We become rev-list --stdin; output goes to pipe. */
- dup2(pipe_fd[1], 1);
- close(pipe_fd[0]);
- close(pipe_fd[1]);
- close(fd);
- exec_rev_list(refs);
-}
-
/*
- * Create "rev-list --stdin | pack-objects" pipe and feed
- * the refs into the pipeline.
+ * Make a pack stream and spit it out into file descriptor fd
*/
-static void rev_list_generate(int fd, struct ref *refs)
+static int pack_objects(int fd, struct ref *refs)
{
int pipe_fd[2];
- pid_t rev_list_generate_pid;
+ pid_t pid;
if (pipe(pipe_fd) < 0)
- die("rev-list-generate setup: pipe failed");
- rev_list_generate_pid = fork();
- if (!rev_list_generate_pid) {
- /* The child becomes the "rev-list | pack-objects"
- * pipeline. It takes input from us, and its output
- * goes to fd.
+ return error("send-pack: pipe failed");
+ pid = fork();
+ if (!pid) {
+ /*
+ * The child becomes pack-objects --revs; we feed
+ * the revision parameters to it via its stdin and
+ * let its stdout go back to the other end.
*/
+ static const char *args[] = {
+ "pack-objects",
+ "--all-progress",
+ "--revs",
+ "--stdout",
+ NULL,
+ NULL,
+ };
+ if (use_thin_pack)
+ args[4] = "--thin";
dup2(pipe_fd[0], 0);
dup2(fd, 1);
close(pipe_fd[0]);
close(pipe_fd[1]);
close(fd);
- rev_list(fd, refs);
- die("rev-list setup failed");
+ execv_git_cmd(args);
+ die("git-pack-objects exec failed (%s)", strerror(errno));
}
- if (rev_list_generate_pid < 0)
- die("rev-list-generate fork failed");
- /* We feed the rev parameters to them. We do not write into
- * fd nor read from the pipe.
+ /*
+ * We feed the pack-objects we just spawned with revision
+ * parameters by writing to the pipe.
*/
close(pipe_fd[0]);
close(fd);
+
while (refs) {
char buf[42];
@@ -130,38 +65,38 @@ static void rev_list_generate(int fd, struct ref *refs)
memcpy(buf + 1, sha1_to_hex(refs->old_sha1), 40);
buf[0] = '^';
buf[41] = '\n';
- write(pipe_fd[1], buf, 42);
+ if (!write_in_full(pipe_fd[1], buf, 42,
+ "send-pack: send refs"))
+ break;
}
if (!is_null_sha1(refs->new_sha1)) {
memcpy(buf, sha1_to_hex(refs->new_sha1), 40);
buf[40] = '\n';
- write(pipe_fd[1], buf, 41);
+ if (!write_in_full(pipe_fd[1], buf, 41,
+ "send-pack: send refs"))
+ break;
}
refs = refs->next;
}
close(pipe_fd[1]);
- // waitpid(rev_list_generate_pid);
- exit(0);
-}
-/*
- * Make a pack stream and spit it out into file descriptor fd
- */
-static void pack_objects(int fd, struct ref *refs)
-{
- pid_t rev_list_pid;
+ for (;;) {
+ int status, code;
+ pid_t waiting = waitpid(pid, &status, 0);
- rev_list_pid = fork();
- if (!rev_list_pid) {
- rev_list_generate(fd, refs);
- die("rev-list setup failed");
+ if (waiting < 0) {
+ if (errno == EINTR)
+ continue;
+ return error("waitpid failed (%s)", strerror(errno));
+ }
+ if ((waiting != pid) || WIFSIGNALED(status) ||
+ !WIFEXITED(status))
+ return error("pack-objects died with strange error");
+ code = WEXITSTATUS(status);
+ if (code)
+ return -code;
+ return 0;
}
- if (rev_list_pid < 0)
- die("rev-list fork failed");
- /*
- * We don't wait for the rev-list pipeline in the parent:
- * we end up waiting for the other end instead
- */
}
static void unmark_and_free(struct commit_list *list, unsigned int mark)
@@ -341,7 +276,7 @@ static int send_pack(int in, int out, int nr_refspec, char **refspec)
if (!force_update &&
!delete_ref &&
- !is_zero_sha1(ref->old_sha1) &&
+ !is_null_sha1(ref->old_sha1) &&
!ref->force) {
if (!has_sha1_file(ref->old_sha1) ||
!ref_newer(ref->peer_ref->new_sha1,
@@ -393,7 +328,7 @@ static int send_pack(int in, int out, int nr_refspec, char **refspec)
packet_flush(out);
if (new_refs)
- pack_objects(out, remote_refs);
+ ret = pack_objects(out, remote_refs);
close(out);
if (expect_status_report) {
diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh
index 99ada71349..af42ccc8d1 100644
--- a/t/lib-git-svn.sh
+++ b/t/lib-git-svn.sh
@@ -7,26 +7,10 @@ then
exit
fi
-perl -e 'use SVN::Core; $SVN::Core::VERSION gt "1.1.0" or die' >/dev/null 2>&1
-if test $? -ne 0
-then
- test_expect_success 'Perl SVN libraries not found, skipping test' :
- test_done
- exit
-fi
-
GIT_DIR=$PWD/.git
GIT_SVN_DIR=$GIT_DIR/svn/git-svn
SVN_TREE=$GIT_SVN_DIR/svn-tree
-svnadmin >/dev/null 2>&1
-if test $? -ne 1
-then
- test_expect_success 'skipping git-svn tests, svnadmin not found' :
- test_done
- exit
-fi
-
svn >/dev/null 2>&1
if test $? -ne 1
then
@@ -37,13 +21,24 @@ fi
svnrepo=$PWD/svnrepo
-set -e
-
-if svnadmin create --help | grep fs-type >/dev/null
+perl -w -e "
+use SVN::Core;
+use SVN::Repos;
+\$SVN::Core::VERSION gt '1.1.0' or exit(42);
+SVN::Repos::create('$svnrepo', undef, undef, undef,
+ { 'fs-config' => 'fsfs'});
+"
+x=$?
+if test $x -ne 0
then
- svnadmin create --fs-type fsfs "$svnrepo"
-else
- svnadmin create "$svnrepo"
+ if test $x -eq 42; then
+ err='Perl SVN libraries must be >= 1.1.0'
+ else
+ err='Perl SVN libraries not found or unusable, skipping test'
+ fi
+ test_expect_success "$err" :
+ test_done
+ exit
fi
svnrepo="file://$svnrepo"
diff --git a/t/t5401-update-hooks.sh b/t/t5401-update-hooks.sh
new file mode 100755
index 0000000000..cd8cee6ae8
--- /dev/null
+++ b/t/t5401-update-hooks.sh
@@ -0,0 +1,81 @@
+#!/bin/sh
+#
+# Copyright (c) 2006 Shawn O. Pearce
+#
+
+test_description='Test the update hook infrastructure.'
+. ./test-lib.sh
+
+test_expect_success setup '
+ echo This is a test. >a &&
+ git-update-index --add a &&
+ tree0=$(git-write-tree) &&
+ commit0=$(echo setup | git-commit-tree $tree0) &&
+ git-update-ref HEAD $commit0 &&
+ git-clone ./. victim &&
+ echo We hope it works. >a &&
+ git-update-index a &&
+ tree1=$(git-write-tree) &&
+ commit1=$(echo modify | git-commit-tree $tree1 -p $commit0) &&
+ git-update-ref HEAD $commit1
+'
+
+cat >victim/.git/hooks/update <<'EOF'
+#!/bin/sh
+echo "$@" >$GIT_DIR/update.args
+read x; echo -n "$x" >$GIT_DIR/update.stdin
+echo STDOUT update
+echo STDERR update >&2
+EOF
+chmod u+x victim/.git/hooks/update
+
+cat >victim/.git/hooks/post-update <<'EOF'
+#!/bin/sh
+echo "$@" >$GIT_DIR/post-update.args
+read x; echo -n "$x" >$GIT_DIR/post-update.stdin
+echo STDOUT post-update
+echo STDERR post-update >&2
+EOF
+chmod u+x victim/.git/hooks/post-update
+
+test_expect_success push '
+ git-send-pack ./victim/.git/ master >send.out 2>send.err
+'
+
+test_expect_success 'hooks ran' '
+ test -f victim/.git/update.args &&
+ test -f victim/.git/update.stdin &&
+ test -f victim/.git/post-update.args &&
+ test -f victim/.git/post-update.stdin
+'
+
+test_expect_success 'update hook arguments' '
+ echo refs/heads/master $commit0 $commit1 |
+ diff -u - victim/.git/update.args
+'
+
+test_expect_success 'post-update hook arguments' '
+ echo refs/heads/master |
+ diff -u - victim/.git/post-update.args
+'
+
+test_expect_failure 'update hook stdin is /dev/null' '
+ test -s victim/.git/update.stdin
+'
+
+test_expect_failure 'post-update hook stdin is /dev/null' '
+ test -s victim/.git/post-update.stdin
+'
+
+test_expect_failure 'send-pack produced no output' '
+ test -s send.out
+'
+
+test_expect_success 'send-pack stderr contains hook messages' '
+ grep "STDOUT update" send.err &&
+ grep "STDERR update" send.err &&
+ grep "STDOUT post-update" send.err &&
+ grep "STDERR post-update" send.err
+'
+
+test_done
diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh
index c22fe47213..040da92756 100755
--- a/t/t9100-git-svn-basic.sh
+++ b/t/t9100-git-svn-basic.sh
@@ -24,10 +24,7 @@ test_expect_success \
mkdir import &&
cd import &&
echo foo > foo &&
- if test -z '$NO_SYMLINK'
- then
- ln -s foo foo.link
- fi
+ ln -s foo foo.link
mkdir -p dir/a/b/c/d/e &&
echo 'deep dir' > dir/a/b/c/d/e/file &&
mkdir bar &&
@@ -136,48 +133,43 @@ test_expect_success "$name" "
test -x '$SVN_TREE'/exec.sh"
-if test -z "$NO_SYMLINK"
-then
- name='executable file becomes a symlink to bar/zzz (file)'
-
- test_expect_success "$name" "
- rm exec.sh &&
- ln -s bar/zzz exec.sh &&
- git update-index exec.sh &&
- git commit -m '$name' &&
- git-svn set-tree --find-copies-harder --rmdir \
- remotes/git-svn..mybranch5 &&
- svn up '$SVN_TREE' &&
- test -L '$SVN_TREE'/exec.sh"
+name='executable file becomes a symlink to bar/zzz (file)'
+test_expect_success "$name" "
+ rm exec.sh &&
+ ln -s bar/zzz exec.sh &&
+ git update-index exec.sh &&
+ git commit -m '$name' &&
+ git-svn set-tree --find-copies-harder --rmdir \
+ remotes/git-svn..mybranch5 &&
+ svn up '$SVN_TREE' &&
+ test -L '$SVN_TREE'/exec.sh"
- name='new symlink is added to a file that was also just made executable'
+name='new symlink is added to a file that was also just made executable'
- test_expect_success "$name" "
- chmod +x bar/zzz &&
- ln -s bar/zzz exec-2.sh &&
- git update-index --add bar/zzz exec-2.sh &&
- git commit -m '$name' &&
- git-svn set-tree --find-copies-harder --rmdir \
- remotes/git-svn..mybranch5 &&
- svn up '$SVN_TREE' &&
- test -x '$SVN_TREE'/bar/zzz &&
- test -L '$SVN_TREE'/exec-2.sh"
-
- name='modify a symlink to become a file'
- test_expect_success "$name" "
- echo git help > help || true &&
- rm exec-2.sh &&
- cp help exec-2.sh &&
- git update-index exec-2.sh &&
- git commit -m '$name' &&
- git-svn set-tree --find-copies-harder --rmdir \
- remotes/git-svn..mybranch5 &&
- svn up '$SVN_TREE' &&
- test -f '$SVN_TREE'/exec-2.sh &&
- test ! -L '$SVN_TREE'/exec-2.sh &&
- diff -u help $SVN_TREE/exec-2.sh"
-fi
+test_expect_success "$name" "
+ chmod +x bar/zzz &&
+ ln -s bar/zzz exec-2.sh &&
+ git update-index --add bar/zzz exec-2.sh &&
+ git commit -m '$name' &&
+ git-svn set-tree --find-copies-harder --rmdir \
+ remotes/git-svn..mybranch5 &&
+ svn up '$SVN_TREE' &&
+ test -x '$SVN_TREE'/bar/zzz &&
+ test -L '$SVN_TREE'/exec-2.sh"
+name='modify a symlink to become a file'
+test_expect_success "$name" "
+ echo git help > help || true &&
+ rm exec-2.sh &&
+ cp help exec-2.sh &&
+ git update-index exec-2.sh &&
+ git commit -m '$name' &&
+ git-svn set-tree --find-copies-harder --rmdir \
+ remotes/git-svn..mybranch5 &&
+ svn up '$SVN_TREE' &&
+ test -f '$SVN_TREE'/exec-2.sh &&
+ test ! -L '$SVN_TREE'/exec-2.sh &&
+ diff -u help $SVN_TREE/exec-2.sh"
if test "$have_utf8" = t
then
@@ -203,12 +195,6 @@ test_expect_success "$name" \
git-rev-list --pretty=raw remotes/alt | grep ^tree | uniq > b &&
diff -u a b"
-if test -n "$NO_SYMLINK"
-then
- test_done
- exit 0
-fi
-
name='check imported tree checksums expected tree checksums'
rm -f expected
if test "$have_utf8" = t
diff --git a/t/t9101-git-svn-props.sh b/t/t9101-git-svn-props.sh
index 5543b07f16..46fcec50a5 100755
--- a/t/t9101-git-svn-props.sh
+++ b/t/t9101-git-svn-props.sh
@@ -57,13 +57,10 @@ test_expect_success 'setup some commits to svn' \
'cd test_wc &&
echo Greetings >> kw.c &&
svn commit -m "Not yet an Id" &&
- svn up &&
echo Hello world >> kw.c &&
svn commit -m "Modified file, but still not yet an Id" &&
- svn up &&
svn propset svn:keywords Id kw.c &&
- svn commit -m "Propset Id" &&
- svn up &&
+ svn commit -m "Propset Id"
cd ..'
test_expect_success 'initialize git-svn' "git-svn init $svnrepo"
@@ -86,8 +83,7 @@ test_expect_success "propset CR on crlf files" \
svn propset svn:eol-style CR empty &&
svn propset svn:eol-style CR crlf &&
svn propset svn:eol-style CR ne_crlf &&
- svn commit -m "propset CR on crlf files" &&
- svn up &&
+ svn commit -m "propset CR on crlf files"
cd ..'
test_expect_success 'fetch and pull latest from svn and checkout a new wc' \
@@ -111,8 +107,7 @@ cd test_wc
svn propset svn:eol-style CRLF ne_cr &&
svn propset svn:keywords Id cr &&
svn propset svn:keywords Id ne_cr &&
- svn commit -m "propset CRLF on cr files" &&
- svn up'
+ svn commit -m "propset CRLF on cr files"'
cd ..
test_expect_success 'fetch and pull latest from svn' \
'git-svn fetch && git pull . remotes/git-svn'
diff --git a/t/t9103-git-svn-graft-branches.sh b/t/t9103-git-svn-graft-branches.sh
index 293b98f928..b5f7677021 100755
--- a/t/t9103-git-svn-graft-branches.sh
+++ b/t/t9103-git-svn-graft-branches.sh
@@ -16,25 +16,19 @@ test_expect_success 'initialize repo' "
cd wc &&
echo feedme >> branches/a/readme &&
svn commit -m hungry &&
- svn up &&
cd trunk &&
svn merge -r3:4 $svnrepo/branches/a &&
svn commit -m 'merge with a' &&
cd ../.. &&
- svn log -v $svnrepo &&
- git-svn init -i trunk $svnrepo/trunk &&
- git-svn init -i a $svnrepo/branches/a &&
- git-svn init -i tags/a $svnrepo/tags/a &&
- git-svn fetch -i tags/a &&
- git-svn fetch -i a &&
- git-svn fetch -i trunk
+ 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-list remotes/a | head -n1`
-r5=`git-rev-list remotes/trunk | head -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" &&
diff --git a/t/t9104-git-svn-follow-parent.sh b/t/t9104-git-svn-follow-parent.sh
index 8d2e2fec39..400c21cd49 100755
--- a/t/t9104-git-svn-follow-parent.sh
+++ b/t/t9104-git-svn-follow-parent.sh
@@ -17,7 +17,6 @@ test_expect_success 'initialize repo' "
cd wc &&
echo world >> trunk/readme &&
svn commit -m 'another commit' &&
- svn up &&
svn mv -m 'rename to thunk' trunk thunk &&
svn up &&
echo goodbye >> thunk/readme &&
diff --git a/t/test-lib.sh b/t/test-lib.sh
index bf108d4226..72ea2b2598 100755
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -99,12 +99,12 @@ trap 'echo >&5 "FATAL: Unexpected exit with code $?"; exit 1' exit
test_tick () {
if test -z "${test_tick+set}"
then
- test_tick=432630000
+ test_tick=1112911993
else
test_tick=$(($test_tick + 60))
fi
- GIT_COMMITTER_DATE=$test_tick
- GIT_AUTHOR_DATE=$test_tick
+ GIT_COMMITTER_DATE="$test_tick -0700"
+ GIT_AUTHOR_DATE="$test_tick -0700"
export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
}
diff --git a/tree-walk.c b/tree-walk.c
index 14cc5aea6c..22f4550b6c 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -113,7 +113,6 @@ void traverse_trees(int n, struct tree_desc *t, const char *base, traverse_callb
struct name_entry *entry = xmalloc(n*sizeof(*entry));
for (;;) {
- struct name_entry entry[3];
unsigned long mask = 0;
int i, last;
diff --git a/write_or_die.c b/write_or_die.c
index 8cf6486025..6db1d3123d 100644
--- a/write_or_die.c
+++ b/write_or_die.c
@@ -59,3 +59,26 @@ int write_or_whine(int fd, const void *buf, size_t count, const char *msg)
return 1;
}
+
+int write_in_full(int fd, const void *buf, size_t count, const char *msg)
+{
+ const char *p = buf;
+ ssize_t written;
+
+ while (count > 0) {
+ written = xwrite(fd, p, count);
+ if (written == 0) {
+ fprintf(stderr, "%s: disk full?\n", msg);
+ return 0;
+ }
+ else if (written < 0) {
+ fprintf(stderr, "%s: write error (%s)\n",
+ msg, strerror(errno));
+ return 0;
+ }
+ count -= written;
+ p += written;
+ }
+
+ return 1;
+}
diff --git a/wt-status.c b/wt-status.c
index db427384ff..8aac526440 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -15,7 +15,7 @@ static char wt_status_colors[][COLOR_MAXLEN] = {
"\033[31m", /* WT_STATUS_CHANGED: red */
"\033[31m", /* WT_STATUS_UNTRACKED: red */
};
-static const char* use_add_msg = "use \"git add file1 file2\" to include for commit";
+static const char* use_add_msg = "use \"git add <file>...\" to incrementally add content to commit";
static int parse_status_slot(const char *var, int offset)
{
@@ -41,8 +41,6 @@ void wt_status_prepare(struct wt_status *s)
unsigned char sha1[20];
const char *head;
- s->is_initial = get_sha1("HEAD", sha1) ? 1 : 0;
-
head = resolve_ref("HEAD", sha1, 0, NULL);
s->branch = head ? xstrdup(head) : NULL;
@@ -51,6 +49,20 @@ void wt_status_prepare(struct wt_status *s)
s->verbose = 0;
s->commitable = 0;
s->untracked = 0;
+
+ s->workdir_clean = 1;
+}
+
+static void wt_status_print_cached_header(const char *reference)
+{
+ const char *c = color(WT_STATUS_HEADER);
+ color_printf_ln(c, "# Cached changes to be committed:");
+ if (reference) {
+ color_printf_ln(c, "# (use \"git reset %s <file>...\" and \"git rm --cached <file>...\" to unstage)", reference);
+ } else {
+ color_printf_ln(c, "# (use \"git rm --cached <file>...\" to unstage)");
+ }
+ color_printf_ln(c, "#");
}
static void wt_status_print_header(const char *main, const char *sub)
@@ -147,8 +159,7 @@ static void wt_status_print_updated_cb(struct diff_queue_struct *q,
if (q->queue[i]->status == 'U')
continue;
if (!shown_header) {
- wt_status_print_header("Added but not yet committed",
- "will commit");
+ wt_status_print_cached_header(s->reference);
s->commitable = 1;
shown_header = 1;
}
@@ -162,9 +173,12 @@ static void wt_status_print_changed_cb(struct diff_queue_struct *q,
struct diff_options *options,
void *data)
{
+ struct wt_status *s = data;
int i;
- if (q->nr)
+ if (q->nr) {
+ s->workdir_clean = 0;
wt_status_print_header("Changed but not added", use_add_msg);
+ }
for (i = 0; i < q->nr; i++)
wt_status_print_filepair(WT_STATUS_CHANGED, q->queue[i]);
if (q->nr)
@@ -179,8 +193,7 @@ void wt_status_print_initial(struct wt_status *s)
read_cache();
if (active_nr) {
s->commitable = 1;
- wt_status_print_header("Added but not yet committed",
- "will commit");
+ wt_status_print_cached_header(NULL);
}
for (i = 0; i < active_nr; i++) {
color_printf(color(WT_STATUS_HEADER), "#\t");
@@ -215,7 +228,7 @@ static void wt_status_print_changed(struct wt_status *s)
run_diff_files(&rev, 0);
}
-static void wt_status_print_untracked(const struct wt_status *s)
+static void wt_status_print_untracked(struct wt_status *s)
{
struct dir_struct dir;
const char *x;
@@ -250,6 +263,7 @@ static void wt_status_print_untracked(const struct wt_status *s)
continue;
}
if (!shown_header) {
+ s->workdir_clean = 0;
wt_status_print_header("Untracked files", use_add_msg);
shown_header = 1;
}
@@ -271,6 +285,9 @@ static void wt_status_print_verbose(struct wt_status *s)
void wt_status_print(struct wt_status *s)
{
+ unsigned char sha1[20];
+ s->is_initial = get_sha1(s->reference, sha1) ? 1 : 0;
+
if (s->branch)
color_printf_ln(color(WT_STATUS_HEADER),
"# On branch %s", s->branch);
@@ -291,10 +308,16 @@ void wt_status_print(struct wt_status *s)
if (s->verbose && !s->is_initial)
wt_status_print_verbose(s);
- if (!s->commitable)
- printf("%s (%s)\n",
- s->amend ? "# No changes" : "nothing to commit",
- use_add_msg);
+ if (!s->commitable) {
+ if (s->amend)
+ printf("# No changes\n");
+ else if (s->workdir_clean)
+ printf(s->is_initial
+ ? "nothing to commit\n"
+ : "nothing to commit (working directory matches HEAD)\n");
+ else
+ printf("no changes added to commit (use \"git add\" and/or \"git commit [-a|-i|-o]\")\n");
+ }
}
int git_status_config(const char *k, const char *v)
diff --git a/wt-status.h b/wt-status.h
index 0a5a5b7ba9..892a86c76a 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -16,6 +16,7 @@ struct wt_status {
int verbose;
int amend;
int untracked;
+ int workdir_clean;
};
int git_status_config(const char *var, const char *value);