Merge branch 'sp/merge' (early part)
authorJunio C Hamano <junkio@cox.net>
Sun, 14 Jan 2007 20:03:53 +0000 (12:03 -0800)
committerJunio C Hamano <junkio@cox.net>
Sun, 14 Jan 2007 20:03:53 +0000 (12:03 -0800)
* 'sp/merge' (early part):
Improve merge performance by avoiding in-index merges.

71 files changed:
Documentation/config.txt
Documentation/core-tutorial.txt
Documentation/cvs-migration.txt
Documentation/git-commit.txt
Documentation/git-init-db.txt
Documentation/git-init.txt
Documentation/git-p4import.txt
Documentation/git-prune-packed.txt
Documentation/git-svn.txt
Documentation/git.txt
Documentation/glossary.txt
Documentation/hooks.txt
Documentation/howto/setup-git-server-over-http.txt
Documentation/repository-layout.txt
GIT-VERSION-GEN
INSTALL
builtin-branch.c
builtin-describe.c
builtin-init-db.c
builtin-prune-packed.c
builtin-reflog.c
builtin-rm.c
cache.h
config.c
environment.c
fsck-objects.c
generate-cmdlist.sh
git-am.sh
git-archimport.perl
git-checkout.sh
git-clean.sh
git-clone.sh
git-commit.sh
git-compat-util.h
git-cvsimport.perl
git-fetch.sh
git-merge.sh
git-p4import.py
git-pull.sh
git-rebase.sh
git-remote.perl
git-repack.sh
git-reset.sh
git-revert.sh
git-sh-setup.sh
git-svn.perl
git-svnimport.perl
git.c
index-pack.c
merge-recursive.c
path.c
perl/Git.pm
read-cache.c
refs.c
revision.c
setup.c
sha1_file.c
t/README
t/lib-git-svn.sh
t/t0000-basic.sh
t/t3200-branch.sh
t/t4116-apply-reverse.sh
t/t5300-pack-object.sh
t/t5500-fetch-pack.sh
t/t5510-fetch.sh
t/t5520-pull.sh
t/t7001-mv.sh
t/t9104-git-svn-follow-parent.sh
t/test-lib.sh
write_or_die.c
wt-status.c
index b4aae0d0aeba86e995b37a5fe3ab7ec61e268687..f7dba8977f4eb9a59171247250e136a33b1f7533 100644 (file)
@@ -100,7 +100,7 @@ core.sharedRepository::
        group-writable). When 'all' (or 'world' or 'everybody'), the
        repository will be readable by all users, additionally to being
        group-shareable. When 'umask' (or 'false'), git will use permissions
-       reported by umask(2). See gitlink:git-init-db[1]. False by default.
+       reported by umask(2). See gitlink:git-init[1]. False by default.
 
 core.warnAmbiguousRefs::
        If true, git will warn you if the ref name you passed it is ambiguous
index 5ea611748c6da80ee7df0387c5c5021a7095f45e..0cd33fb5b7485f54861d30c896c183535413ad0d 100644 (file)
@@ -46,12 +46,12 @@ to import into git.
 For our first example, we're going to start a totally new repository from
 scratch, with no pre-existing files, and we'll call it `git-tutorial`.
 To start up, create a subdirectory for it, change into that
-subdirectory, and initialize the git infrastructure with `git-init-db`:
+subdirectory, and initialize the git infrastructure with `git-init`:
 
 ------------------------------------------------
 $ mkdir git-tutorial
 $ cd git-tutorial
-$ git-init-db
+$ git-init
 ------------------------------------------------
 
 to which git will reply
@@ -1371,11 +1371,11 @@ $ mkdir my-git.git
 ------------
 
 Then, make that directory into a git repository by running
-`git init-db`, but this time, since its name is not the usual
+`git init`, but this time, since its name is not the usual
 `.git`, we do things slightly differently:
 
 ------------
-$ GIT_DIR=my-git.git git-init-db
+$ GIT_DIR=my-git.git git-init
 ------------
 
 Make sure this directory is available for others you want your
@@ -1511,7 +1511,7 @@ A recommended workflow for a "project lead" goes like this:
 +
 If other people are pulling from your repository over dumb
 transport protocols (HTTP), you need to keep this repository
-'dumb transport friendly'.  After `git init-db`,
+'dumb transport friendly'.  After `git init`,
 `$GIT_DIR/hooks/post-update` copied from the standard templates
 would contain a call to `git-update-server-info` but the
 `post-update` hook itself is disabled by default -- enable it
index 8e09beaa799dbff462b258e5593fd5c79c91312a..775bf4266a769e3ad2ca6eb14333b2c569b98698 100644 (file)
@@ -80,7 +80,7 @@ it:
 ------------------------------------------------
 $ mkdir /pub/my-repo.git
 $ cd /pub/my-repo.git
-$ git --bare init-db --shared
+$ git --bare init --shared
 $ git --bare fetch /home/alice/myproject master:master
 ------------------------------------------------
 
index a7adf24fa5a601f372099988c1fedfb929ceaab1..b4528d72ba376bb0444002698196afa89f781fc1 100644 (file)
@@ -32,7 +32,8 @@ methods:
 
 4. by using the -a switch with the 'commit' command to automatically "add"
    changes from all known files i.e. files that have already been committed
-   before, and perform the actual commit.
+   before, and to automatically "rm" files that have been
+   removed from the working tree, and perform the actual commit.
 
 The gitlink:git-status[1] command can be used to obtain a
 summary of what is included by any of the above for the next
@@ -72,12 +73,8 @@ OPTIONS
        Add Signed-off-by line at the end of the commit message.
 
 --no-verify::
-       By default, the command looks for suspicious lines the
-       commit introduces, and aborts committing if there is one.
-       The definition of 'suspicious lines' is currently the
-       lines that has trailing whitespaces, and the lines whose
-       indentation has a SP character immediately followed by a
-       TAB character.  This option turns off the check.
+       This option bypasses the pre-commit hook.
+       See also link:hooks.html[hooks].
 
 -e|--edit::
        The message taken from file with `-F`, command line with
index bc3ba14939054657bd82b8e3a8eb876e26ff14b0..5412135d763af3a8c68e18441b774654f07eadfd 100644 (file)
@@ -11,96 +11,9 @@ SYNOPSIS
 'git-init-db' [--template=<template_directory>] [--shared[=<permissions>]]
 
 
-OPTIONS
--------
-
---
-
---template=<template_directory>::
-
-Provide the directory from which templates will be used.  The default template
-directory is `/usr/share/git-core/templates`.
-
-When specified, `<template_directory>` is used as the source of the template
-files rather than the default.  The template files include some directory
-structure, some suggested "exclude patterns", and copies of non-executing
-"hook" files.  The suggested patterns and hook files are all modifiable and
-extensible.
-
---shared[={false|true|umask|group|all|world|everybody}]::
-
-Specify that the git repository is to be shared amongst several users.  This
-allows users belonging to the same group to push into that
-repository.  When specified, the config variable "core.sharedRepository" is
-set so that files and directories under `$GIT_DIR` are created with the
-requested permissions.  When not specified, git will use permissions reported
-by umask(2).
-
-The option can have the following values, defaulting to 'group' if no value
-is given:
-
- - 'umask' (or 'false'): Use permissions reported by umask(2). The default,
-   when `--shared` is not specified.
-
- - 'group' (or 'true'): Make the repository group-writable, (and g+sx, since
-   the git group may be not the primary group of all users).
-
- - 'all' (or 'world' or 'everybody'): Same as 'group', but make the repository
-   readable by all users.
-
-By default, the configuration flag receive.denyNonFastforward is enabled
-in shared repositories, so that you cannot force a non fast-forwarding push
-into it.
-
---
-
-
 DESCRIPTION
 -----------
-This command creates an empty git repository - basically a `.git` directory
-with subdirectories for `objects`, `refs/heads`, `refs/tags`, and
-template files.
-An initial `HEAD` file that references the HEAD of the master branch
-is also created.
-
-If the `$GIT_DIR` environment variable is set then it specifies a path
-to use instead of `./.git` for the base of the repository.
-
-If the object storage directory is specified via the `$GIT_OBJECT_DIRECTORY`
-environment variable then the sha1 directories are created underneath -
-otherwise the default `$GIT_DIR/objects` directory is used.
-
-Running `git-init-db` in an existing repository is safe. It will not overwrite
-things that are already there. The primary reason for rerunning `git-init-db`
-is to pick up newly added templates.
-
-Note that `git-init` is the same as `git-init-db`.
-
-
-EXAMPLES
---------
-
-Start a new git repository for an existing code base::
-+
-----------------
-$ cd /path/to/my/codebase
-$ git-init-db   <1>
-$ git-add .     <2>
-----------------
-+
-<1> prepare /path/to/my/codebase/.git directory
-<2> add all existing file to the index
-
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
 
-GIT
----
-Part of the gitlink:git[7] suite
+This is a synonym for gitlink:git-init[1].  Please refer to the
+documentation of that command.
 
index 36838c753bba4f19c34ff76d9e2a4b372a0bd577..596b567c90fc53b3662d31478ad57c8559eafab0 100644 (file)
@@ -1 +1,111 @@
-include::git-init-db.txt[]
+git-init(1)
+===========
+
+NAME
+----
+git-init - Creates an empty git repository
+
+
+SYNOPSIS
+--------
+'git-init' [--template=<template_directory>] [--shared[=<permissions>]]
+
+
+OPTIONS
+-------
+
+--
+
+--template=<template_directory>::
+
+Provide the directory from which templates will be used.  The default template
+directory is `/usr/share/git-core/templates`.
+
+When specified, `<template_directory>` is used as the source of the template
+files rather than the default.  The template files include some directory
+structure, some suggested "exclude patterns", and copies of non-executing
+"hook" files.  The suggested patterns and hook files are all modifiable and
+extensible.
+
+--shared[={false|true|umask|group|all|world|everybody}]::
+
+Specify that the git repository is to be shared amongst several users.  This
+allows users belonging to the same group to push into that
+repository.  When specified, the config variable "core.sharedRepository" is
+set so that files and directories under `$GIT_DIR` are created with the
+requested permissions.  When not specified, git will use permissions reported
+by umask(2).
+
+The option can have the following values, defaulting to 'group' if no value
+is given:
+
+ - 'umask' (or 'false'): Use permissions reported by umask(2). The default,
+   when `--shared` is not specified.
+
+ - 'group' (or 'true'): Make the repository group-writable, (and g+sx, since
+   the git group may be not the primary group of all users).
+
+ - 'all' (or 'world' or 'everybody'): Same as 'group', but make the repository
+   readable by all users.
+
+By default, the configuration flag receive.denyNonFastforward is enabled
+in shared repositories, so that you cannot force a non fast-forwarding push
+into it.
+
+--
+
+
+DESCRIPTION
+-----------
+This command creates an empty git repository - basically a `.git` directory
+with subdirectories for `objects`, `refs/heads`, `refs/tags`, and
+template files.
+An initial `HEAD` file that references the HEAD of the master branch
+is also created.
+
+If the `$GIT_DIR` environment variable is set then it specifies a path
+to use instead of `./.git` for the base of the repository.
+
+If the object storage directory is specified via the `$GIT_OBJECT_DIRECTORY`
+environment variable then the sha1 directories are created underneath -
+otherwise the default `$GIT_DIR/objects` directory is used.
+
+Running `git-init` in an existing repository is safe. It will not overwrite
+things that are already there. The primary reason for rerunning `git-init`
+is to pick up newly added templates.
+
+Note that `git-init` is the same as `git-init-db`.  The command
+was primarily meant to initialize the object database, but over
+time it has become responsible for setting up the other aspects
+of the repository, such as installing the default hooks and
+setting the configuration variables.  The old name is retained
+for backward compatibility reasons.
+
+
+EXAMPLES
+--------
+
+Start a new git repository for an existing code base::
++
+----------------
+$ cd /path/to/my/codebase
+$ git-init      <1>
+$ git-add .     <2>
+----------------
++
+<1> prepare /path/to/my/codebase/.git directory
+<2> add all existing file to the index
+
+
+Author
+------
+Written by Linus Torvalds <torvalds@osdl.org>
+
+Documentation
+--------------
+Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the gitlink:git[7] suite
+
index ee9e8fa9090f88d1eb45ddbdb73866e0dc1fd53d..6edb9f12b87e2bc24fb69c8615e1798bb813e14e 100644 (file)
@@ -93,7 +93,7 @@ perforce branch into a branch named "jammy", like so:
 ------------
 $ mkdir -p /home/sean/import/jam
 $ cd /home/sean/import/jam
-$ git init-db
+$ git init
 $ git p4import //public/jam jammy
 ------------
 
index 234882685d923d632c4e09a38cb9ba18439dda4a..a79193fb007bcaa8dc47b2763e4167a6f31a3dff 100644 (file)
@@ -9,7 +9,7 @@ residing in a pack file.
 
 SYNOPSIS
 --------
-'git-prune-packed' [-n]
+'git-prune-packed' [-n] [-q]
 
 
 DESCRIPTION
@@ -32,6 +32,9 @@ OPTIONS
         Don't actually remove any objects, only show those that would have been
         removed.
 
+-q::
+       Squelch the progress indicator.
+
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org>
index 1b013139af0359458c7abae2a12c8da608041849..9ed721118b7dd446657fe28968e1294ab9fbf421 100644 (file)
@@ -171,7 +171,7 @@ OPTIONS
 --shared::
 --template=<template_directory>::
        Only used with the 'init' command.
-       These are passed directly to gitlink:git-init-db[1].
+       These are passed directly to gitlink:git-init[1].
 
 -r <ARG>::
 --revision <ARG>::
@@ -367,7 +367,7 @@ Basic Examples
 Tracking and contributing to a the trunk of a Subversion-managed project:
 
 ------------------------------------------------------------------------
-# Initialize a repo (like git init-db):
+# Initialize a repo (like git init):
        git-svn init http://svn.foo.org/project/trunk
 # Fetch remote revisions:
        git-svn fetch
@@ -388,7 +388,7 @@ See also:
 '<<tracking-multiple-repos,Tracking Multiple Repositories or Branches>>'
 
 ------------------------------------------------------------------------
-# Initialize a repo (like git init-db):
+# Initialize a repo (like git init):
        git-svn multi-init http://svn.foo.org/project \
                -T trunk -b branches -t tags
 # Fetch remote revisions:
index 5662cdc27cb35786e72dcf9c0db74009a3cba4aa..f89d745efa73a9e22537aadb5c36857f04f030ec 100644 (file)
@@ -354,8 +354,7 @@ gitlink:git-index-pack[1]::
        Build pack idx file for an existing packed archive.
 
 gitlink:git-init[1]::
-gitlink:git-init-db[1]::
-       Creates an empty git object database, or reinitialize an
+       Creates an empty git repository, or reinitialize an
        existing one.
 
 gitlink:git-merge-file[1]::
index cd61aa26065ba6f3d06df7d1c00e2e81d42bce9e..bc917bbac3b21eff1baa70b24c689ff11f5a4323 100644 (file)
@@ -259,7 +259,7 @@ refspec::
        means "grab the master branch head from the $URL and store
        it as my origin branch head".
        And `git push $URL refs/heads/master:refs/heads/to-upstream`
-       means "publish my master branch head as to-upstream master head
+       means "publish my master branch head as to-upstream branch
        at $URL".   See also gitlink:git-push[1]
 
 repository::
index 161123f142ff231bc8153242d7f6507c54b09e2b..e3b76f96eb303dc7eda20472c8c546cf51a54e67 100644 (file)
@@ -3,7 +3,7 @@ Hooks used by git
 
 Hooks are little scripts you can place in `$GIT_DIR/hooks`
 directory to trigger action at certain points.  When
-`git-init-db` is run, a handful example hooks are copied in the
+`git-init` is run, a handful example hooks are copied in the
 `hooks` directory of the new repository, but by default they are
 all disabled.  To enable a hook, make it executable with `chmod +x`.
 
index ba191569af9501117322e1881160226a74867007..a202f3a460b4446f085977f7423d1f43e189e5ef 100644 (file)
@@ -70,7 +70,7 @@ DocumentRoot /where/ever/httpd.conf" to find your root:
 Initialize a bare repository
 
     $ cd my-new-repo.git
-    $ git --bare init-db
+    $ git --bare init
 
 
 Change the ownership to your web-server's credentials. Use "grep ^User
index e20fb7e74c22390e810a392f2625a3ba6b325477..0fdd36614d8db6f52d1bdc6f8bf2e5a667edeff0 100644 (file)
@@ -102,7 +102,7 @@ branches::
 hooks::
        Hooks are customization scripts used by various git
        commands.  A handful of sample hooks are installed when
-       `git init-db` is run, but all of them are disabled by
+       `git init` is run, but all of them are disabled by
        default.  To enable, they need to be made executable.
        Read link:hooks.html[hooks] for more details about
        each hook.
index 21ff949ea2be33aa3a51becff87f4d97d871459c..8502e4c5b2cd0235583e975d1e3670b97a4341c3 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.4.5-rc0.GIT
+DEF_VER=v1.5.0-rc1.GIT
 
 LF='
 '
diff --git a/INSTALL b/INSTALL
index e7aea60e92eba80d63e9596d8d78b9447c292bcf..361c65bacc50b4038cb9a32bab07c275a1ecdc76 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -95,7 +95,7 @@ Issues of note:
    repository itself.  For example, you could:
 
        $ mkdir manual && cd manual
-       $ git init-db
+       $ git init
        $ git fetch-pack git://git.kernel.org/pub/scm/git/git.git man html |
          while read a b
          do
index d3df5a57f127f44d7ff48a419d51ca108c7c9618..c760e188ea4169d878986ebd0d6c22702802aa59 100644 (file)
@@ -275,7 +275,7 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
        }
 }
 
-static void print_ref_list(int kinds, int verbose, int abbrev)
+static void print_ref_list(int kinds, int detached, int verbose, int abbrev)
 {
        int i;
        struct ref_list ref_list;
@@ -286,8 +286,20 @@ static void print_ref_list(int kinds, int verbose, int abbrev)
 
        qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp);
 
+       detached = (detached && (kinds & REF_LOCAL_BRANCH));
+       if (detached) {
+               struct ref_item item;
+               item.name = "(no branch)";
+               item.kind = REF_LOCAL_BRANCH;
+               hashcpy(item.sha1, head_sha1);
+               if (strlen(item.name) > ref_list.maxwidth)
+                             ref_list.maxwidth = strlen(item.name);
+               print_ref_item(&item, ref_list.maxwidth, verbose, abbrev, 1);
+       }
+
        for (i = 0; i < ref_list.index; i++) {
-               int current = (ref_list.list[i].kind == REF_LOCAL_BRANCH) &&
+               int current = !detached &&
+                       (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);
@@ -296,7 +308,8 @@ static void print_ref_list(int kinds, int verbose, int abbrev)
        free_ref_list(&ref_list);
 }
 
-static void create_branch(const char *name, const char *start,
+static void create_branch(const char *name, const char *start_name,
+                         unsigned char *start_sha1,
                          int force, int reflog)
 {
        struct ref_lock *lock;
@@ -315,9 +328,14 @@ static void create_branch(const char *name, const char *start,
                        die("Cannot force update the current branch.");
        }
 
-       if (get_sha1(start, sha1) ||
-           (commit = lookup_commit_reference(sha1)) == NULL)
-               die("Not a valid branch point: '%s'.", start);
+       if (start_sha1)
+               /* detached HEAD */
+               hashcpy(sha1, start_sha1);
+       else if (get_sha1(start_name, sha1))
+               die("Not a valid object name: '%s'.", start_name);
+
+       if ((commit = lookup_commit_reference(sha1)) == NULL)
+               die("Not a valid branch point: '%s'.", start_name);
        hashcpy(sha1, commit->object.sha1);
 
        lock = lock_any_ref_for_update(ref, NULL);
@@ -326,7 +344,8 @@ static void create_branch(const char *name, const char *start,
 
        if (reflog) {
                log_all_ref_updates = 1;
-               snprintf(msg, sizeof msg, "branch: Created from %s", start);
+               snprintf(msg, sizeof msg, "branch: Created from %s",
+                        start_name);
        }
 
        if (write_ref_sha1(lock, sha1, msg) < 0)
@@ -338,6 +357,9 @@ static void rename_branch(const char *oldname, const char *newname, int force)
        char oldref[PATH_MAX], newref[PATH_MAX], logmsg[PATH_MAX*2 + 100];
        unsigned char sha1[20];
 
+       if (!oldname)
+               die("cannot rename the curren branch while not on any.");
+
        if (snprintf(oldref, sizeof(oldref), "refs/heads/%s", oldname) > sizeof(oldref))
                die("Old branchname too long");
 
@@ -367,7 +389,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 {
        int delete = 0, force_delete = 0, force_create = 0;
        int rename = 0, force_rename = 0;
-       int verbose = 0, abbrev = DEFAULT_ABBREV;
+       int verbose = 0, abbrev = DEFAULT_ABBREV, detached = 0;
        int reflog = 0;
        int kinds = REF_LOCAL_BRANCH;
        int i;
@@ -444,22 +466,27 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
        head = xstrdup(resolve_ref("HEAD", head_sha1, 0, NULL));
        if (!head)
                die("Failed to resolve HEAD as a valid ref.");
-       if (strncmp(head, "refs/heads/", 11))
-               die("HEAD not found below refs/heads!");
-       head += 11;
+       if (!strcmp(head, "HEAD")) {
+               detached = 1;
+       }
+       else {
+               if (strncmp(head, "refs/heads/", 11))
+                       die("HEAD not found below refs/heads!");
+               head += 11;
+       }
 
        if (delete)
                return delete_branches(argc - i, argv + i, force_delete, kinds);
        else if (i == argc)
-               print_ref_list(kinds, verbose, abbrev);
+               print_ref_list(kinds, detached, verbose, abbrev);
        else if (rename && (i == argc - 1))
                rename_branch(head, argv[i], force_rename);
        else if (rename && (i == argc - 2))
                rename_branch(argv[i], argv[i + 1], force_rename);
        else if (i == argc - 1)
-               create_branch(argv[i], head, force_create, reflog);
+               create_branch(argv[i], head, head_sha1, force_create, reflog);
        else if (i == argc - 2)
-               create_branch(argv[i], argv[i + 1], force_create, reflog);
+               create_branch(argv[i], argv[i+1], NULL, force_create, reflog);
        else
                usage(builtin_branch_usage);
 
index ad3b469f372c6c62b3b6ba2c36c2a80874743e6d..a8c98cea163a28cafb9b23861bd976b6354c2def 100644 (file)
@@ -2,10 +2,11 @@
 #include "commit.h"
 #include "tag.h"
 #include "refs.h"
+#include "diff.h"
+#include "diffcore.h"
+#include "revision.h"
 #include "builtin.h"
 
-#define SEEN (1u << 0)
-
 static const char describe_usage[] =
 "git-describe [--all] [--tags] [--abbrev=<n>] <committish>*";
 
@@ -16,7 +17,7 @@ static int abbrev = DEFAULT_ABBREV;
 
 static int names, allocs;
 static struct commit_name {
-       const struct commit *commit;
+       struct commit *commit;
        int prio; /* annotated tag = 2, tag = 1, head = 0 */
        char path[FLEX_ARRAY]; /* more */
 } **name_array = NULL;
@@ -35,7 +36,7 @@ static struct commit_name *match(struct commit *cmit)
 }
 
 static void add_to_known_names(const char *path,
-                              const struct commit *commit,
+                              struct commit *commit,
                               int prio)
 {
        int idx;
@@ -98,6 +99,12 @@ static int compare_names(const void *_a, const void *_b)
        return (a_date > b_date) ? -1 : (a_date == b_date) ? 0 : 1;
 }
 
+struct possible_tag {
+       struct possible_tag *next;
+       struct commit_name *name;
+       unsigned long depth;
+};
+
 static void describe(const char *arg, int last_one)
 {
        unsigned char sha1[20];
@@ -105,6 +112,7 @@ static void describe(const char *arg, int last_one)
        struct commit_list *list;
        static int initialized = 0;
        struct commit_name *n;
+       struct possible_tag *all_matches, *min_match, *cur_match;
 
        if (get_sha1(arg, sha1))
                die("Not a valid object name %s", arg);
@@ -125,19 +133,68 @@ static void describe(const char *arg, int last_one)
        }
 
        list = NULL;
+       all_matches = NULL;
+       cur_match = NULL;
        commit_list_insert(cmit, &list);
        while (list) {
-               struct commit *c = pop_most_recent_commit(&list, SEEN);
+               struct commit *c = pop_commit(&list);
                n = match(c);
                if (n) {
-                       printf("%s-g%s\n", n->path,
-                              find_unique_abbrev(cmit->object.sha1, abbrev));
-                       if (!last_one)
-                               clear_commit_marks(cmit, SEEN);
-                       return;
+                       struct possible_tag *p = xmalloc(sizeof(*p));
+                       p->name = n;
+                       p->next = NULL;
+                       if (cur_match)
+                               cur_match->next = p;
+                       else
+                               all_matches = p;
+                       cur_match = p;
+               } else {
+                       struct commit_list *parents = c->parents;
+                       while (parents) {
+                               struct commit *p = parents->item;
+                               parse_commit(p);
+                               if (!(p->object.flags & SEEN)) {
+                                       p->object.flags |= SEEN;
+                                       insert_by_date(p, &list);
+                               }
+                               parents = parents->next;
+                       }
+               }
+       }
+
+       if (!all_matches)
+               die("cannot describe '%s'", sha1_to_hex(cmit->object.sha1));
+
+       min_match = NULL;
+       for (cur_match = all_matches; cur_match; cur_match = cur_match->next) {
+               struct rev_info revs;
+               struct commit *tagged = cur_match->name->commit;
+
+               clear_commit_marks(cmit, -1);
+               init_revisions(&revs, NULL);
+               tagged->object.flags |= UNINTERESTING;
+               add_pending_object(&revs, &tagged->object, NULL);
+               add_pending_object(&revs, &cmit->object, NULL);
+
+               prepare_revision_walk(&revs);
+               cur_match->depth = 0;
+               while ((!min_match || cur_match->depth < min_match->depth)
+                       && get_revision(&revs))
+                       cur_match->depth++;
+               if (!min_match || cur_match->depth < min_match->depth)
+                       min_match = cur_match;
+               free_commit_list(revs.commits);
+       }
+       printf("%s-g%s\n", min_match->name->path,
+                  find_unique_abbrev(cmit->object.sha1, abbrev));
+
+       if (!last_one) {
+               for (cur_match = all_matches; cur_match; cur_match = min_match) {
+                       min_match = cur_match->next;
+                       free(cur_match);
                }
+               clear_commit_marks(cmit, SEEN);
        }
-       die("cannot describe '%s'", sha1_to_hex(cmit->object.sha1));
 }
 
 int cmd_describe(int argc, const char **argv, const char *prefix)
index bbef820e478dd91cfe63431adf3cecc30e437416..8e7540b6922696fb8100879eb9c4acf587f004db 100644 (file)
@@ -56,7 +56,7 @@ static void copy_templates_1(char *path, int baselen,
 
        /* Note: if ".git/hooks" file exists in the repository being
         * re-initialized, /etc/core-git/templates/hooks/update would
-        * cause git-init-db to fail here.  I think this is sane but
+        * cause git-init to fail here.  I think this is sane but
         * it means that the set of templates we ship by default, along
         * with the way the namespace under .git/ is organized, should
         * be really carefully chosen.
@@ -252,9 +252,13 @@ static int create_default_files(const char *git_dir, const char *template_path)
        }
        git_config_set("core.filemode", filemode ? "true" : "false");
 
-       /* Enable logAllRefUpdates if a working tree is attached */
-       if (!is_bare_git_dir(git_dir))
+       if (is_bare_repository()) {
+               git_config_set("core.bare", "true");
+       }
+       else {
+               git_config_set("core.bare", "false");
                git_config_set("core.logallrefupdates", "true");
+       }
        return reinit;
 }
 
index 24e3b0a8c21b43e0e82e5e505353213ca79f01b0..a57b76d7b7496f3cf81914672845bdebc75c91f8 100644 (file)
@@ -4,7 +4,10 @@
 static const char prune_packed_usage[] =
 "git-prune-packed [-n]";
 
-static void prune_dir(int i, DIR *dir, char *pathname, int len, int dryrun)
+#define DRY_RUN 01
+#define VERBOSE 02
+
+static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts)
 {
        struct dirent *de;
        char hex[40];
@@ -20,7 +23,7 @@ static void prune_dir(int i, DIR *dir, char *pathname, int len, int dryrun)
                if (!has_sha1_pack(sha1, NULL))
                        continue;
                memcpy(pathname + len, de->d_name, 38);
-               if (dryrun)
+               if (opts & DRY_RUN)
                        printf("rm -f %s\n", pathname);
                else if (unlink(pathname) < 0)
                        error("unable to unlink %s", pathname);
@@ -29,7 +32,7 @@ static void prune_dir(int i, DIR *dir, char *pathname, int len, int dryrun)
        rmdir(pathname);
 }
 
-void prune_packed_objects(int dryrun)
+void prune_packed_objects(int opts)
 {
        int i;
        static char pathname[PATH_MAX];
@@ -46,24 +49,31 @@ void prune_packed_objects(int dryrun)
 
                sprintf(pathname + len, "%02x/", i);
                d = opendir(pathname);
+               if (opts == VERBOSE && (d || i == 255))
+                       fprintf(stderr, "Removing unused objects %d%%...\015",
+                               ((i+1) * 100) / 256);
                if (!d)
                        continue;
-               prune_dir(i, d, pathname, len + 3, dryrun);
+               prune_dir(i, d, pathname, len + 3, opts);
                closedir(d);
        }
+       if (opts == VERBOSE)
+               fprintf(stderr, "\nDone.\n");
 }
 
 int cmd_prune_packed(int argc, const char **argv, const char *prefix)
 {
        int i;
-       int dryrun = 0;
+       int opts = VERBOSE;
 
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
 
                if (*arg == '-') {
                        if (!strcmp(arg, "-n"))
-                               dryrun = 1;
+                               opts |= DRY_RUN;
+                       else if (!strcmp(arg, "-q"))
+                               opts &= ~VERBOSE;
                        else
                                usage(prune_packed_usage);
                        continue;
@@ -72,6 +82,6 @@ int cmd_prune_packed(int argc, const char **argv, const char *prefix)
                usage(prune_packed_usage);
        }
        sync();
-       prune_packed_objects(dryrun);
+       prune_packed_objects(opts);
        return 0;
 }
index ca22452e64f99a24f5f13923d2d6a756bcf82ade..7206b7a0139099c78b36f53c84705312f8daf8e5 100644 (file)
@@ -173,7 +173,6 @@ static int keep_entry(struct commit **it, unsigned char *sha1)
 {
        struct commit *commit;
 
-       *it = NULL;
        if (is_null_sha1(sha1))
                return 1;
        commit = lookup_commit_reference_gently(sha1, 1);
@@ -204,15 +203,22 @@ static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
        if (timestamp < cb->cmd->expire_total)
                goto prune;
 
+       old = new = NULL;
        if (cb->cmd->stalefix &&
            (!keep_entry(&old, osha1) || !keep_entry(&new, nsha1)))
                goto prune;
 
-       if ((timestamp < cb->cmd->expire_unreachable) &&
-           (!cb->ref_commit ||
-            (old && !in_merge_bases(old, cb->ref_commit)) ||
-            (new && !in_merge_bases(new, cb->ref_commit))))
-               goto prune;
+       if (timestamp < cb->cmd->expire_unreachable) {
+               if (!cb->ref_commit)
+                       goto prune;
+               if (!old && !is_null_sha1(osha1))
+                       old = lookup_commit_reference_gently(osha1, 1);
+               if (!new && !is_null_sha1(nsha1))
+                       new = lookup_commit_reference_gently(nsha1, 1);
+               if ((old && !in_merge_bases(old, cb->ref_commit)) ||
+                   (new && !in_merge_bases(new, cb->ref_commit)))
+                       goto prune;
+       }
 
        if (cb->newlog) {
                char sign = (tz < 0) ? '-' : '+';
index 5b078c41943c9ce0ff1983896e8ad6ae38705f60..d81f289c3c28fa9afbc99facf6ea81b68306a46d 100644 (file)
@@ -32,6 +32,10 @@ static int remove_file(const char *name)
        char *slash;
 
        ret = unlink(name);
+       if (ret && errno == ENOENT)
+               /* The user has removed it from the filesystem by hand */
+               ret = errno = 0;
+
        if (!ret && (slash = strrchr(name, '/'))) {
                char *n = xstrdup(name);
                do {
@@ -204,7 +208,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
                return 0;
 
        /*
-        * Then, unless we used "--cache", remove the filenames from
+        * Then, unless we used "--cached", remove the filenames from
         * the workspace. If we fail to remove the first one, we
         * abort the "git rm" (but once we've successfully removed
         * any file at all, we'll go ahead and commit to it all:
diff --git a/cache.h b/cache.h
index a9583ff18eec46bf945ef820ea4a41fe51e0a4b1..620b6a4ed47b9b94700a7f9bec270aca7efe29db 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -127,7 +127,8 @@ extern int cache_errno;
 #define CONFIG_LOCAL_ENVIRONMENT "GIT_CONFIG_LOCAL"
 #define EXEC_PATH_ENVIRONMENT "GIT_EXEC_PATH"
 
-extern int is_bare_git_dir(const char *dir);
+extern int is_bare_repository_cfg;
+extern int is_bare_repository(void);
 extern const char *get_git_dir(void);
 extern char *get_object_directory(void);
 extern char *get_refs_directory(void);
@@ -299,7 +300,7 @@ extern char *sha1_to_hex(const unsigned char *sha1);        /* static buffer result! */
 extern int read_ref(const char *filename, unsigned char *sha1);
 extern const char *resolve_ref(const char *path, unsigned char *sha1, int, int *);
 extern int create_symref(const char *ref, const char *refs_heads_master);
-extern int validate_symref(const char *ref);
+extern int validate_headref(const char *ref);
 
 extern int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
 extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2);
@@ -433,7 +434,6 @@ extern char *git_log_output_encoding;
 
 extern int copy_fd(int ifd, int ofd);
 extern int read_in_full(int fd, void *buf, size_t count);
-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);
 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);
index 2cd0263e13cab1b445498d82e73d1ca09b0b58f0..b6082f597c118d75a9342d1e0bf5788c7a8257ee 100644 (file)
--- a/config.c
+++ b/config.c
@@ -269,6 +269,11 @@ int git_default_config(const char *var, const char *value)
                return 0;
        }
 
+       if (!strcmp(var, "core.bare")) {
+               is_bare_repository_cfg = git_config_bool(var, value);
+               return 0;
+       }
+
        if (!strcmp(var, "core.ignorestat")) {
                assume_unchanged = git_config_bool(var, value);
                return 0;
@@ -694,11 +699,9 @@ int git_config_set_multivar(const char* key, const char* value,
 
                store.key = (char*)key;
                if (!store_write_section(fd, key) ||
-                   !store_write_pair(fd, key, value)) {
-                       ret = write_error();
-                       goto out_free;
-               }
-       } else{
+                   !store_write_pair(fd, key, value))
+                       goto write_err_out;
+       } else {
                struct stat st;
                char* contents;
                int i, copy_begin, copy_end, new_line = 0;
@@ -777,31 +780,33 @@ int git_config_set_multivar(const char* key, const char* value,
 
                        /* write the first part of the config */
                        if (copy_end > copy_begin) {
-                               write_in_full(fd, contents + copy_begin,
-                               copy_end - copy_begin);
-                               if (new_line)
-                                       write_in_full(fd, "\n", 1);
+                               if (write_in_full(fd, contents + copy_begin,
+                                                 copy_end - copy_begin) <
+                                   copy_end - copy_begin)
+                                       goto write_err_out;
+                               if (new_line &&
+                                   write_in_full(fd, "\n", 1) != 1)
+                                       goto write_err_out;
                        }
                        copy_begin = store.offset[i];
                }
 
                /* write the pair (value == NULL means unset) */
                if (value != NULL) {
-                       if (store.state == START)
-                               if (!store_write_section(fd, key)) {
-                                       ret = write_error();
-                                       goto out_free;
-                               }
-                       if (!store_write_pair(fd, key, value)) {
-                               ret = write_error();
-                               goto out_free;
+                       if (store.state == START) {
+                               if (!store_write_section(fd, key))
+                                       goto write_err_out;
                        }
+                       if (!store_write_pair(fd, key, value))
+                               goto write_err_out;
                }
 
                /* write the rest of the config */
                if (copy_begin < st.st_size)
-                       write_in_full(fd, contents + copy_begin,
-                               st.st_size - copy_begin);
+                       if (write_in_full(fd, contents + copy_begin,
+                                         st.st_size - copy_begin) <
+                           st.st_size - copy_begin)
+                               goto write_err_out;
 
                munmap(contents, st.st_size);
                unlink(config_filename);
@@ -824,6 +829,11 @@ int git_config_set_multivar(const char* key, const char* value,
                free(lock_file);
        }
        return ret;
+
+write_err_out:
+       ret = write_error();
+       goto out_free;
+
 }
 
 int git_config_rename_section(const char *old_name, const char *new_name)
index 09976c7bf63a2a1f77854f8157d430c00c0e3473..54c22f8248cc04647829c8a7558f2bb24515f30f 100644 (file)
@@ -15,7 +15,8 @@ int use_legacy_headers = 1;
 int trust_executable_bit = 1;
 int assume_unchanged;
 int prefer_symlink_refs;
-int log_all_ref_updates;
+int is_bare_repository_cfg = -1; /* unspecified */
+int log_all_ref_updates = -1; /* unspecified */
 int warn_ambiguous_refs = 1;
 int repository_format_version;
 char *git_commit_encoding;
@@ -51,12 +52,15 @@ static void setup_git_env(void)
        git_graft_file = getenv(GRAFT_ENVIRONMENT);
        if (!git_graft_file)
                git_graft_file = xstrdup(git_path("info/grafts"));
-       log_all_ref_updates = !is_bare_git_dir(git_dir);
 }
 
-int is_bare_git_dir (const char *dir)
+int is_bare_repository(void)
 {
-       const char *s;
+       const char *dir, *s;
+       if (0 <= is_bare_repository_cfg)
+               return is_bare_repository_cfg;
+
+       dir = get_git_dir();
        if (!strcmp(dir, DEFAULT_GIT_DIR_ENVIRONMENT))
                return 0;
        s = strrchr(dir, '/');
index 0d8a8ebb4615c832a116a0278dfac3da1a737268..81f00db90b2f31d5362654a3e6a86f9cb93cf474 100644 (file)
@@ -290,7 +290,7 @@ static int fsck_sha1(unsigned char *sha1)
 {
        struct object *obj = parse_object(sha1);
        if (!obj)
-               return error("%s: object not found", sha1_to_hex(sha1));
+               return error("%s: object corrupt or missing", sha1_to_hex(sha1));
        if (obj->flags & SEEN)
                return 0;
        obj->flags |= SEEN;
index 1de14ea82fe678e3afb66ea11d6dd6e306158387..975777f05ed69ef78f1fd91ac512f5b92a384141 100755 (executable)
@@ -22,7 +22,7 @@ commit
 diff
 fetch
 grep
-init-db
+init
 log
 merge
 mv
index 59d663ba9e0c3828d11b442c6fd9536a87d937cb..1252f26bbd46484f25e58e92680e553f7fd7c1da 100755 (executable)
--- a/git-am.sh
+++ b/git-am.sh
@@ -7,6 +7,7 @@ USAGE='[--signoff] [--dotest=<dir>] [--utf8 | --no-utf8] [--binary] [--3way]
   or, when resuming [--skip | --resolved]'
 . git-sh-setup
 set_reflog_action am
+require_work_tree
 
 git var GIT_COMMITTER_IDENT >/dev/null || exit
 
index ada60ec240a8b3eb4ef6efea6b6223fc8523705f..2e15781246c4a5997eb595885801fe7c6e741495 100755 (executable)
@@ -226,7 +226,7 @@ sub do_abrowse {
 unless (-d $git_dir) { # initial import
     if ($psets[0]{type} eq 'i' || $psets[0]{type} eq 't') {
         print "Starting import from $psets[0]{id}\n";
-       `git-init-db`;
+       `git-init`;
        die $! if $?;
        $import = 1;
     } else {
index 92ec069a3acacc2d12c2c709311969f3d0aa4153..66e40b90ebfa8e65e9c42731203f10dde0424b8c 100755 (executable)
@@ -3,9 +3,11 @@
 USAGE='[-f] [-b <new_branch>] [-m] [<branch>] [<paths>...]'
 SUBDIRECTORY_OK=Sometimes
 . git-sh-setup
+require_work_tree
 
 old_name=HEAD
 old=$(git-rev-parse --verify $old_name 2>/dev/null)
+oldbranch=$(git-symbolic-ref $old_name 2>/dev/null)
 new=
 new_name=
 force=
@@ -13,6 +15,8 @@ branch=
 newbranch=
 newbranch_log=
 merge=
+LF='
+'
 while [ "$#" != "0" ]; do
     arg="$1"
     shift
@@ -50,7 +54,7 @@ while [ "$#" != "0" ]; do
                                exit 1
                        fi
                        new="$rev"
-                       new_name="$arg^0"
+                       new_name="$arg"
                        if git-show-ref --verify --quiet -- "refs/heads/$arg"
                        then
                                branch="$arg"
@@ -131,31 +135,53 @@ fi
 
 # We are switching branches and checking out trees, so
 # we *NEED* to be at the toplevel.
-cdup=$(git-rev-parse --show-cdup)
-if test ! -z "$cdup"
-then
-       cd "$cdup"
-fi
+cd_to_toplevel
 
 [ -z "$new" ] && new=$old && new_name="$old_name"
 
-# If we don't have an old branch that we're switching to,
+# If we don't have an existing branch that we're switching to,
 # and we don't have a new branch name for the target we
-# are switching to, then we'd better just be checking out
-# what we already had
+# are switching to, then we are detaching our HEAD from any
+# branch.  However, if "git checkout HEAD" detaches the HEAD
+# from the current branch, even though that may be logically
+# correct, it feels somewhat funny.  More importantly, we do not
+# want "git checkout" nor "git checkout -f" to detach HEAD.
 
-[ -z "$branch$newbranch" ] &&
-       [ "$new" != "$old" ] &&
-       die "git checkout: provided reference cannot be checked out directly
+detached=
+detach_warn=
 
-  You need -b to associate a new branch with the wanted checkout. Example:
-  git checkout -b <new_branch_name> $arg
-"
+if test -z "$branch$newbranch" && test "$new" != "$old"
+then
+       detached="$new"
+       if test -n "$oldbranch"
+       then
+               detach_warn="warning: you are not on ANY branch anymore.
+If you meant to create a new branch from the commit, you need -b to
+associate a new branch with the wanted checkout.  Example:
+  git checkout -b <new_branch_name> $arg"
+       fi
+elif test -z "$oldbranch" && test -n "$branch"
+then
+       # Coming back...
+       if test -z "$force"
+       then
+               git show-ref -d -s | grep "$old" >/dev/null || {
+                       echo >&2 \
+"You are not on any branch and switching to branch '$new_name'
+may lose your changes.  At this point, you can do one of two things:
+ (1) Decide it is Ok and say 'git checkout -f $new_name';
+ (2) Start a new branch from the current commit, by saying
+     'git checkout -b <branch-name>'.
+Leaving your HEAD detached; not switching to branch '$new_name'."
+                       exit 1;
+               }
+       fi
+fi
 
 if [ "X$old" = X ]
 then
-       echo "warning: You do not appear to currently be on a branch." >&2
-       echo "warning: Forcing checkout of $new_name." >&2
+       echo >&2 "warning: You appear to be on a branch yet to be born."
+       echo >&2 "warning: Forcing checkout of $new_name."
        force=1
 fi
 
@@ -226,8 +252,25 @@ if [ "$?" -eq 0 ]; then
                git-update-ref -m "checkout: Created from $new_name" "refs/heads/$newbranch" $new || exit
                branch="$newbranch"
        fi
-       [ "$branch" ] &&
-       GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD "refs/heads/$branch"
+       if test -n "$branch"
+       then
+               GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD "refs/heads/$branch"
+       elif test -n "$detached"
+       then
+               # NEEDSWORK: we would want a command to detach the HEAD
+               # atomically, instead of this handcrafted command sequence.
+               # Perhaps:
+               #       git update-ref --detach HEAD $new
+               # or something like that...
+               #
+               echo "$detached" >"$GIT_DIR/HEAD.new" &&
+               mv "$GIT_DIR/HEAD.new" "$GIT_DIR/HEAD" ||
+                       die "Cannot detach HEAD"
+               if test -n "$detach_warn"
+               then
+                       echo >&2 "$detach_warn"
+               fi
+       fi
        rm -f "$GIT_DIR/MERGE_HEAD"
 else
        exit 1
index 071b974f496b8deff3a2d1b869c35d4f556dc17f..db177a7886b6407b4c4ad7b778a1ae99471355ac 100755 (executable)
@@ -14,6 +14,7 @@ When optional <paths>... arguments are given, the paths
 affected are further limited to those that match them.'
 SUBDIRECTORY_OK=Yes
 . git-sh-setup
+require_work_tree
 
 ignored=
 ignoredonly=
index cf761b2c694d9e6cbcfc8cd1e075095d34ba857b..0f7bbbfb39cb4eb08379b8441b1ceab3d55d18e5 100755 (executable)
@@ -214,7 +214,7 @@ yes)
        GIT_DIR="$D" ;;
 *)
        GIT_DIR="$D/.git" ;;
-esac && export GIT_DIR && git-init-db ${template+"$template"} || usage
+esac && export GIT_DIR && git-init ${template+"$template"} || usage
 
 if test -n "$reference"
 then
index c2beb76fe436279422ff5212aed573fb821bad7b..9fdf234b522322cf4e5d539f52debe76bebf6aa8 100755 (executable)
@@ -6,6 +6,7 @@
 USAGE='[-a] [-s] [-v] [--no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit>] [-u] [--amend] [-e] [--author <author>] [[-i | -o] <path>...]'
 SUBDIRECTORY_OK=Yes
 . git-sh-setup
+require_work_tree
 
 git-rev-parse --verify HEAD >/dev/null 2>&1 || initial_commit=t
 
@@ -315,22 +316,16 @@ esac
 ################################################################
 # Prepare index to have a tree to be committed
 
-TOP=`git-rev-parse --show-cdup`
-if test -z "$TOP"
-then
-       TOP=./
-fi
-
 case "$all,$also" in
 t,)
        save_index &&
        (
-               cd "$TOP"
-               GIT_INDEX_FILE="$NEXT_INDEX"
-               export GIT_INDEX_FILE
+               cd_to_toplevel &&
+               GIT_INDEX_FILE="$NEXT_INDEX" &&
+               export GIT_INDEX_FILE &&
                git-diff-files --name-only -z |
                git-update-index --remove -z --stdin
-       )
+       ) || exit
        ;;
 ,t)
        save_index &&
@@ -338,11 +333,11 @@ t,)
 
        git-diff-files --name-only -z -- "$@"  |
        (
-               cd "$TOP"
-               GIT_INDEX_FILE="$NEXT_INDEX"
-               export GIT_INDEX_FILE
+               cd_to_toplevel &&
+               GIT_INDEX_FILE="$NEXT_INDEX" &&
+               export GIT_INDEX_FILE &&
                git-update-index --remove -z --stdin
-       )
+       ) || exit
        ;;
 ,)
        case "$#" in
index f8d46d587bec2b4dbab0263fa3df97e60beb08e4..8781e8e22d575c155967c8766f5d74835c0b1f78 100644 (file)
@@ -202,6 +202,8 @@ static inline void *xmmap(void *start, size_t length,
 {
        void *ret = mmap(start, length, prot, flags, fd, offset);
        if (ret == MAP_FAILED) {
+               if (!length)
+                       return NULL;
                release_pack_memory(length);
                ret = mmap(start, length, prot, flags, fd, offset);
                if (ret == MAP_FAILED)
index 1018f4f6fa42c16a11930283f8ddf2c2f87642d3..35ef0c0ee54a8f284c1afd7754f2e69e03d925c1 100755 (executable)
@@ -520,7 +520,7 @@ ($$)
 my %index; # holds filenames of one index per branch
 
 unless (-d $git_dir) {
-       system("git-init-db");
+       system("git-init");
        die "Cannot init the GIT db at $git_tree: $?\n" if $?;
        system("git-read-tree");
        die "Cannot init an empty tree: $?\n" if $?;
@@ -660,7 +660,7 @@ ()
 sub commit {
        if ($branch eq $opt_o && !$index{branch} && !get_headref($branch, $git_dir)) {
            # looks like an initial commit
-           # use the index primed by git-init-db
+           # use the index primed by git-init
            $ENV{GIT_INDEX_FILE} = '.git/index';
            $index{$branch} = '.git/index';
        } else {
index 466fe59e35e03a6f9955f78e4238d9e0a60b8dc0..87b940b85b5b128f29dc6084bb545640e5bf6b92 100755 (executable)
@@ -5,12 +5,8 @@ USAGE='<fetch-options> <repository> <refspec>...'
 SUBDIRECTORY_OK=Yes
 . git-sh-setup
 set_reflog_action "fetch $*"
+cd_to_toplevel ;# probably unnecessary...
 
-TOP=$(git-rev-parse --show-cdup)
-if test ! -z "$TOP"
-then
-       cd "$TOP"
-fi
 . git-parse-remote
 _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
 _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
@@ -231,11 +227,12 @@ update_local_ref () {
     esac
 }
 
-case "$update_head_ok" in
-'')
+# updating the current HEAD with git-fetch in a bare
+# repository is always fine.
+if test -z "$update_head_ok" && test $(is_bare_repository) = false
+then
        orig_head=$(git-rev-parse --verify HEAD 2>/dev/null)
-       ;;
-esac
+fi
 
 # If --tags (and later --heads or --all) is specified, then we are
 # not talking about defaults stored in Pull: line of remotes or
index 1c4f6693f5b6919da2a867a02465a382477cfcac..7b590268edb44cc5455fe9bdbcbfc0698a6fb800 100755 (executable)
@@ -5,11 +5,14 @@
 
 USAGE='[-n] [--no-commit] [--squash] [-s <strategy>] [-m=<merge-message>] <commit>+'
 
+SUBDIRECTORY_OK=Yes
 . git-sh-setup
 set_reflog_action "merge $*"
+require_work_tree
+cd_to_toplevel
 
 test -z "$(git ls-files -u)" ||
-       die "You are in a middle of conflicted merge."
+       die "You are in the middle of a conflicted merge."
 
 LF='
 '
index 908941dd77007e71f5aa036bb190a14d628050c8..5c56cace0ef132c117e9e0f5624eaf375a5b84d2 100644 (file)
@@ -163,7 +163,7 @@ def __init__(self):
             self.gitdir = self.get_single("rev-parse --git-dir")
             report(2, "gdir:", self.gitdir)
         except:
-            die("Not a git repository... did you forget to \"git init-db\" ?")
+            die("Not a git repository... did you forget to \"git init\" ?")
         try:
             self.cdup = self.get_single("rev-parse --show-cdup")
             if self.cdup != "":
index c184fb81a4dab622d79120bcc986c3bf2b07df7f..959261757c1fd8df50f7894ba449b76d621f3c45 100755 (executable)
@@ -6,11 +6,14 @@
 
 USAGE='[-n | --no-summary] [--no-commit] [-s strategy]... [<fetch-options>] <repo> <head>...'
 LONG_USAGE='Fetch one or more remote refs and merge it/them into the current HEAD.'
+SUBDIRECTORY_OK=Yes
 . git-sh-setup
 set_reflog_action "pull $*"
+require_work_tree
+cd_to_toplevel
 
 test -z "$(git ls-files -u)" ||
-       die "You are in a middle of conflicted merge."
+       die "You are in the middle of a conflicted merge."
 
 strategy_args= no_summary= no_commit= squash=
 while case "$#,$1" in 0) break ;; *,-*) ;; *) break ;; esac
index 828c59ce61a8317f23ba9113e4de6e09a58e70ce..c8bd0f99d1306cd311eaf45f73581efc8bb0e512 100755 (executable)
@@ -27,8 +27,12 @@ Example:       git-rebase master~1 topic
        /                   -->           /
   D---E---F---G master          D---E---F---G master
 '
+
+SUBDIRECTORY_OK=Yes
 . git-sh-setup
 set_reflog_action rebase
+require_work_tree
+cd_to_toplevel
 
 RESOLVEMSG="
 When you have resolved this problem run \"git rebase --continue\".
index 059c141b68e829c7114d09ed9f4541b9db4c3d66..fc055b6d9577b8667e104a9e1528f43cfe29f7e3 100755 (executable)
@@ -274,4 +274,9 @@ sub add_remote {
        }
        add_remote($ARGV[1], $ARGV[2]);
 }
-
+else {
+       print STDERR "Usage: git remote\n";
+       print STDERR "       git remote add <name> <url>\n";
+       print STDERR "       git remote show <name>\n";
+       exit(1);
+}
index 375434b1dcdd3183c85b1278c4415e9136508192..da8e67f7a558229aa09216e7eb74713ca6c970cd 100755 (executable)
@@ -110,7 +110,7 @@ then
                  done
                )
        fi
-       git-prune-packed
+       git-prune-packed $quiet
 fi
 
 case "$no_update_info" in
index 76c8a818d421c796141fae3835e1cb4726d23ef3..91c7e6e664eeac0a130044d3d026ccbbfa00f3b3 100755 (executable)
@@ -6,6 +6,7 @@ USAGE='[--mixed | --soft | --hard]  [<commit-ish>] [ [--] <paths>...]'
 SUBDIRECTORY_OK=Yes
 . git-sh-setup
 set_reflog_action "reset $*"
+require_work_tree
 
 update= reset_type=--mixed
 unset rev
@@ -52,11 +53,7 @@ then
        exit
 fi
 
-TOP=$(git-rev-parse --show-cdup)
-if test ! -z "$TOP"
-then
-       cd "$TOP"
-fi
+cd_to_toplevel
 
 if test "$reset_type" = "--hard"
 then
index 50cc47b0634201e7acaaa0a0642be779aaf7c2da..224e6540ca073da804332799660a8cdeacdfdaf7 100755 (executable)
@@ -16,9 +16,14 @@ case "$0" in
        me=cherry-pick
        USAGE='[--edit] [-n] [-r] [-x] <commit-ish>'  ;;
 * )
-       die "What are you talking about?" ;;
+       echo >&2 "What are you talking about?"
+       exit 1 ;;
 esac
+
+SUBDIRECTORY_OK=Yes ;# we will cd up
 . git-sh-setup
+require_work_tree
+cd_to_toplevel
 
 no_commit=
 while case "$#" in 0) break ;; esac
index 87b939c0e4857ec9c9245c01f609a059788f656a..6b1c1423ebb7fde53aae566fa09211d331c422bc 100755 (executable)
@@ -28,6 +28,30 @@ set_reflog_action() {
        fi
 }
 
+is_bare_repository () {
+       git-repo-config --bool --get core.bare ||
+       case "$GIT_DIR" in
+       .git | */.git) echo false ;;
+       *) echo true ;;
+       esac
+}
+
+cd_to_toplevel () {
+       cdup=$(git-rev-parse --show-cdup)
+       if test ! -z "$cdup"
+       then
+               cd "$cdup" || {
+                       echo >&2 "Cannot chdir to $cdup, the toplevel of the working tree"
+                       exit 1
+               }
+       fi
+}
+
+require_work_tree () {
+       test $(is_bare_repository) = false ||
+       die "fatal: $0 cannot be used without a working tree."
+}
+
 if [ -z "$LONG_USAGE" ]
 then
        LONG_USAGE="Usage: $0 $USAGE"
@@ -47,7 +71,11 @@ esac
 if [ -z "$SUBDIRECTORY_OK" ]
 then
        : ${GIT_DIR=.git}
-       GIT_DIR=$(GIT_DIR="$GIT_DIR" git-rev-parse --git-dir) || exit
+       GIT_DIR=$(GIT_DIR="$GIT_DIR" git-rev-parse --git-dir) || {
+               exit=$?
+               echo >&2 "You need to run this command from the toplevel of the working tree."
+               exit $exit
+       }
 else
        GIT_DIR=$(git-rev-parse --git-dir) || exit
 fi
index 56f17002d1647d5a0e0c59a78a60bd96496dcf1b..9986a0c9bb29fe348050775ba06fd93c89bb11b5 100755 (executable)
@@ -286,7 +286,7 @@ sub init {
 
        $SVN_URL = $url;
        unless (-d $GIT_DIR) {
-               my @init_db = ('init-db');
+               my @init_db = ('init');
                push @init_db, "--template=$_template" if defined $_template;
                push @init_db, "--shared" if defined $_shared;
                command_noisy(@init_db);
index f1f1a7dbedcf09a5b62f49ca62029bbc9ecbec14..3af8c7e1106d755b1589750ff5673ff6a6cd3b14 100755 (executable)
@@ -285,7 +285,7 @@ ($$)
 my $last_branch;
 my $current_rev = $opt_s || 1;
 unless(-d $git_dir) {
-       system("git-init-db");
+       system("git-init");
        die "Cannot init the GIT db at $git_tree: $?\n" if $?;
        system("git-read-tree");
        die "Cannot init an empty tree: $?\n" if $?;
diff --git a/git.c b/git.c
index 9ce545d67693c8713b4254d5fa0e186723e348c2..72a1486f30a93c6822611c834a391bfc351c398f 100644 (file)
--- a/git.c
+++ b/git.c
@@ -199,6 +199,11 @@ const char git_version_string[] = GIT_VERSION;
 
 #define RUN_SETUP      (1<<0)
 #define USE_PAGER      (1<<1)
+/*
+ * require working tree to be present -- anything uses this needs
+ * RUN_SETUP for reading from the configuration file.
+ */
+#define NOT_BARE       (1<<2)
 
 static void handle_internal_command(int argc, const char **argv, char **envp)
 {
@@ -208,7 +213,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
                int (*fn)(int, const char **, const char *);
                int option;
        } commands[] = {
-               { "add", cmd_add, RUN_SETUP },
+               { "add", cmd_add, RUN_SETUP | NOT_BARE },
                { "annotate", cmd_annotate, },
                { "apply", cmd_apply },
                { "archive", cmd_archive },
@@ -240,7 +245,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
                { "mailinfo", cmd_mailinfo },
                { "mailsplit", cmd_mailsplit },
                { "merge-file", cmd_merge_file },
-               { "mv", cmd_mv, RUN_SETUP },
+               { "mv", cmd_mv, RUN_SETUP | NOT_BARE },
                { "name-rev", cmd_name_rev, RUN_SETUP },
                { "pack-objects", cmd_pack_objects, RUN_SETUP },
                { "pickaxe", cmd_blame, RUN_SETUP | USE_PAGER },
@@ -253,8 +258,8 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
                { "rerere", cmd_rerere, RUN_SETUP },
                { "rev-list", cmd_rev_list, RUN_SETUP },
                { "rev-parse", cmd_rev_parse, RUN_SETUP },
-               { "rm", cmd_rm, RUN_SETUP },
-               { "runstatus", cmd_runstatus, RUN_SETUP },
+               { "rm", cmd_rm, RUN_SETUP | NOT_BARE },
+               { "runstatus", cmd_runstatus, RUN_SETUP | NOT_BARE },
                { "shortlog", cmd_shortlog, RUN_SETUP | USE_PAGER },
                { "show-branch", cmd_show_branch, RUN_SETUP },
                { "show", cmd_show, RUN_SETUP | USE_PAGER },
@@ -291,6 +296,8 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
                        prefix = setup_git_directory();
                if (p->option & USE_PAGER)
                        setup_pager();
+               if ((p->option & NOT_BARE) && is_bare_repository())
+                       die("%s cannot be used in a bare git directory", cmd);
                trace_argv_printf(argv, argc, "trace: built-in: git");
 
                exit(p->fn(argc, argv, prefix));
index 8d10d6ba243ee99d698ddbb7651a10422cc5c9ba..72e0962415d74c856917f6bb56e6fa2fea950c25 100644 (file)
@@ -814,7 +814,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
                char buf[48];
                int len = snprintf(buf, sizeof(buf), "%s\t%s\n",
                                   report, sha1_to_hex(sha1));
-               write_in_full(1, buf, len);
+               write_or_die(1, buf, len);
 
                /*
                 * Let's just mimic git-unpack-objects here and write
index 87a27e0379c87efc8f04a4cf826f1bc7da242d34..b4acbb74080ad308625fcff09be0af51c2b4111d 100644 (file)
@@ -110,35 +110,6 @@ static void output_commit_title(struct commit *commit)
        }
 }
 
-static const char *current_index_file = NULL;
-static const char *original_index_file;
-static const char *temporary_index_file;
-static int cache_dirty = 0;
-
-static int flush_cache(void)
-{
-       /* flush temporary index */
-       struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
-       int fd = hold_lock_file_for_update(lock, current_index_file, 1);
-       if (write_cache(fd, active_cache, active_nr) ||
-                       close(fd) || commit_lock_file(lock))
-               die ("unable to write %s", current_index_file);
-       discard_cache();
-       cache_dirty = 0;
-       return 0;
-}
-
-static void setup_index(int temp)
-{
-       current_index_file = temp ? temporary_index_file: original_index_file;
-       if (cache_dirty) {
-               discard_cache();
-               cache_dirty = 0;
-       }
-       unlink(temporary_index_file);
-       discard_cache();
-}
-
 static struct cache_entry *make_cache_entry(unsigned int mode,
                const unsigned char *sha1, const char *path, int stage, int refresh)
 {
@@ -167,9 +138,6 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
                const char *path, int stage, int refresh, int options)
 {
        struct cache_entry *ce;
-       if (!cache_dirty)
-               read_cache_from(current_index_file);
-       cache_dirty++;
        ce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage, refresh);
        if (!ce)
                return error("cache_addinfo failed: %s", strerror(cache_errno));
@@ -187,26 +155,6 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
  */
 static int index_only = 0;
 
-static int git_read_tree(struct tree *tree)
-{
-       int rc;
-       struct object_list *trees = NULL;
-       struct unpack_trees_options opts;
-
-       if (cache_dirty)
-               die("read-tree with dirty cache");
-
-       memset(&opts, 0, sizeof(opts));
-       object_list_append(&tree->object, &trees);
-       rc = unpack_trees(trees, &opts);
-       cache_tree_free(&active_cache_tree);
-
-       if (rc == 0)
-               cache_dirty = 1;
-
-       return rc;
-}
-
 static int git_merge_trees(int index_only,
                           struct tree *common,
                           struct tree *head,
@@ -216,11 +164,6 @@ static int git_merge_trees(int index_only,
        struct object_list *trees = NULL;
        struct unpack_trees_options opts;
 
-       if (!cache_dirty) {
-               read_cache_from(current_index_file);
-               cache_dirty = 1;
-       }
-
        memset(&opts, 0, sizeof(opts));
        if (index_only)
                opts.index_only = 1;
@@ -236,39 +179,37 @@ static int git_merge_trees(int index_only,
 
        rc = unpack_trees(trees, &opts);
        cache_tree_free(&active_cache_tree);
-
-       cache_dirty = 1;
-
        return rc;
 }
 
+static int unmerged_index(void)
+{
+       int i;
+       for (i = 0; i < active_nr; i++) {
+               struct cache_entry *ce = active_cache[i];
+               if (ce_stage(ce))
+                       return 1;
+       }
+       return 0;
+}
+
 static struct tree *git_write_tree(void)
 {
        struct tree *result = NULL;
 
-       if (cache_dirty) {
-               unsigned i;
-               for (i = 0; i < active_nr; i++) {
-                       struct cache_entry *ce = active_cache[i];
-                       if (ce_stage(ce))
-                               return NULL;
-               }
-       } else
-               read_cache_from(current_index_file);
+       if (unmerged_index())
+               return NULL;
 
        if (!active_cache_tree)
                active_cache_tree = cache_tree();
 
        if (!cache_tree_fully_valid(active_cache_tree) &&
-                       cache_tree_update(active_cache_tree,
-                               active_cache, active_nr, 0, 0) < 0)
+           cache_tree_update(active_cache_tree,
+                             active_cache, active_nr, 0, 0) < 0)
                die("error building trees");
 
        result = lookup_tree(active_cache_tree->sha1);
 
-       flush_cache();
-       cache_dirty = 0;
-
        return result;
 }
 
@@ -331,10 +272,7 @@ static struct path_list *get_unmerged(void)
        int i;
 
        unmerged->strdup_paths = 1;
-       if (!cache_dirty) {
-               read_cache_from(current_index_file);
-               cache_dirty++;
-       }
+
        for (i = 0; i < active_nr; i++) {
                struct path_list_item *item;
                struct stage_data *e;
@@ -469,9 +407,6 @@ static int remove_file(int clean, const char *path, int no_wd)
        int update_working_directory = !index_only && !no_wd;
 
        if (update_cache) {
-               if (!cache_dirty)
-                       read_cache_from(current_index_file);
-               cache_dirty++;
                if (remove_file_from_cache(path))
                        return -1;
        }
@@ -954,8 +889,6 @@ static int process_renames(struct path_list *a_renames,
        path_list_clear(&a_by_dst, 0);
        path_list_clear(&b_by_dst, 0);
 
-       if (cache_dirty)
-               flush_cache();
        return clean_merge;
 }
 
@@ -1083,9 +1016,6 @@ static int process_entry(const char *path, struct stage_data *entry,
        } else
                die("Fatal merge failure, shouldn't happen.");
 
-       if (cache_dirty)
-               flush_cache();
-
        return clean_merge;
 }
 
@@ -1110,9 +1040,7 @@ static int merge_trees(struct tree *head,
                    sha1_to_hex(head->object.sha1),
                    sha1_to_hex(merge->object.sha1));
 
-       *result = git_write_tree();
-
-       if (!*result) {
+       if (unmerged_index()) {
                struct path_list *entries, *re_head, *re_merge;
                int i;
                path_list_clear(&current_file_set, 1);
@@ -1138,17 +1066,12 @@ static int merge_trees(struct tree *head,
                path_list_clear(re_head, 0);
                path_list_clear(entries, 1);
 
-               if (clean || index_only)
-                       *result = git_write_tree();
-               else
-                       *result = NULL;
-       } else {
-               clean = 1;
-               printf("merging of trees %s and %s resulted in %s\n",
-                      sha1_to_hex(head->object.sha1),
-                      sha1_to_hex(merge->object.sha1),
-                      sha1_to_hex((*result)->object.sha1));
        }
+       else
+               clean = 1;
+
+       if (index_only)
+               *result = git_write_tree();
 
        return clean;
 }
@@ -1173,10 +1096,10 @@ static int merge(struct commit *h1,
                 const char *branch1,
                 const char *branch2,
                 int call_depth /* =0 */,
-                struct commit *ancestor /* =None */,
+                struct commit_list *ca,
                 struct commit **result)
 {
-       struct commit_list *ca = NULL, *iter;
+       struct commit_list *iter;
        struct commit *merged_common_ancestors;
        struct tree *mrtree;
        int clean;
@@ -1185,10 +1108,10 @@ static int merge(struct commit *h1,
        output_commit_title(h1);
        output_commit_title(h2);
 
-       if (ancestor)
-               commit_list_insert(ancestor, &ca);
-       else
-               ca = reverse_commit_list(get_merge_bases(h1, h2, 1));
+       if (!ca) {
+               ca = get_merge_bases(h1, h2, 1);
+               ca = reverse_commit_list(ca);
+       }
 
        output("found %u common ancestor(s):", commit_list_count(ca));
        for (iter = ca; iter; iter = iter->next)
@@ -1214,6 +1137,7 @@ static int merge(struct commit *h1,
                 * merge_trees has always overwritten it: the commited
                 * "conflicts" were already resolved.
                 */
+               discard_cache();
                merge(merged_common_ancestors, iter->item,
                      "Temporary merge branch 1",
                      "Temporary merge branch 2",
@@ -1226,25 +1150,21 @@ static int merge(struct commit *h1,
                        die("merge returned no commit");
        }
 
+       discard_cache();
        if (call_depth == 0) {
-               setup_index(0 /* $GIT_DIR/index */);
+               read_cache();
                index_only = 0;
-       } else {
-               setup_index(1 /* temporary index */);
-               git_read_tree(h1->tree);
+       } else
                index_only = 1;
-       }
 
        clean = merge_trees(h1->tree, h2->tree, merged_common_ancestors->tree,
                            branch1, branch2, &mrtree);
 
-       if (!ancestor && (clean || index_only)) {
+       if (index_only) {
                *result = make_virtual_commit(mrtree, "merged tree");
                commit_list_insert(h1, &(*result)->parents);
                commit_list_insert(h2, &(*result)->parents->next);
-       } else
-               *result = NULL;
-
+       }
        return clean;
 }
 
@@ -1280,19 +1200,16 @@ static struct commit *get_ref(const char *ref)
 
 int main(int argc, char *argv[])
 {
-       static const char *bases[2];
+       static const char *bases[20];
        static unsigned bases_count = 0;
        int i, clean;
        const char *branch1, *branch2;
        struct commit *result, *h1, *h2;
+       struct commit_list *ca = NULL;
+       struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
+       int index_fd;
 
        git_config(git_default_config); /* core.filemode */
-       original_index_file = getenv(INDEX_ENVIRONMENT);
-
-       if (!original_index_file)
-               original_index_file = xstrdup(git_path("index"));
-
-       temporary_index_file = xstrdup(git_path("mrg-rcrsv-tmp-idx"));
 
        if (argc < 4)
                die("Usage: %s <base>... -- <head> <remote> ...\n", argv[0]);
@@ -1316,18 +1233,18 @@ int main(int argc, char *argv[])
        branch2 = better_branch_name(branch2);
        printf("Merging %s with %s\n", branch1, branch2);
 
-       if (bases_count == 1) {
-               struct commit *ancestor = get_ref(bases[0]);
-               clean = merge(h1, h2, branch1, branch2, 0, ancestor, &result);
-       } else
-               clean = merge(h1, h2, branch1, branch2, 0, NULL, &result);
+       index_fd = hold_lock_file_for_update(lock, get_index_file(), 1);
 
-       if (cache_dirty)
-               flush_cache();
+       for (i = 0; i < bases_count; i++) {
+               struct commit *ancestor = get_ref(bases[i]);
+               ca = commit_list_insert(ancestor, &ca);
+       }
+       clean = merge(h1, h2, branch1, branch2, 0, ca, &result);
+
+       if (active_cache_changed &&
+           (write_cache(index_fd, active_cache, active_nr) ||
+            close(index_fd) || commit_lock_file(lock)))
+                       die ("unable to write %s", get_index_file());
 
        return clean ? 0: 1;
 }
-
-/*
-vim: sw=8 noet
-*/
diff --git a/path.c b/path.c
index bb5ee7bf99780b6c4069dd9833994b24f1577e82..c5d25a4b903bd92930df4004d30d4dffa6054456 100644 (file)
--- a/path.c
+++ b/path.c
@@ -90,10 +90,11 @@ int git_mkstemp(char *path, size_t len, const char *template)
 }
 
 
-int validate_symref(const char *path)
+int validate_headref(const char *path)
 {
        struct stat st;
        char *buf, buffer[256];
+       unsigned char sha1[20];
        int len, fd;
 
        if (lstat(path, &st) < 0)
@@ -119,14 +120,23 @@ int validate_symref(const char *path)
        /*
         * Is it a symbolic ref?
         */
-       if (len < 4 || memcmp("ref:", buffer, 4))
+       if (len < 4)
                return -1;
-       buf = buffer + 4;
-       len -= 4;
-       while (len && isspace(*buf))
-               buf++, len--;
-       if (len >= 5 && !memcmp("refs/", buf, 5))
+       if (!memcmp("ref:", buffer, 4)) {
+               buf = buffer + 4;
+               len -= 4;
+               while (len && isspace(*buf))
+                       buf++, len--;
+               if (len >= 5 && !memcmp("refs/", buf, 5))
+                       return 0;
+       }
+
+       /*
+        * Is this a detached HEAD?
+        */
+       if (!get_sha1_hex(buffer, sha1))
                return 0;
+
        return -1;
 }
 
@@ -241,7 +251,7 @@ char *enter_repo(char *path, int strict)
                return NULL;
 
        if (access("objects", X_OK) == 0 && access("refs", X_OK) == 0 &&
-           validate_symref("HEAD") == 0) {
+           validate_headref("HEAD") == 0) {
                putenv("GIT_DIR=.");
                check_repository_format();
                return path;
index 2b26b65bfb00c60535919d7b9359a5549f9e9709..3474ad320f6c90a67eb4a5973092f4210d173e9d 100644 (file)
@@ -63,7 +63,7 @@ =head1 DESCRIPTION
 the generic command interface.
 
 While some commands can be executed outside of any context (e.g. 'version'
-or 'init-db'), most operations require a repository context, which in practice
+or 'init'), most operations require a repository context, which in practice
 means getting an instance of the Git object using the repository() constructor.
 (In the future, we will also get a new_repository() constructor.) All commands
 called as methods of the object are then executed in the context of the
index 8ecd826e9c628346365cfd8c913c7a20af0fc76e..c54a61187711087b98138b9598db6353457e4df3 100644 (file)
@@ -1010,7 +1010,7 @@ int write_cache(int newfd, struct cache_entry **cache, int entries)
                if (data &&
                    !write_index_ext_header(&c, newfd, CACHE_EXT_TREE, sz) &&
                    !ce_write(&c, newfd, data, sz))
-                       ;
+                       free(data);
                else {
                        free(data);
                        return -1;
diff --git a/refs.c b/refs.c
index d189d8ad99de2dd7a65a2b10dc2e353055c55509..689ac50bae64a1068f2d9b1d720817748fc2289d 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -923,6 +923,9 @@ static int log_ref_write(struct ref_lock *lock,
        char *logrec;
        const char *committer;
 
+       if (log_all_ref_updates < 0)
+               log_all_ref_updates = !is_bare_repository();
+
        if (log_all_ref_updates &&
            (!strncmp(lock->ref_name, "refs/heads/", 11) ||
             !strncmp(lock->ref_name, "refs/remotes/", 13))) {
index 1e3b29a429e99fd04da54a3af661d07ddb870688..f2ddd95e29e5eaef2cb4beb28c34921396d94fdf 100644 (file)
@@ -1121,21 +1121,23 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
 void prepare_revision_walk(struct rev_info *revs)
 {
        int nr = revs->pending.nr;
-       struct object_array_entry *list = revs->pending.objects;
+       struct object_array_entry *e, *list;
 
+       e = list = revs->pending.objects;
        revs->pending.nr = 0;
        revs->pending.alloc = 0;
        revs->pending.objects = NULL;
        while (--nr >= 0) {
-               struct commit *commit = handle_commit(revs, list->item, list->name);
+               struct commit *commit = handle_commit(revs, e->item, e->name);
                if (commit) {
                        if (!(commit->object.flags & SEEN)) {
                                commit->object.flags |= SEEN;
                                insert_by_date(commit, &revs->commits);
                        }
                }
-               list++;
+               e++;
        }
+       free(list);
 
        if (revs->no_walk)
                return;
diff --git a/setup.c b/setup.c
index 2ae57f7c94e304ef3468a27cd245c314a08046ed..cc97f9f5c1b8ebfb21a4487d4c5b0ee972797779 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -138,7 +138,8 @@ const char **get_pathspec(const char *prefix, const char **pathspec)
  *    GIT_OBJECT_DIRECTORY environment variable
  *  - a refs/ directory
  *  - either a HEAD symlink or a HEAD file that is formatted as
- *    a proper "ref:".
+ *    a proper "ref:", or a regular file HEAD that has a properly
+ *    formatted sha1 object name.
  */
 static int is_git_directory(const char *suspect)
 {
@@ -161,7 +162,7 @@ static int is_git_directory(const char *suspect)
                return 0;
 
        strcpy(path + len, "/HEAD");
-       if (validate_symref(path))
+       if (validate_headref(path))
                return 0;
 
        return 1;
index 53e25f278c6193860431f63a3c9de97f4e347f27..1b1c0f7b4dc814764ead5ba1af77070ed381110c 100644 (file)
@@ -572,7 +572,8 @@ static void open_packed_git(struct packed_git *p)
                die("cannot set FD_CLOEXEC");
 
        /* Verify we recognize this pack file format. */
-       read_or_die(p->pack_fd, &hdr, sizeof(hdr));
+       if (read_in_full(p->pack_fd, &hdr, sizeof(hdr)) != sizeof(hdr))
+               die("file %s is far too short to be a packfile", p->pack_name);
        if (hdr.hdr_signature != htonl(PACK_SIGNATURE))
                die("file %s is not a GIT packfile", p->pack_name);
        if (!pack_version_ok(hdr.hdr_version))
@@ -588,7 +589,8 @@ static void open_packed_git(struct packed_git *p)
                        num_packed_objects(p));
        if (lseek(p->pack_fd, p->pack_size - sizeof(sha1), SEEK_SET) == -1)
                die("end of packfile %s is unavailable", p->pack_name);
-       read_or_die(p->pack_fd, sha1, sizeof(sha1));
+       if (read_in_full(p->pack_fd, sha1, sizeof(sha1)) != sizeof(sha1))
+               die("packfile %s signature is unavailable", p->pack_name);
        idx_sha1 = ((unsigned char *)p->index_base) + p->index_size - 40;
        if (hashcmp(sha1, idx_sha1))
                die("packfile %s does not match index", p->pack_name);
@@ -1618,12 +1620,7 @@ int move_temp_to_file(const char *tmpfile, const char *filename)
 
 static int write_buffer(int fd, const void *buf, size_t len)
 {
-       ssize_t size;
-
-       size = write_in_full(fd, buf, len);
-       if (!size)
-               return error("file write: disk full");
-       if (size < 0)
+       if (write_in_full(fd, buf, len) < 0)
                return error("file write error (%s)", strerror(errno));
        return 0;
 }
index 7abab1dafe83527a5ff84808824057f549a08080..36f251761739c6cda0053bbe26cc6331ed7be40c 100644 (file)
--- a/t/README
+++ b/t/README
@@ -18,7 +18,7 @@ The easiest way to run tests is to say "make".  This runs all
 the tests.
 
     *** t0000-basic.sh ***
-    *   ok 1: .git/objects should be empty after git-init-db in an empty repo.
+    *   ok 1: .git/objects should be empty after git-init in an empty repo.
     *   ok 2: .git/objects should have 256 subdirectories.
     *   ok 3: git-update-index without --add should fail adding.
     ...
index af42ccc8d157e54b97de435194d22e5ed895ab4b..bb1d7b84bcdd3a413e900a0002baf268fa631f3f 100644 (file)
@@ -25,14 +25,15 @@ 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'});
-"
+system(qw/svnadmin create --fs-type fsfs/, '$svnrepo') == 0 or exit(41);
+" >&3 2>&4
 x=$?
 if test $x -ne 0
 then
        if test $x -eq 42; then
                err='Perl SVN libraries must be >= 1.1.0'
+       elif test $x -eq 41; then
+               err='svnadmin failed to create fsfs repository'
        else
                err='Perl SVN libraries not found or unusable, skipping test'
        fi
index 0cd1c41866c6ca344ed99fae3d71014dd9321e2d..186de7024336ca98bd5dcea6f675e1fc221d0ce0 100755 (executable)
@@ -31,12 +31,12 @@ fi
 . ./test-lib.sh
 
 ################################################################
-# init-db has been done in an empty repository.
+# git-init has been done in an empty repository.
 # make sure it is empty.
 
 find .git/objects -type f -print >should-be-empty
 test_expect_success \
-    '.git/objects should be empty after git-init-db in an empty repo.' \
+    '.git/objects should be empty after git-init in an empty repo.' \
     'cmp -s /dev/null should-be-empty' 
 
 # also it should have 2 subdirectories; no fan-out anymore, pack, and info.
index a6ea0f6a196c5285c229021c96bb83f33a3aa748..bb80e4286a7144e88aca9839c26b9fd99ff6cd4e 100755 (executable)
@@ -48,7 +48,7 @@ test_expect_success \
         test ! -f .git/logs/refs/heads/d/e/f'
 
 cat >expect <<EOF
-0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000     checkout: Created from master^0
+0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000     checkout: Created from master
 EOF
 test_expect_success \
     'git checkout -b g/h/i -l should create a branch and a log' \
index 74f5c2a5755c8d29045498031c0bc3721a00b9c7..aa2c869e0e7ffcfba2e4349cf5af0e2badcb5516 100755 (executable)
@@ -50,12 +50,12 @@ test_expect_success 'setup separate repository lacking postimage' '
 
        git tar-tree initial initial | tar xf - &&
        (
-               cd initial && git init-db && git add .
+               cd initial && git init && git add .
        ) &&
 
        git tar-tree second second | tar xf - &&
        (
-               cd second && git init-db && git add .
+               cd second && git init && git add .
        )
 
 '
index de45ac4e0fcea5b7acab245af9876b58ec1ccea3..f51154745586b246ecb30caee3f2150441911e1d 100755 (executable)
@@ -44,7 +44,7 @@ test_expect_success \
     'unpack without delta' \
     "GIT_OBJECT_DIRECTORY=.git2/objects &&
      export GIT_OBJECT_DIRECTORY &&
-     git-init-db &&
+     git-init &&
      git-unpack-objects -n <test-1-${packname_1}.pack &&
      git-unpack-objects <test-1-${packname_1}.pack"
 
@@ -75,7 +75,7 @@ test_expect_success \
     'unpack with delta' \
     'GIT_OBJECT_DIRECTORY=.git2/objects &&
      export GIT_OBJECT_DIRECTORY &&
-     git-init-db &&
+     git-init &&
      git-unpack-objects -n <test-2-${packname_2}.pack &&
      git-unpack-objects <test-2-${packname_2}.pack'
 
@@ -100,7 +100,7 @@ test_expect_success \
     'use packed objects' \
     'GIT_OBJECT_DIRECTORY=.git2/objects &&
      export GIT_OBJECT_DIRECTORY &&
-     git-init-db &&
+     git-init &&
      cp test-1-${packname_1}.pack test-1-${packname_1}.idx .git2/objects/pack && {
         git-diff-tree --root -p $commit &&
         while read object
index 77c3c575d89ad5707ad8f6b22f62b58aef458104..ef78df67ea39e619f1118f427ad4dcc07e923bca 100755 (executable)
@@ -97,7 +97,7 @@ pull_to_client () {
 (
        mkdir client &&
        cd client &&
-       git-init-db 2>> log2.txt
+       git-init 2>> log2.txt
 )
 
 add A1
index 90eeeba2a31949a84daeb34b1996eaa4818321e6..3ce9446210bc56443e7a39273699983c1d9a65a4 100755 (executable)
@@ -73,7 +73,7 @@ test_expect_success 'fetch following tags' '
 
        mkdir four &&
        cd four &&
-       git init-db &&
+       git init &&
 
        git fetch .. :track &&
        git show-ref --verify refs/tags/anno &&
index f841574573545fa333e00b6815ba0df7d6931273..7eb37838bb788dfb68361bca95860fd532276deb 100755 (executable)
@@ -17,7 +17,7 @@ test_expect_success setup '
 test_expect_success 'pulling into void' '
        mkdir cloned &&
        cd cloned &&
-       git init-db &&
+       git init &&
        git pull ..
 '
 
index 2f4ff82e149c497d79583f6b431b29d597e4a1ae..344033249cc1ea3f7066d4d6007ade6cc1a2c5de 100755 (executable)
@@ -88,7 +88,7 @@ test_expect_success \
 
 test_expect_success "Michael Cassar's test case" '
        rm -fr .git papers partA &&
-       git init-db &&
+       git init &&
        mkdir -p papers/unsorted papers/all-papers partA &&
        echo a > papers/unsorted/Thesis.pdf &&
        echo b > partA/outline.txt &&
@@ -109,7 +109,7 @@ rm -fr papers partA path?
 
 test_expect_success "Sergey Vlasov's test case" '
        rm -fr .git &&
-       git init-db &&
+       git init &&
        mkdir ab &&
        date >ab.c &&
        date >ab/d &&
index 400c21cd49b6307eeef6d4d25cb34e612b1d0a71..8d2e2fec395a328f4bf6a65af3c7eba5a98cc133 100755 (executable)
@@ -17,6 +17,7 @@ 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 &&
index 72ea2b259875e209752022f63bd57f9ca83a0cc4..8e3ee6cd7b38e07d3fd39904066c8e64f1d3642f 100755 (executable)
@@ -220,8 +220,8 @@ test_create_repo () {
        repo="$1"
        mkdir "$repo"
        cd "$repo" || error "Cannot setup test environment"
-       "$GIT_EXEC_PATH/git" init-db --template=$GIT_EXEC_PATH/templates/blt/ >/dev/null 2>&1 ||
-       error "cannot run git init-db -- have you built things yet?"
+       "$GIT_EXEC_PATH/git" init --template=$GIT_EXEC_PATH/templates/blt/ >/dev/null 2>&1 ||
+       error "cannot run git init -- have you built things yet?"
        mv .git/hooks .git/hooks-disabled
        cd "$owd"
 }
index a119e1d208445093dd1d2869729eca9435aa020e..046e79d485feaa26d305868012f73b04088366b6 100644 (file)
@@ -4,16 +4,11 @@ int read_in_full(int fd, void *buf, size_t count)
 {
        char *p = buf;
        ssize_t total = 0;
-       ssize_t loaded = 0;
 
        while (count > 0) {
-               loaded = xread(fd, p, count);
-               if (loaded <= 0) {
-                       if (total)
-                               return total;
-                       else
-                               return loaded;
-               }
+               ssize_t loaded = xread(fd, p, count);
+               if (loaded <= 0)
+                       return total ? total : loaded;
                count -= loaded;
                p += loaded;
                total += loaded;
@@ -22,30 +17,18 @@ int read_in_full(int fd, void *buf, size_t count)
        return total;
 }
 
-void read_or_die(int fd, void *buf, size_t count)
-{
-       ssize_t loaded;
-
-       loaded = read_in_full(fd, buf, count);
-       if (loaded == 0)
-               die("unexpected end of file");
-       else if (loaded < 0)
-               die("read error (%s)", strerror(errno));
-}
-
 int write_in_full(int fd, const void *buf, size_t count)
 {
        const char *p = buf;
        ssize_t total = 0;
-       ssize_t written = 0;
 
        while (count > 0) {
-               written = xwrite(fd, p, count);
-               if (written <= 0) {
-                       if (total)
-                               return total;
-                       else
-                               return written;
+               size_t written = xwrite(fd, p, count);
+               if (written < 0)
+                       return -1;
+               if (!written) {
+                       errno = ENOSPC;
+                       return -1;
                }
                count -= written;
                p += written;
@@ -57,12 +40,7 @@ int write_in_full(int fd, const void *buf, size_t count)
 
 void write_or_die(int fd, const void *buf, size_t count)
 {
-       ssize_t written;
-
-       written = write_in_full(fd, buf, count);
-       if (written == 0)
-               die("disk full?");
-       else if (written < 0) {
+       if (write_in_full(fd, buf, count) < 0) {
                if (errno == EPIPE)
                        exit(0);
                die("write error (%s)", strerror(errno));
@@ -71,14 +49,7 @@ void write_or_die(int fd, const void *buf, size_t count)
 
 int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg)
 {
-       ssize_t written;
-
-       written = write_in_full(fd, buf, count);
-       if (written == 0) {
-               fprintf(stderr, "%s: disk full?\n", msg);
-               return 0;
-       }
-       else if (written < 0) {
+       if (write_in_full(fd, buf, count) < 0) {
                if (errno == EPIPE)
                        exit(0);
                fprintf(stderr, "%s: write error (%s)\n",
@@ -91,14 +62,7 @@ int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg)
 
 int write_or_whine(int fd, const void *buf, size_t count, const char *msg)
 {
-       ssize_t written;
-
-       written = write_in_full(fd, buf, count);
-       if (written == 0) {
-               fprintf(stderr, "%s: disk full?\n", msg);
-               return 0;
-       }
-       else if (written < 0) {
+       if (write_in_full(fd, buf, count) < 0) {
                fprintf(stderr, "%s: write error (%s)\n",
                        msg, strerror(errno));
                return 0;
index 1dc2fdc340740574913d4815b8d2963a8c5cd49a..b7250e43100244abcdaa5bc923574aad7f815d0b 100644 (file)
@@ -15,7 +15,13 @@ 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 <file>...\" to incrementally add content to commit";
+
+static const char use_add_msg[] =
+"use \"git add <file>...\" to update what will be committed";
+static const char use_add_rm_msg[] =
+"use \"git add/rm <file>...\" to update what will be committed";
+static const char use_add_to_include_msg[] =
+"use \"git add <file>...\" to include in what will be committed";
 
 static int parse_status_slot(const char *var, int offset)
 {
@@ -177,8 +183,14 @@ static void wt_status_print_changed_cb(struct diff_queue_struct *q,
        struct wt_status *s = data;
        int i;
        if (q->nr) {
+               const char *msg = use_add_msg;
                s->workdir_dirty = 1;
-               wt_status_print_header("Changed but not added", use_add_msg);
+               for (i = 0; i < q->nr; i++)
+                       if (q->queue[i]->status == DIFF_STATUS_DELETED) {
+                               msg = use_add_rm_msg;
+                               break;
+                       }
+               wt_status_print_header("Changed but not updated", msg);
        }
        for (i = 0; i < q->nr; i++)
                wt_status_print_filepair(WT_STATUS_CHANGED, q->queue[i]);
@@ -265,7 +277,8 @@ static void wt_status_print_untracked(struct wt_status *s)
                }
                if (!shown_header) {
                        s->workdir_untracked = 1;
-                       wt_status_print_header("Untracked files", use_add_msg);
+                       wt_status_print_header("Untracked files",
+                                              use_add_to_include_msg);
                        shown_header = 1;
                }
                color_printf(color(WT_STATUS_HEADER), "#\t");
@@ -289,9 +302,18 @@ 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)
+       if (s->branch) {
+               const char *on_what = "On branch ";
+               const char *branch_name = s->branch;
+               if (!strncmp(branch_name, "refs/heads/", 11))
+                       branch_name += 11;
+               else if (!strcmp(branch_name, "HEAD")) {
+                       branch_name = "";
+                       on_what = "Not currently on any branch.";
+               }
                color_printf_ln(color(WT_STATUS_HEADER),
-                       "# On branch %s", s->branch);
+                       "# %s%s", on_what, branch_name);
+       }
 
        if (s->is_initial) {
                color_printf_ln(color(WT_STATUS_HEADER), "#");
@@ -313,7 +335,7 @@ void wt_status_print(struct wt_status *s)
                if (s->amend)
                        printf("# No changes\n");
                else if (s->workdir_dirty)
-                       printf("no changes added to commit (use \"git add\" and/or \"git commit [-a|-i|-o]\")\n");
+                       printf("no changes added to commit (use \"git add\" and/or \"git commit -a\")\n");
                else if (s->workdir_untracked)
                        printf("nothing added to commit but untracked files present (use \"git add\" to track)\n");
                else if (s->is_initial)