Merge branch 'master' into lj/refs
authorJunio C Hamano <junkio@cox.net>
Thu, 28 Sep 2006 05:23:12 +0000 (22:23 -0700)
committerJunio C Hamano <junkio@cox.net>
Thu, 28 Sep 2006 05:23:12 +0000 (22:23 -0700)
* master: (72 commits)
runstatus: do not recurse into subdirectories if not needed
grep: fix --fixed-strings combined with expression.
grep: free expressions and patterns when done.
Corrected copy-and-paste thinko in ignore executable bit test case.
An illustration of rev-list --parents --pretty=raw
Allow git-checkout when on a non-existant branch.
gitweb: Decode long title for link tooltips
git-svn: Fix fetch --no-ignore-externals with GIT_SVN_NO_LIB=1
Ignore executable bit when adding files if filemode=0.
Remove empty ref directories that prevent creating a ref.
Use const for interpolate arguments
git-archive: update documentation
Deprecate merge-recursive.py
gitweb: fix over-eager application of esc_html().
Allow '(no author)' in git-svn's authors file.
Allow 'svn fetch' on '(no date)' revisions in Subversion.
git-repack: allow git-repack to run in subdirectory
Remove upload-tar and make git-tar-tree a thin wrapper to git-archive
git-tar-tree: Move code for git-archive --format=tar to archive-tar.c
git-tar-tree: Remove duplicate git_config() call
...

12 files changed:
1  2 
.gitignore
Makefile
builtin-init-db.c
builtin-update-index.c
builtin.h
cache.h
git-branch.sh
git-checkout.sh
git.c
receive-pack.c
revision.c
sha1_name.c
diff --combined .gitignore
index 0ffe14ac4eb85ff88b3b09c50584c6a6c2c4d794,25eb4637a6f971a4a290ab823a937997c700bd7f..4c8c8e411500fe2ed0108c46838d50576ed15185
@@@ -37,7 -37,6 +37,7 @@@ git-fetc
  git-fetch-pack
  git-findtags
  git-fmt-merge-msg
 +git-for-each-ref
  git-format-patch
  git-fsck-objects
  git-get-tar-commit-id
@@@ -66,6 -65,7 +66,7 @@@ git-merge-one-fil
  git-merge-ours
  git-merge-recur
  git-merge-recursive
+ git-merge-recursive-old
  git-merge-resolve
  git-merge-stupid
  git-mktag
@@@ -74,7 -74,6 +75,7 @@@ git-name-re
  git-mv
  git-pack-redundant
  git-pack-objects
 +git-pack-refs
  git-parse-remote
  git-patch-id
  git-peek-remote
@@@ -106,7 -105,6 +107,7 @@@ git-shortlo
  git-show
  git-show-branch
  git-show-index
 +git-show-ref
  git-ssh-fetch
  git-ssh-pull
  git-ssh-push
@@@ -125,13 -123,11 +126,11 @@@ git-update-re
  git-update-server-info
  git-upload-archive
  git-upload-pack
- git-upload-tar
  git-var
  git-verify-pack
  git-verify-tag
  git-whatchanged
  git-write-tree
- git-zip-tree
  git-core-*/?*
  gitweb/gitweb.cgi
  test-date
diff --combined Makefile
index af4d68fd7e7faa1d590cf0eef3f2d1a8e435a136,c888c810bf8220c25b9949f47730742347738c32..65fb8284f3c9ef210c08711b5ce4796593e72e75
+++ b/Makefile
@@@ -81,8 -81,6 +81,6 @@@ all
  # Define NO_ACCURATE_DIFF if your diff program at least sometimes misses
  # a missing newline at the end of the file.
  #
- # Define NO_PYTHON if you want to lose all benefits of the recursive merge.
- #
  # Define COLLISION_CHECK below if you believe that SHA1's
  # 1461501637330902918203684832716283019655932542976 hashes do not give you
  # sufficient guarantee that no collisions between objects will ever happen.
@@@ -174,7 -172,7 +172,7 @@@ SCRIPT_PERL = 
        git-send-email.perl git-svn.perl
  
  SCRIPT_PYTHON = \
-       git-merge-recursive.py
+       git-merge-recursive-old.py
  
  SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
          $(patsubst %.perl,%,$(SCRIPT_PERL)) \
@@@ -199,7 -197,7 +197,7 @@@ PROGRAMS = 
        git-upload-pack$X git-verify-pack$X \
        git-pack-redundant$X git-var$X \
        git-describe$X git-merge-tree$X git-blame$X git-imap-send$X \
-       git-merge-recur$X \
+       git-merge-recursive$X \
        $(EXTRA_PROGRAMS)
  
  # Empty...
@@@ -234,7 -232,7 +232,7 @@@ LIB_FILE=libgit.
  XDIFF_LIB=xdiff/lib.a
  
  LIB_H = \
-       archive.h blob.h cache.h commit.h csum-file.h delta.h \
+       archive.h blob.h cache.h commit.h csum-file.h delta.h grep.h \
        diff.h object.h pack.h pkt-line.h quote.h refs.h list-objects.h sideband.h \
        run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \
        tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h
@@@ -246,15 -244,17 +244,17 @@@ DIFF_OBJS = 
  
  LIB_OBJS = \
        blob.o commit.o connect.o csum-file.o cache-tree.o base85.o \
-       date.o diff-delta.o entry.o exec_cmd.o ident.o lockfile.o \
+       date.o diff-delta.o entry.o exec_cmd.o ident.o \
+       interpolate.o \
+       lockfile.o \
        object.o pack-check.o patch-delta.o path.o pkt-line.o sideband.o \
        quote.o read-cache.o refs.o run-command.o dir.o object-refs.o \
        server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
        tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
        fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \
-       write_or_die.o trace.o list-objects.o \
+       write_or_die.o trace.o list-objects.o grep.o \
        alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
-       color.o wt-status.o
+       color.o wt-status.o archive-zip.o archive-tar.o
  
  BUILTIN_OBJS = \
        builtin-add.o \
        builtin-diff-stages.o \
        builtin-diff-tree.o \
        builtin-fmt-merge-msg.o \
 +      builtin-for-each-ref.o \
        builtin-grep.o \
        builtin-init-db.o \
        builtin-log.o \
        builtin-update-index.o \
        builtin-update-ref.o \
        builtin-upload-archive.o \
-       builtin-upload-tar.o \
        builtin-verify-pack.o \
 -      builtin-write-tree.o
 +      builtin-write-tree.o \
-       builtin-zip-tree.o \
 +      builtin-show-ref.o \
 +      builtin-pack-refs.o
  
  GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
  LIBS = $(GITLIBS) -lz
@@@ -573,7 -568,8 +571,8 @@@ LIB_OBJS += $(COMPAT_OBJS
  export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir
  ### Build rules
  
- all: $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk gitweb/gitweb.cgi
+ all: $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk gitweb/gitweb.cgi \
+       git-merge-recur$X
  
  all:
        $(MAKE) -C templates
@@@ -588,6 -584,9 +587,9 @@@ git$X: git.c common-cmds.h $(BUILTIN_OB
  
  help.o: common-cmds.h
  
+ git-merge-recur$X: git-merge-recursive$X
+       rm -f $@ && ln git-merge-recursive$X $@
  $(BUILT_INS): git$X
        rm -f $@ && ln git$X $@
  
@@@ -725,11 -724,6 +727,6 @@@ git-http-push$X: revision.o http.o http
        $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
                $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
  
- merge-recursive.o path-list.o: path-list.h
- git-merge-recur$X: merge-recursive.o path-list.o $(GITLIBS)
-       $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
-               $(LIBS)
  $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
  $(patsubst git-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
  $(DIFF_OBJS): diffcore.h
@@@ -890,6 -884,7 +887,7 @@@ check-docs:
                case "$$v" in \
                git-merge-octopus | git-merge-ours | git-merge-recursive | \
                git-merge-resolve | git-merge-stupid | git-merge-recur | \
+               git-merge-recursive-old | \
                git-ssh-pull | git-ssh-push ) continue ;; \
                esac ; \
                test -f "Documentation/$$v.txt" || \
diff --combined builtin-init-db.c
index 23b7714f894019c7d59fc9ede00d83c008d6bc89,c3ed1ce4929472b4e3fb7577ac61bd914baf0954..235a0ee48f2c5ce09c63a949358eb16cde05332d
@@@ -218,8 -218,8 +218,8 @@@ static void create_default_files(const 
         * branch, if it does not exist yet.
         */
        strcpy(path + len, "HEAD");
 -      if (read_ref(path, sha1) < 0) {
 -              if (create_symref(path, "refs/heads/master") < 0)
 +      if (read_ref("HEAD", sha1) < 0) {
 +              if (create_symref("HEAD", "refs/heads/master") < 0)
                        exit(1);
        }
  
@@@ -311,6 -311,7 +311,7 @@@ int cmd_init_db(int argc, const char **
                 */
                sprintf(buf, "%d", shared_repository);
                git_config_set("core.sharedrepository", buf);
+               git_config_set("receive.denyNonFastforwards", "true");
        }
  
        return 0;
diff --combined builtin-update-index.c
index 09214c8a11e6afb927ab6da1aa3f0be5e50888c8,a3c0a455ae5d1b8d7b7b6a8798ed7f038ab7bd72..7f9c638466f79fee7d2914b8ec76d713c3670e7e
@@@ -112,11 -112,13 +112,13 @@@ static int add_file_to_cache(const cha
        ce->ce_mode = create_ce_mode(st.st_mode);
        if (!trust_executable_bit) {
                /* If there is an existing entry, pick the mode bits
-                * from it.
+                * from it, otherwise force to 644.
                 */
                int pos = cache_name_pos(path, namelen);
                if (0 <= pos)
                        ce->ce_mode = active_cache[pos]->ce_mode;
+               else
+                       ce->ce_mode = create_ce_mode(S_IFREG | 0644);
        }
  
        if (index_path(ce->sha1, path, &st, !info_only))
@@@ -404,9 -406,9 +406,9 @@@ static int unresolve_one(const char *pa
  
  static void read_head_pointers(void)
  {
 -      if (read_ref(git_path("HEAD"), head_sha1))
 +      if (read_ref("HEAD", head_sha1))
                die("No HEAD -- no initial commit yet?\n");
 -      if (read_ref(git_path("MERGE_HEAD"), merge_head_sha1)) {
 +      if (read_ref("MERGE_HEAD", merge_head_sha1)) {
                fprintf(stderr, "Not in the middle of a merge.\n");
                exit(0);
        }
@@@ -443,7 -445,7 +445,7 @@@ static int do_reupdate(int ac, const ch
        int has_head = 1;
        const char **pathspec = get_pathspec(prefix, av + 1);
  
 -      if (read_ref(git_path("HEAD"), head_sha1))
 +      if (read_ref("HEAD", head_sha1))
                /* If there is no HEAD, that means it is an initial
                 * commit.  Update everything in the index.
                 */
diff --combined builtin.h
index 6bf0ace37579da68d8a01e928008f5d58b2e958f,f9fa9ff1d245e81630438d2b321cfe04c7905905..721b8d8037655a0a5a5edad07838867a64bf6eda
+++ b/builtin.h
@@@ -26,7 -26,6 +26,7 @@@ extern int cmd_diff(int argc, const cha
  extern int cmd_diff_stages(int argc, const char **argv, const char *prefix);
  extern int cmd_diff_tree(int argc, const char **argv, const char *prefix);
  extern int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix);
 +extern int cmd_for_each_ref(int argc, const char **argv, const char *prefix);
  extern int cmd_format_patch(int argc, const char **argv, const char *prefix);
  extern int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix);
  extern int cmd_grep(int argc, const char **argv, const char *prefix);
@@@ -49,12 -48,11 +49,11 @@@ extern int cmd_rev_list(int argc, cons
  extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);
  extern int cmd_rm(int argc, const char **argv, const char *prefix);
  extern int cmd_runstatus(int argc, const char **argv, const char *prefix);
 -extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
  extern int cmd_show(int argc, const char **argv, const char *prefix);
 +extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
  extern int cmd_stripspace(int argc, const char **argv, const char *prefix);
  extern int cmd_symbolic_ref(int argc, const char **argv, const char *prefix);
  extern int cmd_tar_tree(int argc, const char **argv, const char *prefix);
- extern int cmd_zip_tree(int argc, const char **argv, const char *prefix);
  extern int cmd_unpack_objects(int argc, const char **argv, const char *prefix);
  extern int cmd_update_index(int argc, const char **argv, const char *prefix);
  extern int cmd_update_ref(int argc, const char **argv, const char *prefix);
@@@ -64,7 -62,5 +63,7 @@@ extern int cmd_version(int argc, const 
  extern int cmd_whatchanged(int argc, const char **argv, const char *prefix);
  extern int cmd_write_tree(int argc, const char **argv, const char *prefix);
  extern int cmd_verify_pack(int argc, const char **argv, const char *prefix);
 +extern int cmd_show_ref(int argc, const char **argv, const char *prefix);
 +extern int cmd_pack_refs(int argc, const char **argv, const char *prefix);
  
  #endif
diff --combined cache.h
index 6e004505be5091146302c75b12a4538c915092da,97debd03c51c03c6df9a96e3f7de99bf4b4313e1..0565333f05e3fc95fb83d472a0590a5efb615af2
+++ b/cache.h
@@@ -179,7 -179,6 +179,7 @@@ struct lock_file 
  extern int hold_lock_file_for_update(struct lock_file *, const char *path, int);
  extern int commit_lock_file(struct lock_file *);
  extern void rollback_lock_file(struct lock_file *);
 +extern int delete_ref(const char *, unsigned char *sha1);
  
  /* Environment bits from configuration mechanism */
  extern int use_legacy_headers;
@@@ -189,6 -188,7 +189,7 @@@ extern int prefer_symlink_refs
  extern int log_all_ref_updates;
  extern int warn_ambiguous_refs;
  extern int shared_repository;
+ extern int deny_non_fast_forwards;
  extern const char *apply_default_whitespace;
  extern int zlib_compression_level;
  
@@@ -279,6 -279,12 +280,12 @@@ enum object_type 
        OBJ_BAD,
  };
  
+ extern signed char hexval_table[256];
+ static inline unsigned int hexval(unsigned int c)
+ {
+       return hexval_table[c];
+ }
  /* Convert to/from hex/sha1 representation */
  #define MINIMUM_ABBREV 4
  #define DEFAULT_ABBREV 7
@@@ -287,9 -293,9 +294,9 @@@ extern int get_sha1(const char *str, un
  extern int get_sha1_hex(const char *hex, unsigned char *sha1);
  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);
 -extern int create_symref(const char *git_HEAD, const char *refs_heads_master);
 -extern int validate_symref(const char *git_HEAD);
 +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 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);
@@@ -384,10 -390,10 +391,10 @@@ extern void unuse_packed_git(struct pac
  extern struct packed_git *add_packed_git(char *, int, int);
  extern int num_packed_objects(const struct packed_git *p);
  extern int nth_packed_object_sha1(const struct packed_git *, int, unsigned char*);
- extern int find_pack_entry_one(const unsigned char *, struct pack_entry *, struct packed_git *);
- extern void *unpack_entry_gently(struct pack_entry *, char *, unsigned long *);
+ extern unsigned long find_pack_entry_one(const unsigned char *, struct packed_git *);
+ extern void *unpack_entry_gently(struct packed_git *, unsigned long, char *, unsigned long *);
  extern unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep);
- extern void packed_object_info_detail(struct pack_entry *, char *, unsigned long *, unsigned long *, unsigned int *, unsigned char *);
+ extern void packed_object_info_detail(struct packed_git *, unsigned long, char *, unsigned long *, unsigned long *, unsigned int *, unsigned char *);
  
  /* Dumb servers support */
  extern int update_server_info(int);
diff --combined git-branch.sh
index 4379a07210cf30c5d6e5abdb36722985983edb46,4f31903d63662db7d49d3d257e328004ca2958f7..bf84b30695fdeda5d5e18456813e0b3cc3d11275
@@@ -21,7 -21,7 +21,7 @@@ delete_branch () 
        ,,)
            die "What branch are you on anyway?" ;;
        esac
 -      branch=$(cat "$GIT_DIR/refs/heads/$branch_name") &&
 +      branch=$(git-show-ref --verify --hash -- "refs/heads/$branch_name") &&
            branch=$(git-rev-parse --verify "$branch^0") ||
                die "Seriously, what branch are you talking about?"
        case "$option" in
@@@ -42,7 -42,8 +42,7 @@@ If you are sure you want to delete it, 
            esac
            ;;
        esac
 -      rm -f "$GIT_DIR/logs/refs/heads/$branch_name"
 -      rm -f "$GIT_DIR/refs/heads/$branch_name"
 +      git update-ref -d "refs/heads/$branch_name" "$branch"
        echo "Deleted branch $branch_name."
      done
      exit 0
@@@ -111,8 -112,17 +111,18 @@@ rev=$(git-rev-parse --verify "$head") |
  git-check-ref-format "heads/$branchname" ||
        die "we do not like '$branchname' as a branch name."
  
 -if [ -e "$GIT_DIR/refs/heads/$branchname" ]
+ if [ -d "$GIT_DIR/refs/heads/$branchname" ]
+ then
+       for refdir in `cd "$GIT_DIR" && \
+               find "refs/heads/$branchname" -type d | sort -r`
+       do
+               rmdir "$GIT_DIR/$refdir" || \
+                   die "Could not delete '$refdir', there may still be a ref there."
+       done
+ fi
 +prev=''
 +if git-show-ref --verify --quiet -- "refs/heads/$branchname"
  then
        if test '' = "$force"
        then
        then
                die "cannot force-update the current branch."
        fi
 +      prev=`git rev-parse --verify "refs/heads/$branchname"`
  fi
  if test "$create_log" = 'yes'
  then
        mkdir -p $(dirname "$GIT_DIR/logs/refs/heads/$branchname")
        touch "$GIT_DIR/logs/refs/heads/$branchname"
  fi
 -git update-ref -m "branch: Created from $head" "refs/heads/$branchname" $rev
 +git update-ref -m "branch: Created from $head" "refs/heads/$branchname" "$rev" "$prev"
diff --combined git-checkout.sh
index f03620b054ea81554e293dabf0884cac12bb73e4,dd477245fb3703402b950cbc1378b35ce379d631..119bca1ffbfb8fb0dae404a8e7389f577aebc42c
@@@ -4,8 -4,8 +4,8 @@@ USAGE='[-f] [-b <new_branch>] [-m] [<br
  SUBDIRECTORY_OK=Sometimes
  . git-sh-setup
  
- old=$(git-rev-parse HEAD)
  old_name=HEAD
+ old=$(git-rev-parse --verify $old_name 2>/dev/null)
  new=
  new_name=
  force=
@@@ -22,7 -22,7 +22,7 @@@ while [ "$#" != "0" ]; d
                shift
                [ -z "$newbranch" ] &&
                        die "git checkout: -b needs a branch name"
 -              [ -e "$GIT_DIR/refs/heads/$newbranch" ] &&
 +              git-show-ref --verify --quiet -- "refs/heads/$newbranch" &&
                        die "git checkout: branch $newbranch already exists"
                git-check-ref-format "heads/$newbranch" ||
                        die "git checkout: we do not like '$newbranch' as a branch name."
@@@ -51,8 -51,7 +51,8 @@@
                        fi
                        new="$rev"
                        new_name="$arg^0"
 -                      if [ -f "$GIT_DIR/refs/heads/$arg" ]; then
 +                      if git-show-ref --verify --quiet -- "refs/heads/$arg"
 +                      then
                                branch="$arg"
                        fi
                elif rev=$(git-rev-parse --verify "$arg^{tree}" 2>/dev/null)
        die "git checkout: to checkout the requested commit you need to specify 
                a name for a new branch which is created and switched to"
  
+ 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
+       force=1
+ fi
  if [ "$force" ]
  then
      git-read-tree --reset -u $new
diff --combined git.c
index f7e784164997a3d0e6885cc57eceeacf41d433ab,ae80e78456007e8ccb025949af82279f84cdb8fa..9108fec808e6fa6fc78a0409f7a45aa12cd4a325
--- 1/git.c
--- 2/git.c
+++ b/git.c
@@@ -232,7 -232,6 +232,7 @@@ static void handle_internal_command(in
                { "diff-stages", cmd_diff_stages, RUN_SETUP },
                { "diff-tree", cmd_diff_tree, RUN_SETUP },
                { "fmt-merge-msg", cmd_fmt_merge_msg, RUN_SETUP },
 +              { "for-each-ref", cmd_for_each_ref, RUN_SETUP },
                { "format-patch", cmd_format_patch, RUN_SETUP },
                { "get-tar-commit-id", cmd_get_tar_commit_id },
                { "grep", cmd_grep, RUN_SETUP },
                { "stripspace", cmd_stripspace },
                { "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
                { "tar-tree", cmd_tar_tree, RUN_SETUP },
-               { "zip-tree", cmd_zip_tree, RUN_SETUP },
                { "unpack-objects", cmd_unpack_objects, RUN_SETUP },
                { "update-index", cmd_update_index, RUN_SETUP },
                { "update-ref", cmd_update_ref, RUN_SETUP },
                { "upload-archive", cmd_upload_archive },
-               { "upload-tar", cmd_upload_tar },
                { "version", cmd_version },
                { "whatchanged", cmd_whatchanged, RUN_SETUP | USE_PAGER },
                { "write-tree", cmd_write_tree, RUN_SETUP },
                { "verify-pack", cmd_verify_pack },
 +              { "show-ref", cmd_show_ref, RUN_SETUP },
 +              { "pack-refs", cmd_pack_refs, RUN_SETUP },
        };
        int i;
  
diff --combined receive-pack.c
index c8aacbbdd3089fdc412da368ca7609da590e0ca3,ea2dbd4e3398ca90823dcd453cbb52c5dcea135c..1fcf3a91127250448a659fe0d48393c34ecd7c47
@@@ -2,6 -2,8 +2,8 @@@
  #include "refs.h"
  #include "pkt-line.h"
  #include "run-command.h"
+ #include "commit.h"
+ #include "object.h"
  
  static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
  
@@@ -12,7 -14,7 +14,7 @@@ static int report_status
  static char capabilities[] = "report-status";
  static int capabilities_sent;
  
 -static int show_ref(const char *path, const unsigned char *sha1)
 +static int show_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
  {
        if (capabilities_sent)
                packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
@@@ -25,9 -27,9 +27,9 @@@
  
  static void write_head_info(void)
  {
 -      for_each_ref(show_ref);
 +      for_each_ref(show_ref, NULL);
        if (!capabilities_sent)
 -              show_ref("capabilities^{}", null_sha1);
 +              show_ref("capabilities^{}", null_sha1, 0, NULL);
  
  }
  
@@@ -41,6 -43,34 +43,6 @@@ struct command 
  
  static struct command *commands;
  
 -static int is_all_zeroes(const char *hex)
 -{
 -      int i;
 -      for (i = 0; i < 40; i++)
 -              if (*hex++ != '0')
 -                      return 0;
 -      return 1;
 -}
 -
 -static int verify_old_ref(const char *name, char *hex_contents)
 -{
 -      int fd, ret;
 -      char buffer[60];
 -
 -      if (is_all_zeroes(hex_contents))
 -              return 0;
 -      fd = open(name, O_RDONLY);
 -      if (fd < 0)
 -              return -1;
 -      ret = read(fd, buffer, 40);
 -      close(fd);
 -      if (ret != 40)
 -              return -1;
 -      if (memcmp(buffer, hex_contents, 40))
 -              return -1;
 -      return 0;
 -}
 -
  static char update_hook[] = "hooks/update";
  
  static int run_update_hook(const char *refname,
@@@ -77,8 -107,8 +79,8 @@@ static int update(struct command *cmd
        const char *name = cmd->ref_name;
        unsigned char *old_sha1 = cmd->old_sha1;
        unsigned char *new_sha1 = cmd->new_sha1;
 -      char new_hex[60], *old_hex, *lock_name;
 -      int newfd, namelen, written;
 +      char new_hex[41], old_hex[41];
 +      struct ref_lock *lock;
  
        cmd->error_string = NULL;
        if (!strncmp(name, "refs/", 5) && check_ref_format(name + 5)) {
                             name);
        }
  
 -      namelen = strlen(name);
 -      lock_name = xmalloc(namelen + 10);
 -      memcpy(lock_name, name, namelen);
 -      memcpy(lock_name + namelen, ".lock", 6);
 -
        strcpy(new_hex, sha1_to_hex(new_sha1));
 -      old_hex = sha1_to_hex(old_sha1);
 +      strcpy(old_hex, sha1_to_hex(old_sha1));
        if (!has_sha1_file(new_sha1)) {
                cmd->error_string = "bad pack";
                return error("unpack should have generated %s, "
                             "but I can't find it!", new_hex);
        }
 -      safe_create_leading_directories(lock_name);
 -
 -      newfd = open(lock_name, O_CREAT | O_EXCL | O_WRONLY, 0666);
 -      if (newfd < 0) {
 -              cmd->error_string = "can't lock";
 -              return error("unable to create %s (%s)",
 -                           lock_name, strerror(errno));
 -      }
 -
 -      /* Write the ref with an ending '\n' */
 -      new_hex[40] = '\n';
 -      new_hex[41] = 0;
 -      written = write(newfd, new_hex, 41);
 -      /* Remove the '\n' again */
 -      new_hex[40] = 0;
 -
 -      close(newfd);
 -      if (written != 41) {
 -              unlink(lock_name);
 -              cmd->error_string = "can't write";
 -              return error("unable to write %s", lock_name);
 -      }
 -      if (verify_old_ref(name, old_hex) < 0) {
 -              unlink(lock_name);
 -              cmd->error_string = "raced";
 -              return error("%s changed during push", name);
 -      }
+       if (deny_non_fast_forwards && !is_null_sha1(old_sha1)) {
+               struct commit *old_commit, *new_commit;
+               struct commit_list *bases, *ent;
+               old_commit = (struct commit *)parse_object(old_sha1);
+               new_commit = (struct commit *)parse_object(new_sha1);
+               bases = get_merge_bases(old_commit, new_commit, 1);
+               for (ent = bases; ent; ent = ent->next)
+                       if (!hashcmp(old_sha1, ent->item->object.sha1))
+                               break;
+               free_commit_list(bases);
+               if (!ent)
+                       return error("denying non-fast forward;"
+                                    " you should pull first");
+       }
        if (run_update_hook(name, old_hex, new_hex)) {
 -              unlink(lock_name);
                cmd->error_string = "hook declined";
                return error("hook declined to update %s", name);
        }
 -      else if (rename(lock_name, name) < 0) {
 -              unlink(lock_name);
 -              cmd->error_string = "can't rename";
 -              return error("unable to replace %s", name);
 -      }
 -      else {
 -              fprintf(stderr, "%s: %s -> %s\n", name, old_hex, new_hex);
 -              return 0;
 +
 +      lock = lock_any_ref_for_update(name, old_sha1);
 +      if (!lock) {
 +              cmd->error_string = "failed to lock";
 +              return error("failed to lock %s", name);
        }
 +      write_ref_sha1(lock, new_sha1, "push");
 +
 +      fprintf(stderr, "%s: %s -> %s\n", name, old_hex, new_hex);
 +      return 0;
  }
  
  static char update_post_hook[] = "hooks/post-update";
@@@ -258,12 -335,9 +275,12 @@@ int main(int argc, char **argv
        if (!dir)
                usage(receive_pack_usage);
  
 -      if(!enter_repo(dir, 0))
 +      if (!enter_repo(dir, 0))
                die("'%s': unable to chdir or not a git archive", dir);
  
 +      setup_ident();
 +      git_config(git_default_config);
 +
        write_head_info();
  
        /* EOF */
diff --combined revision.c
index cb13b90776793dba8d18af4aecefb9e0dde5628b,93f25130a05ccca3e3e6c65b750f256246ae16be..d87cb6cd6474375c85855670fef713288af2fb34
@@@ -6,6 -6,8 +6,8 @@@
  #include "diff.h"
  #include "refs.h"
  #include "revision.h"
+ #include <regex.h>
+ #include "grep.h"
  
  static char *path_name(struct name_path *path, const char *name)
  {
@@@ -466,7 -468,7 +468,7 @@@ static void limit_list(struct rev_info 
  static int all_flags;
  static struct rev_info *all_revs;
  
 -static int handle_one_ref(const char *path, const unsigned char *sha1)
 +static int handle_one_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
  {
        struct object *object = get_reference(all_revs, path, sha1, all_flags);
        add_pending_object(all_revs, object, "");
@@@ -477,7 -479,7 +479,7 @@@ static void handle_all(struct rev_info 
  {
        all_revs = revs;
        all_flags = flags;
 -      for_each_ref(handle_one_ref);
 +      for_each_ref(handle_one_ref, NULL);
  }
  
  static int add_parents_only(struct rev_info *revs, const char *arg, int flags)
@@@ -672,6 -674,42 +674,42 @@@ int handle_revision_arg(const char *arg
        return 0;
  }
  
+ static void add_grep(struct rev_info *revs, const char *ptn, enum grep_pat_token what)
+ {
+       if (!revs->grep_filter) {
+               struct grep_opt *opt = xcalloc(1, sizeof(*opt));
+               opt->status_only = 1;
+               opt->pattern_tail = &(opt->pattern_list);
+               opt->regflags = REG_NEWLINE;
+               revs->grep_filter = opt;
+       }
+       append_grep_pattern(revs->grep_filter, ptn,
+                           "command line", 0, what);
+ }
+ static void add_header_grep(struct rev_info *revs, const char *field, const char *pattern)
+ {
+       char *pat;
+       const char *prefix;
+       int patlen, fldlen;
+       fldlen = strlen(field);
+       patlen = strlen(pattern);
+       pat = xmalloc(patlen + fldlen + 10);
+       prefix = ".*";
+       if (*pattern == '^') {
+               prefix = "";
+               pattern++;
+       }
+       sprintf(pat, "^%s %s%s", field, prefix, pattern);
+       add_grep(revs, pat, GREP_PATTERN_HEAD);
+ }
+ static void add_message_grep(struct rev_info *revs, const char *pattern)
+ {
+       add_grep(revs, pattern, GREP_PATTERN_BODY);
+ }
  static void add_ignore_packed(struct rev_info *revs, const char *name)
  {
        int num = ++revs->num_ignore_packed;
@@@ -913,6 -951,23 +951,23 @@@ int setup_revisions(int argc, const cha
                                revs->relative_date = 1;
                                continue;
                        }
+                       /*
+                        * Grepping the commit log
+                        */
+                       if (!strncmp(arg, "--author=", 9)) {
+                               add_header_grep(revs, "author", arg+9);
+                               continue;
+                       }
+                       if (!strncmp(arg, "--committer=", 12)) {
+                               add_header_grep(revs, "committer", arg+12);
+                               continue;
+                       }
+                       if (!strncmp(arg, "--grep=", 7)) {
+                               add_message_grep(revs, arg+7);
+                               continue;
+                       }
                        opts = diff_opt_parse(&revs->diffopt, argv+i, argc-i);
                        if (opts > 0) {
                                revs->diff = 1;
        if (diff_setup_done(&revs->diffopt) < 0)
                die("diff_setup_done failed");
  
+       if (revs->grep_filter)
+               compile_grep_patterns(revs->grep_filter);
        return left;
  }
  
@@@ -1045,6 -1103,15 +1103,15 @@@ static void mark_boundary_to_show(struc
        }
  }
  
+ static int commit_match(struct commit *commit, struct rev_info *opt)
+ {
+       if (!opt->grep_filter)
+               return 1;
+       return grep_buffer(opt->grep_filter,
+                          NULL, /* we say nothing, not even filename */
+                          commit->buffer, strlen(commit->buffer));
+ }
  struct commit *get_revision(struct rev_info *revs)
  {
        struct commit_list *list = revs->commits;
                if (revs->no_merges &&
                    commit->parents && commit->parents->next)
                        continue;
+               if (!commit_match(commit, revs))
+                       continue;
                if (revs->prune_fn && revs->dense) {
                        /* Commit without changes? */
                        if (!(commit->object.flags & TREECHANGE)) {
diff --combined sha1_name.c
index 84d24c6abf39f395281c7d80476575cbd482e6f0,9b226e3579b68fe8b59c7105bd926e3a0a70b0ad..ed711f2079752fd7ecc24b1a48b7d6fcc256659f
@@@ -247,8 -247,8 +247,8 @@@ static int get_sha1_basic(const char *s
                NULL
        };
        static const char *warning = "warning: refname '%.*s' is ambiguous.\n";
 -      const char **p, *pathname;
 -      char *real_path = NULL;
 +      const char **p, *ref;
 +      char *real_ref = NULL;
        int refs_found = 0, am;
        unsigned long at_time = (unsigned long)-1;
        unsigned char *this_result;
  
        for (p = fmt; *p; p++) {
                this_result = refs_found ? sha1_from_ref : sha1;
 -              pathname = resolve_ref(git_path(*p, len, str), this_result, 1);
 -              if (pathname) {
 +              ref = resolve_ref(mkpath(*p, len, str), this_result, 1, NULL);
 +              if (ref) {
                        if (!refs_found++)
 -                              real_path = xstrdup(pathname);
 +                              real_ref = xstrdup(ref);
                        if (!warn_ambiguous_refs)
                                break;
                }
  
        if (at_time != (unsigned long)-1) {
                read_ref_at(
 -                      real_path + strlen(git_path(".")) - 1,
 +                      real_ref,
                        at_time,
                        sha1);
        }
  
 -      free(real_path);
 +      free(real_ref);
        return 0;
  }
  
@@@ -431,6 -431,26 +431,26 @@@ static int peel_onion(const char *name
        return 0;
  }
  
+ static int get_describe_name(const char *name, int len, unsigned char *sha1)
+ {
+       const char *cp;
+       for (cp = name + len - 1; name + 2 <= cp; cp--) {
+               char ch = *cp;
+               if (hexval(ch) & ~0377) {
+                       /* We must be looking at g in "SOMETHING-g"
+                        * for it to be describe output.
+                        */
+                       if (ch == 'g' && cp[-1] == '-') {
+                               cp++;
+                               len -= cp - name;
+                               return get_short_sha1(cp, len, sha1, 1);
+                       }
+               }
+       }
+       return -1;
+ }
  static int get_sha1_1(const char *name, int len, unsigned char *sha1)
  {
        int ret, has_suffix;
        ret = get_sha1_basic(name, len, sha1);
        if (!ret)
                return 0;
+       /* It could be describe output that is "SOMETHING-gXXXX" */
+       ret = get_describe_name(name, len, sha1);
+       if (!ret)
+               return 0;
        return get_short_sha1(name, len, sha1, 0);
  }