Merge branch 'lj/refs'
authorJunio C Hamano <junkio@cox.net>
Wed, 1 Nov 2006 16:48:50 +0000 (08:48 -0800)
committerJunio C Hamano <junkio@cox.net>
Wed, 1 Nov 2006 16:48:50 +0000 (08:48 -0800)
* lj/refs: (63 commits)
Fix show-ref usagestring
t3200: git-branch testsuite update
sha1_name.c: avoid compilation warnings.
Make git-branch a builtin
ref-log: fix D/F conflict coming from deleted refs.
git-revert with conflicts to behave as git-merge with conflicts
core.logallrefupdates thinko-fix
git-pack-refs --all
core.logallrefupdates create new log file only for branch heads.
Remove bashism from t3210-pack-refs.sh
ref-log: allow ref@{count} syntax.
pack-refs: call fflush before fsync.
pack-refs: use lockfile as everybody else does.
git-fetch: do not look into $GIT_DIR/refs to see if a tag exists.
lock_ref_sha1_basic does not remove empty directories on BSD
Do not create tag leading directories since git update-ref does it.
Check that a tag exists using show-ref instead of looking for the ref file.
Use git-update-ref to delete a tag instead of rm()ing the ref file.
Fix refs.c;:repack_without_ref() clean-up path
Clean up "git-branch.sh" and add remove recursive dir test cases.
...

15 files changed:
1  2 
Documentation/config.txt
Makefile
builtin-prune.c
builtin.h
cache.h
fetch-pack.c
git-commit.sh
git-fetch.sh
git-revert.sh
git.c
receive-pack.c
revision.c
sha1_name.c
upload-pack.c
wt-status.c
diff --combined Documentation/config.txt
index 026d4cf9ade90cd108d351e372ed862378cde100,232e2a9732236a61112f88ee28c195d7bb5b6730..d9e73da2a7949a876360674f4ddd41cba8dec0ae
@@@ -71,12 -71,16 +71,16 @@@ core.preferSymlinkRefs:
        expect HEAD to be a symbolic link.
  
  core.logAllRefUpdates::
-       If true, `git-update-ref` will append a line to
-       "$GIT_DIR/logs/<ref>" listing the new SHA1 and the date/time
-       of the update.  If the file does not exist it will be
-       created automatically.  This information can be used to
-       determine what commit was the tip of a branch "2 days ago".
-       This value is false by default (no logging).
+       Updates to a ref <ref> is logged to the file
+       "$GIT_DIR/logs/<ref>", by appending the new and old
+       SHA1, the date/time and the reason of the update, but
+       only when the file exists.  If this configuration
+       variable is set to true, missing "$GIT_DIR/logs/<ref>"
+       file is automatically created for branch heads.
+       This information can be used to determine what commit
+       was the tip of a branch "2 days ago".  This value is
+       false by default (no automated creation of log files).
  
  core.repositoryFormatVersion::
        Internal variable identifying the repository format and layout
@@@ -230,22 -234,6 +234,22 @@@ pull.octopus:
  pull.twohead::
        The default merge strategy to use when pulling a single branch.
  
 +remote.<name>.url::
 +      The URL of a remote repository.  See gitlink:git-fetch[1] or
 +      gitlink:git-push[1].
 +
 +remote.<name>.fetch::
 +      The default set of "refspec" for gitlink:git-fetch[1]. See
 +      gitlink:git-fetch[1].
 +
 +remote.<name>.push::
 +      The default set of "refspec" for gitlink:git-push[1]. See
 +      gitlink:git-push[1].
 +
 +repack.usedeltabaseoffset::
 +      Allow gitlink:git-repack[1] to create packs that uses
 +      delta-base offset.  Defaults to false.
 +
  show.difftree::
        The default gitlink:git-diff-tree[1] arguments to be used
        for gitlink:git-show[1].
diff --combined Makefile
index 2d62efb5c4eb0a84c440e2e75b521b536b790bf9,be8bf392a2f57b03882f3550da8ddb9b88af9353..40e2a680f050f6f7623f2e49066a8897f4b64cbd
+++ b/Makefile
@@@ -132,8 -132,6 +132,8 @@@ GITWEB_HOMETEXT = indextext.htm
  GITWEB_CSS = gitweb.css
  GITWEB_LOGO = git-logo.png
  GITWEB_FAVICON = git-favicon.png
 +GITWEB_SITE_HEADER =
 +GITWEB_SITE_FOOTER =
  
  export prefix bindir gitexecdir template_dir GIT_PYTHON_DIR
  
@@@ -158,7 -156,7 +158,7 @@@ BASIC_CFLAGS 
  BASIC_LDFLAGS =
  
  SCRIPT_SH = \
-       git-bisect.sh git-branch.sh git-checkout.sh \
+       git-bisect.sh git-checkout.sh \
        git-cherry.sh git-clean.sh git-clone.sh git-commit.sh \
        git-fetch.sh \
        git-ls-remote.sh \
  SCRIPT_PERL = \
        git-archimport.perl git-cvsimport.perl git-relink.perl \
        git-shortlog.perl git-rerere.perl \
 -      git-annotate.perl git-cvsserver.perl \
 +      git-cvsserver.perl \
        git-svnimport.perl git-cvsexportcommit.perl \
        git-send-email.perl git-svn.perl
  
@@@ -267,9 -265,9 +267,10 @@@ LIB_OBJS = 
  
  BUILTIN_OBJS = \
        builtin-add.o \
 +      builtin-annotate.o \
        builtin-apply.o \
        builtin-archive.o \
+       builtin-branch.o \
        builtin-cat-file.o \
        builtin-checkout-index.o \
        builtin-check-ref-format.o \
        builtin-update-ref.o \
        builtin-upload-archive.o \
        builtin-verify-pack.o \
-       builtin-write-tree.o
+       builtin-write-tree.o \
+       builtin-show-ref.o \
+       builtin-pack-refs.o
  
  GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
  EXTLIBS = -lz
@@@ -679,8 -679,6 +682,8 @@@ gitweb/gitweb.cgi: gitweb/gitweb.per
            -e 's|++GITWEB_CSS++|$(GITWEB_CSS)|g' \
            -e 's|++GITWEB_LOGO++|$(GITWEB_LOGO)|g' \
            -e 's|++GITWEB_FAVICON++|$(GITWEB_FAVICON)|g' \
 +          -e 's|++GITWEB_SITE_HEADER++|$(GITWEB_SITE_HEADER)|g' \
 +          -e 's|++GITWEB_SITE_FOOTER++|$(GITWEB_SITE_FOOTER)|g' \
            $< >$@+
        chmod +x $@+
        mv $@+ $@
@@@ -766,8 -764,6 +769,8 @@@ $(LIB_FILE): $(LIB_OBJS
        rm -f $@ && $(AR) rcs $@ $(LIB_OBJS)
  
  XDIFF_OBJS=xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o
 +$(XDIFF_OBJS): xdiff/xinclude.h xdiff/xmacros.h xdiff/xdiff.h xdiff/xtypes.h \
 +      xdiff/xutils.h xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h
  
  $(XDIFF_LIB): $(XDIFF_OBJS)
        rm -f $@ && $(AR) rcs $@ $(XDIFF_OBJS)
@@@ -864,9 -860,8 +867,9 @@@ git.spec: git.spec.i
        mv $@+ $@
  
  GIT_TARNAME=git-$(GIT_VERSION)
 -dist: git.spec git-tar-tree
 -      ./git-tar-tree HEAD^{tree} $(GIT_TARNAME) > $(GIT_TARNAME).tar
 +dist: git.spec git-archive
 +      ./git-archive --format=tar \
 +              --prefix=$(GIT_TARNAME)/ HEAD^{tree} > $(GIT_TARNAME).tar
        @mkdir -p $(GIT_TARNAME)
        @cp git.spec $(GIT_TARNAME)
        @echo $(GIT_VERSION) > $(GIT_TARNAME)/version
diff --combined builtin-prune.c
index 7290e6d9aa9e26cc8256a34ed22028e80936c010,e79b515c76d9eac9f1ce8e5d88ba0f7058ca53fb..d853902c51e78800b76cf4714dffaa79600d3e53
@@@ -174,7 -174,7 +174,7 @@@ static void walk_commit_list(struct rev
        }
  }
  
- static int add_one_ref(const char *path, const unsigned char *sha1)
+ static int add_one_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
  {
        struct object *object = parse_object(sha1);
        if (!object)
@@@ -240,7 -240,7 +240,7 @@@ int cmd_prune(int argc, const char **ar
        revs.tree_objects = 1;
  
        /* Add all external refs */
-       for_each_ref(add_one_ref);
+       for_each_ref(add_one_ref, NULL);
  
        /* Add all refs from the index file */
        add_cache_refs();
  
        prune_object_dir(get_object_directory());
  
 +      sync();
 +      prune_packed_objects(show_only);
        return 0;
  }
diff --combined builtin.h
index 708a2f22e8b14f337a0829c53c47e57393c4ee75,db9b369e27206fb56e86cddffea5f1ab2c92e5be..f7150aa6b8c715c05ca1a6c0ec2718ba1d48b7fb
+++ b/builtin.h
@@@ -11,12 -11,11 +11,13 @@@ extern int mailinfo(FILE *in, FILE *out
  extern int split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip);
  extern void stripspace(FILE *in, FILE *out);
  extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
 +extern void prune_packed_objects(int);
  
  extern int cmd_add(int argc, const char **argv, const char *prefix);
 +extern int cmd_annotate(int argc, const char **argv, const char *prefix);
  extern int cmd_apply(int argc, const char **argv, const char *prefix);
  extern int cmd_archive(int argc, const char **argv, const char *prefix);
+ extern int cmd_branch(int argc, const char **argv, const char *prefix);
  extern int cmd_cat_file(int argc, const char **argv, const char *prefix);
  extern int cmd_checkout_index(int argc, const char **argv, const char *prefix);
  extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
@@@ -65,5 -64,7 +66,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 f4f7be19167151d79504fbbe8d44951cca7a6a9b,0565333f05e3fc95fb83d472a0590a5efb615af2..e997a8500526024d33e60b87e782557f7c427d14
+++ b/cache.h
@@@ -179,6 -179,7 +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;
@@@ -188,6 -189,7 +189,6 @@@ 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;
  
@@@ -244,8 -246,13 +245,8 @@@ char *enter_repo(char *path, int strict
  extern int sha1_object_info(const unsigned char *, char *, unsigned long *);
  extern void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size);
  extern void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size);
 +extern int hash_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *sha1);
  extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
 -extern char *write_sha1_file_prepare(void *buf,
 -                                   unsigned long len,
 -                                   const char *type,
 -                                   unsigned char *sha1,
 -                                   unsigned char *hdr,
 -                                   int *hdrlen);
  
  extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned long size, const char *type);
  
@@@ -268,9 -275,8 +269,9 @@@ enum object_type 
        OBJ_TREE = 2,
        OBJ_BLOB = 3,
        OBJ_TAG = 4,
 -      /* 5/6 for future expansion */
 -      OBJ_DELTA = 7,
 +      /* 5 for future expansion */
 +      OBJ_OFS_DELTA = 6,
 +      OBJ_REF_DELTA = 7,
        OBJ_BAD,
  };
  
@@@ -288,9 -294,9 +289,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);
diff --combined fetch-pack.c
index 474d54520eae356a8987349b1e36186a30914966,99ac08b2c2528358d51665ef3f301cd68947409c..90b79407c65840deaf1ab80697a90d2e9df12a4a
@@@ -42,7 -42,7 +42,7 @@@ static void rev_list_push(struct commi
        }
  }
  
- static int rev_list_insert_ref(const char *path, const unsigned char *sha1)
+ static int rev_list_insert_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
  {
        struct object *o = deref_tag(parse_object(sha1), path, 0);
  
@@@ -143,7 -143,7 +143,7 @@@ static int find_common(int fd[2], unsig
        unsigned in_vain = 0;
        int got_continue = 0;
  
-       for_each_ref(rev_list_insert_ref);
+       for_each_ref(rev_list_insert_ref, NULL);
  
        fetching = 0;
        for ( ; refs ; refs = refs->next) {
                }
  
                if (!fetching)
 -                      packet_write(fd[1], "want %s%s%s%s%s\n",
 +                      packet_write(fd[1], "want %s%s%s%s%s%s\n",
                                     sha1_to_hex(remote),
                                     (multi_ack ? " multi_ack" : ""),
                                     (use_sideband == 2 ? " side-band-64k" : ""),
                                     (use_sideband == 1 ? " side-band" : ""),
 -                                   (use_thin_pack ? " thin-pack" : ""));
 +                                   (use_thin_pack ? " thin-pack" : ""),
 +                                   " ofs-delta");
                else
                        packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
                fetching++;
@@@ -254,7 -253,7 +254,7 @@@ done
  
  static struct commit_list *complete;
  
- static int mark_complete(const char *path, const unsigned char *sha1)
+ static int mark_complete(const char *path, const unsigned char *sha1, int flag, void *cb_data)
  {
        struct object *o = parse_object(sha1);
  
@@@ -366,7 -365,7 +366,7 @@@ static int everything_local(struct ref 
                }
        }
  
-       for_each_ref(mark_complete);
+       for_each_ref(mark_complete, NULL);
        if (cutoff)
                mark_recent_complete_commits(cutoff);
  
diff --combined git-commit.sh
index 5b1cf85825b0c69f2515445842812a0caf48ef10,8ac8dcc34821b514b814d33287b74e391467f87f..81c3a0cb6152b02ccdcaed607efcd500813ce607
@@@ -32,6 -32,33 +32,6 @@@ save_index () 
        cp -p "$THIS_INDEX" "$NEXT_INDEX"
  }
  
 -report () {
 -  header="#
 -# $1:
 -#   ($2)
 -#
 -"
 -  trailer=""
 -  while read status name newname
 -  do
 -    printf '%s' "$header"
 -    header=""
 -    trailer="#
 -"
 -    case "$status" in
 -    M ) echo "#       modified: $name";;
 -    D*) echo "#       deleted:  $name";;
 -    T ) echo "#       typechange: $name";;
 -    C*) echo "#       copied: $name -> $newname";;
 -    R*) echo "#       renamed: $name -> $newname";;
 -    A*) echo "#       new file: $name";;
 -    U ) echo "#       unmerged: $name";;
 -    esac
 -  done
 -  printf '%s' "$trailer"
 -  [ "$header" ]
 -}
 -
  run_status () {
        # If TMP_INDEX is defined, that means we are doing
        # "--only" partial commit, and that index file is used
        # so the regular index file is what we use to compare.
        if test '' != "$TMP_INDEX"
        then
 -          GIT_INDEX_FILE="$TMP_INDEX"
 -          export GIT_INDEX_FILE
 +              GIT_INDEX_FILE="$TMP_INDEX"
 +              export GIT_INDEX_FILE
        elif test -f "$NEXT_INDEX"
        then
 -          GIT_INDEX_FILE="$NEXT_INDEX"
 -          export GIT_INDEX_FILE
 +              GIT_INDEX_FILE="$NEXT_INDEX"
 +              export GIT_INDEX_FILE
        fi
  
 -  case "$status_only" in
 -    t) color= ;;
 -    *) color=--nocolor ;;
 -  esac
 -  git-runstatus ${color} \
 -                ${verbose:+--verbose} \
 -                ${amend:+--amend} \
 +      case "$status_only" in
 +      t) color= ;;
 +      *) color=--nocolor ;;
 +      esac
 +      git-runstatus ${color} \
 +              ${verbose:+--verbose} \
 +              ${amend:+--amend} \
                ${untracked_files:+--untracked}
  }
  
@@@ -87,181 -114,179 +87,181 @@@ only_include_assumed
  untracked_files=
  while case "$#" in 0) break;; esac
  do
 -  case "$1" in
 -  -F|--F|-f|--f|--fi|--fil|--file)
 -      case "$#" in 1) usage ;; esac
 -      shift
 -      no_edit=t
 -      log_given=t$log_given
 -      logfile="$1"
 -      shift
 -      ;;
 -  -F*|-f*)
 -      no_edit=t
 -      log_given=t$log_given
 -      logfile=`expr "z$1" : 'z-[Ff]\(.*\)'`
 -      shift
 -      ;;
 -  --F=*|--f=*|--fi=*|--fil=*|--file=*)
 -      no_edit=t
 -      log_given=t$log_given
 -      logfile=`expr "z$1" : 'z-[^=]*=\(.*\)'`
 -      shift
 -      ;;
 -  -a|--a|--al|--all)
 -      all=t
 -      shift
 -      ;;
 -  --au=*|--aut=*|--auth=*|--autho=*|--author=*)
 -      force_author=`expr "z$1" : 'z-[^=]*=\(.*\)'`
 -      shift
 -      ;;
 -  --au|--aut|--auth|--autho|--author)
 -      case "$#" in 1) usage ;; esac
 -      shift
 -      force_author="$1"
 -      shift
 -      ;;
 -  -e|--e|--ed|--edi|--edit)
 -      edit_flag=t
 -      shift
 -      ;;
 -  -i|--i|--in|--inc|--incl|--inclu|--includ|--include)
 -      also=t
 -      shift
 -      ;;
 -  -o|--o|--on|--onl|--only)
 -      only=t
 -      shift
 -      ;;
 -  -m|--m|--me|--mes|--mess|--messa|--messag|--message)
 -      case "$#" in 1) usage ;; esac
 -      shift
 -      log_given=m$log_given
 -      if test "$log_message" = ''
 -      then
 -          log_message="$1"
 -      else
 -          log_message="$log_message
 +      case "$1" in
 +      -F|--F|-f|--f|--fi|--fil|--file)
 +              case "$#" in 1) usage ;; esac
 +              shift
 +              no_edit=t
 +              log_given=t$log_given
 +              logfile="$1"
 +              shift
 +              ;;
 +      -F*|-f*)
 +              no_edit=t
 +              log_given=t$log_given
 +              logfile=`expr "z$1" : 'z-[Ff]\(.*\)'`
 +              shift
 +              ;;
 +      --F=*|--f=*|--fi=*|--fil=*|--file=*)
 +              no_edit=t
 +              log_given=t$log_given
 +              logfile=`expr "z$1" : 'z-[^=]*=\(.*\)'`
 +              shift
 +              ;;
 +      -a|--a|--al|--all)
 +              all=t
 +              shift
 +              ;;
 +      --au=*|--aut=*|--auth=*|--autho=*|--author=*)
 +              force_author=`expr "z$1" : 'z-[^=]*=\(.*\)'`
 +              shift
 +              ;;
 +      --au|--aut|--auth|--autho|--author)
 +              case "$#" in 1) usage ;; esac
 +              shift
 +              force_author="$1"
 +              shift
 +              ;;
 +      -e|--e|--ed|--edi|--edit)
 +              edit_flag=t
 +              shift
 +              ;;
 +      -i|--i|--in|--inc|--incl|--inclu|--includ|--include)
 +              also=t
 +              shift
 +              ;;
 +      -o|--o|--on|--onl|--only)
 +              only=t
 +              shift
 +              ;;
 +      -m|--m|--me|--mes|--mess|--messa|--messag|--message)
 +              case "$#" in 1) usage ;; esac
 +              shift
 +              log_given=m$log_given
 +              if test "$log_message" = ''
 +              then
 +                  log_message="$1"
 +              else
 +                  log_message="$log_message
  
  $1"
 -      fi
 -      no_edit=t
 -      shift
 -      ;;
 -  -m*)
 -      log_given=m$log_given
 -      if test "$log_message" = ''
 -      then
 -          log_message=`expr "z$1" : 'z-m\(.*\)'`
 -      else
 -          log_message="$log_message
 +              fi
 +              no_edit=t
 +              shift
 +              ;;
 +      -m*)
 +              log_given=m$log_given
 +              if test "$log_message" = ''
 +              then
 +                  log_message=`expr "z$1" : 'z-m\(.*\)'`
 +              else
 +                  log_message="$log_message
  
  `expr "z$1" : 'z-m\(.*\)'`"
 -      fi
 -      no_edit=t
 -      shift
 -      ;;
 -  --m=*|--me=*|--mes=*|--mess=*|--messa=*|--messag=*|--message=*)
 -      log_given=m$log_given
 -      if test "$log_message" = ''
 -      then
 -          log_message=`expr "z$1" : 'z-[^=]*=\(.*\)'`
 -      else
 -          log_message="$log_message
 +              fi
 +              no_edit=t
 +              shift
 +              ;;
 +      --m=*|--me=*|--mes=*|--mess=*|--messa=*|--messag=*|--message=*)
 +              log_given=m$log_given
 +              if test "$log_message" = ''
 +              then
 +                  log_message=`expr "z$1" : 'z-[^=]*=\(.*\)'`
 +              else
 +                  log_message="$log_message
  
  `expr "z$1" : 'zq-[^=]*=\(.*\)'`"
 -      fi
 -      no_edit=t
 -      shift
 -      ;;
 -  -n|--n|--no|--no-|--no-v|--no-ve|--no-ver|--no-veri|--no-verif|--no-verify)
 -      verify=
 -      shift
 -      ;;
 -  --a|--am|--ame|--amen|--amend)
 -      amend=t
 -      log_given=t$log_given
 -      use_commit=HEAD
 -      shift
 -      ;;
 -  -c)
 -      case "$#" in 1) usage ;; esac
 -      shift
 -      log_given=t$log_given
 -      use_commit="$1"
 -      no_edit=
 -      shift
 -      ;;
 -  --ree=*|--reed=*|--reedi=*|--reedit=*|--reedit-=*|--reedit-m=*|\
 -  --reedit-me=*|--reedit-mes=*|--reedit-mess=*|--reedit-messa=*|\
 -  --reedit-messag=*|--reedit-message=*)
 -      log_given=t$log_given
 -      use_commit=`expr "z$1" : 'z-[^=]*=\(.*\)'`
 -      no_edit=
 -      shift
 -      ;;
 -  --ree|--reed|--reedi|--reedit|--reedit-|--reedit-m|--reedit-me|\
 -  --reedit-mes|--reedit-mess|--reedit-messa|--reedit-messag|--reedit-message)
 -      case "$#" in 1) usage ;; esac
 -      shift
 -      log_given=t$log_given
 -      use_commit="$1"
 -      no_edit=
 -      shift
 -      ;;
 -  -C)
 -      case "$#" in 1) usage ;; esac
 -      shift
 -      log_given=t$log_given
 -      use_commit="$1"
 -      no_edit=t
 -      shift
 -      ;;
 -  --reu=*|--reus=*|--reuse=*|--reuse-=*|--reuse-m=*|--reuse-me=*|\
 -  --reuse-mes=*|--reuse-mess=*|--reuse-messa=*|--reuse-messag=*|\
 -  --reuse-message=*)
 -      log_given=t$log_given
 -      use_commit=`expr "z$1" : 'z-[^=]*=\(.*\)'`
 -      no_edit=t
 -      shift
 -      ;;
 -  --reu|--reus|--reuse|--reuse-|--reuse-m|--reuse-me|--reuse-mes|\
 -  --reuse-mess|--reuse-messa|--reuse-messag|--reuse-message)
 -      case "$#" in 1) usage ;; esac
 -      shift
 -      log_given=t$log_given
 -      use_commit="$1"
 -      no_edit=t
 -      shift
 -      ;;
 -  -s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
 -      signoff=t
 -      shift
 -      ;;
 -  -v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
 -      verbose=t
 -      shift
 -      ;;
 -  -u|--u|--un|--unt|--untr|--untra|--untrac|--untrack|--untracke|--untracked|\
 -  --untracked-|--untracked-f|--untracked-fi|--untracked-fil|--untracked-file|\
 -  --untracked-files)
 -      untracked_files=t
 -      shift
 -      ;;
 -  --)
 -      shift
 -      break
 -      ;;
 -  -*)
 -      usage
 -      ;;
 -  *)
 -      break
 -      ;;
 -  esac
 +              fi
 +              no_edit=t
 +              shift
 +              ;;
 +      -n|--n|--no|--no-|--no-v|--no-ve|--no-ver|--no-veri|--no-verif|\
 +      --no-verify)
 +              verify=
 +              shift
 +              ;;
 +      --a|--am|--ame|--amen|--amend)
 +              amend=t
 +              log_given=t$log_given
 +              use_commit=HEAD
 +              shift
 +              ;;
 +      -c)
 +              case "$#" in 1) usage ;; esac
 +              shift
 +              log_given=t$log_given
 +              use_commit="$1"
 +              no_edit=
 +              shift
 +              ;;
 +      --ree=*|--reed=*|--reedi=*|--reedit=*|--reedit-=*|--reedit-m=*|\
 +      --reedit-me=*|--reedit-mes=*|--reedit-mess=*|--reedit-messa=*|\
 +      --reedit-messag=*|--reedit-message=*)
 +              log_given=t$log_given
 +              use_commit=`expr "z$1" : 'z-[^=]*=\(.*\)'`
 +              no_edit=
 +              shift
 +              ;;
 +      --ree|--reed|--reedi|--reedit|--reedit-|--reedit-m|--reedit-me|\
 +      --reedit-mes|--reedit-mess|--reedit-messa|--reedit-messag|\
 +      --reedit-message)
 +              case "$#" in 1) usage ;; esac
 +              shift
 +              log_given=t$log_given
 +              use_commit="$1"
 +              no_edit=
 +              shift
 +              ;;
 +      -C)
 +              case "$#" in 1) usage ;; esac
 +              shift
 +              log_given=t$log_given
 +              use_commit="$1"
 +              no_edit=t
 +              shift
 +              ;;
 +      --reu=*|--reus=*|--reuse=*|--reuse-=*|--reuse-m=*|--reuse-me=*|\
 +      --reuse-mes=*|--reuse-mess=*|--reuse-messa=*|--reuse-messag=*|\
 +      --reuse-message=*)
 +              log_given=t$log_given
 +              use_commit=`expr "z$1" : 'z-[^=]*=\(.*\)'`
 +              no_edit=t
 +              shift
 +              ;;
 +      --reu|--reus|--reuse|--reuse-|--reuse-m|--reuse-me|--reuse-mes|\
 +      --reuse-mess|--reuse-messa|--reuse-messag|--reuse-message)
 +              case "$#" in 1) usage ;; esac
 +              shift
 +              log_given=t$log_given
 +              use_commit="$1"
 +              no_edit=t
 +              shift
 +              ;;
 +      -s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
 +              signoff=t
 +              shift
 +              ;;
 +      -v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
 +              verbose=t
 +              shift
 +              ;;
 +      -u|--u|--un|--unt|--untr|--untra|--untrac|--untrack|--untracke|\
 +      --untracked|--untracked-|--untracked-f|--untracked-fi|--untracked-fil|\
 +      --untracked-file|--untracked-files)
 +              untracked_files=t
 +              shift
 +              ;;
 +      --)
 +              shift
 +              break
 +              ;;
 +      -*)
 +              usage
 +              ;;
 +      *)
 +              break
 +              ;;
 +      esac
  done
  case "$edit_flag" in t) no_edit= ;; esac
  
  
  case "$amend,$initial_commit" in
  t,t)
 -  die "You do not have anything to amend." ;;
 +      die "You do not have anything to amend." ;;
  t,)
 -  if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
 -    die "You are in the middle of a merge -- cannot amend."
 -  fi ;;
 +      if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
 +              die "You are in the middle of a merge -- cannot amend."
 +      fi ;;
  esac
  
  case "$log_given" in
  tt*)
 -  die "Only one of -c/-C/-F can be used." ;;
 +      die "Only one of -c/-C/-F can be used." ;;
  *tm*|*mt*)
 -  die "Option -m cannot be combined with -c/-C/-F." ;;
 +      die "Option -m cannot be combined with -c/-C/-F." ;;
  esac
  
  case "$#,$also,$only,$amend" in
  *,t,t,*)
 -  die "Only one of --include/--only can be used." ;;
 +      die "Only one of --include/--only can be used." ;;
  0,t,,* | 0,,t,)
 -  die "No paths with --include/--only does not make sense." ;;
 +      die "No paths with --include/--only does not make sense." ;;
  0,,t,t)
 -  only_include_assumed="# Clever... amending the last one with dirty index." ;;
 +      only_include_assumed="# Clever... amending the last one with dirty index." ;;
  0,,,*)
 -  ;;
 +      ;;
  *,,,*)
 -  only_include_assumed="# Explicit paths specified without -i nor -o; assuming --only paths..."
 -  also=
 -  ;;
 +      only_include_assumed="# Explicit paths specified without -i nor -o; assuming --only paths..."
 +      also=
 +      ;;
  esac
  unset only
  case "$all,$also,$#" in
@@@ -343,47 -368,47 +343,47 @@@ t,
  ,)
        case "$#" in
        0)
 -          ;; # commit as-is
 +              ;; # commit as-is
        *)
 -          if test -f "$GIT_DIR/MERGE_HEAD"
 -          then
 -              refuse_partial "Cannot do a partial commit during a merge."
 -          fi
 -          TMP_INDEX="$GIT_DIR/tmp-index$$"
 -          if test -z "$initial_commit"
 -          then
 -              # make sure index is clean at the specified paths, or
 -              # they are additions.
 -              dirty_in_index=`git-diff-index --cached --name-status \
 -                      --diff-filter=DMTU HEAD -- "$@"`
 -              test -z "$dirty_in_index" ||
 -              refuse_partial "Different in index and the last commit:
 +              if test -f "$GIT_DIR/MERGE_HEAD"
 +              then
 +                      refuse_partial "Cannot do a partial commit during a merge."
 +              fi
 +              TMP_INDEX="$GIT_DIR/tmp-index$$"
 +              if test -z "$initial_commit"
 +              then
 +                      # make sure index is clean at the specified paths, or
 +                      # they are additions.
 +                      dirty_in_index=`git-diff-index --cached --name-status \
 +                              --diff-filter=DMTU HEAD -- "$@"`
 +                      test -z "$dirty_in_index" ||
 +                      refuse_partial "Different in index and the last commit:
  $dirty_in_index"
 -          fi
 -          commit_only=`git-ls-files --error-unmatch -- "$@"` || exit
 +              fi
 +              commit_only=`git-ls-files --error-unmatch -- "$@"` || exit
  
 -          # Build the temporary index and update the real index
 -          # the same way.
 -          if test -z "$initial_commit"
 -          then
 -              cp "$THIS_INDEX" "$TMP_INDEX"
 -              GIT_INDEX_FILE="$TMP_INDEX" git-read-tree -m HEAD
 -          else
 -                  rm -f "$TMP_INDEX"
 -          fi || exit
 +              # Build the temporary index and update the real index
 +              # the same way.
 +              if test -z "$initial_commit"
 +              then
 +                      cp "$THIS_INDEX" "$TMP_INDEX"
 +                      GIT_INDEX_FILE="$TMP_INDEX" git-read-tree -m HEAD
 +              else
 +                      rm -f "$TMP_INDEX"
 +              fi || exit
  
 -          echo "$commit_only" |
 -          GIT_INDEX_FILE="$TMP_INDEX" \
 -          git-update-index --add --remove --stdin &&
 +              echo "$commit_only" |
 +              GIT_INDEX_FILE="$TMP_INDEX" \
 +              git-update-index --add --remove --stdin &&
  
 -          save_index &&
 -          echo "$commit_only" |
 -          (
 -              GIT_INDEX_FILE="$NEXT_INDEX"
 -              export GIT_INDEX_FILE
 -              git-update-index --remove --stdin
 -          ) || exit
 -          ;;
 +              save_index &&
 +              echo "$commit_only" |
 +              (
 +                      GIT_INDEX_FILE="$NEXT_INDEX"
 +                      export GIT_INDEX_FILE
 +                      git-update-index --remove --stdin
 +              ) || exit
 +              ;;
        esac
        ;;
  esac
@@@ -401,7 -426,7 +401,7 @@@ els
  fi
  
  GIT_INDEX_FILE="$USE_INDEX" \
 -    git-update-index -q $unmerged_ok_if_status --refresh || exit
 +      git-update-index -q $unmerged_ok_if_status --refresh || exit
  
  ################################################################
  # If the request is status, just show it and exit.
@@@ -441,7 -466,7 +441,7 @@@ the
  elif test "$use_commit" != ""
  then
        git-cat-file commit "$use_commit" | sed -e '1,/^$/d'
- elif test -f "$GIT_DIR/MERGE_HEAD" && test -f "$GIT_DIR/MERGE_MSG"
+ elif test -f "$GIT_DIR/MERGE_MSG"
  then
        cat "$GIT_DIR/MERGE_MSG"
  elif test -f "$GIT_DIR/SQUASH_MSG"
@@@ -522,15 -547,15 +522,15 @@@ the
                PARENTS=$(git-cat-file commit HEAD |
                        sed -n -e '/^$/q' -e 's/^parent /-p /p')
        fi
-       current=$(git-rev-parse --verify HEAD)
+       current="$(git-rev-parse --verify HEAD)"
  else
        if [ -z "$(git-ls-files)" ]; then
                echo >&2 Nothing to commit
                exit 1
        fi
        PARENTS=""
-       current=
        rloga='commit (initial)'
+       current=''
  fi
  
  if test -z "$no_edit"
@@@ -606,8 -631,8 +606,8 @@@ the
        fi &&
        commit=$(cat "$GIT_DIR"/COMMIT_MSG | git-commit-tree $tree $PARENTS) &&
        rlogm=$(sed -e 1q "$GIT_DIR"/COMMIT_MSG) &&
-       git-update-ref -m "$rloga: $rlogm" HEAD $commit $current &&
-       rm -f -- "$GIT_DIR/MERGE_HEAD" &&
+       git-update-ref -m "$rloga: $rlogm" HEAD $commit "$current" &&
+       rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" &&
        if test -f "$NEXT_INDEX"
        then
                mv "$NEXT_INDEX" "$THIS_INDEX"
diff --combined git-fetch.sh
index 7dc1f33687279812605c7b6f9ddc13478e143058,e8a766818282d1ace559d4a5148927a656e2b492..fa73ad2260bb2a48308feed3c4670610f3eff7a7
@@@ -129,25 -129,22 +129,25 @@@ append_fetch_head () 
      then
        headc_=$(git-rev-parse --verify "$head_^0") || exit
        echo "$headc_   $not_for_merge_ $note_" >>"$GIT_DIR/FETCH_HEAD"
 -      [ "$verbose" ] && echo >&2 "* committish: $head_"
 -      [ "$verbose" ] && echo >&2 "  $note_"
      else
        echo "$head_    not-for-merge   $note_" >>"$GIT_DIR/FETCH_HEAD"
 -      [ "$verbose" ] && echo >&2 "* non-commit: $head_"
 -      [ "$verbose" ] && echo >&2 "  $note_"
 -    fi
 -    if test "$local_name_" != ""
 -    then
 -      # We are storing the head locally.  Make sure that it is
 -      # a fast forward (aka "reverse push").
 -      fast_forward_local "$local_name_" "$head_" "$note_"
      fi
 +
 +    update_local_ref "$local_name_" "$head_" "$note_"
  }
  
 -fast_forward_local () {
 +update_local_ref () {
 +    # If we are storing the head locally make sure that it is
 +    # a fast forward (aka "reverse push").
 +
 +    label_=$(git-cat-file -t $2)
 +    newshort_=$(git-rev-parse --short $2)
 +    if test -z "$1" ; then
 +      [ "$verbose" ] && echo >&2 "* fetched $3"
 +      [ "$verbose" ] && echo >&2 "  $label_: $newshort_"
 +      return 0
 +    fi
 +    oldshort_=$(git-rev-parse --short "$1" 2>/dev/null)
      mkdir -p "$(dirname "$GIT_DIR/$1")"
      case "$1" in
      refs/tags/*)
        then
                if now_=$(cat "$GIT_DIR/$1") && test "$now_" = "$2"
                then
 -                      [ "$verbose" ] && echo >&2 "* $1: same as $3" ||:
 +                      [ "$verbose" ] && echo >&2 "* $1: same as $3"
 +                      [ "$verbose" ] && echo >&2 "  $label_: $newshort_" ||:
                else
                        echo >&2 "* $1: updating with $3"
 +                      echo >&2 "  $label_: $newshort_"
                        git-update-ref -m "$rloga: updating tag" "$1" "$2"
                fi
        else
                echo >&2 "* $1: storing $3"
 +              echo >&2 "  $label_: $newshort_"
                git-update-ref -m "$rloga: storing tag" "$1" "$2"
        fi
        ;;
                if test -n "$verbose"
                then
                        echo >&2 "* $1: same as $3"
 +                      echo >&2 "  $label_: $newshort_"
                fi
                ;;
            *,$local)
                echo >&2 "* $1: fast forward to $3"
 -              echo >&2 "  from $local to $2"
 +              echo >&2 "  old..new: $oldshort_..$newshort_"
                git-update-ref -m "$rloga: fast-forward" "$1" "$2" "$local"
                ;;
            *)
                false
                ;;
            esac || {
 -              echo >&2 "* $1: does not fast forward to $3;"
                case ",$force,$single_force," in
                *,t,*)
 -                      echo >&2 "  forcing update."
 +                      echo >&2 "* $1: forcing update to non-fast forward $3"
 +                      echo >&2 "  old...new: $oldshort_...$newshort_"
                        git-update-ref -m "$rloga: forced-update" "$1" "$2" "$local"
                        ;;
                *)
 -                      echo >&2 "  not updating."
 +                      echo >&2 "* $1: not updating to non-fast forward $3"
 +                      echo >&2 "  old...new: $oldshort_...$newshort_"
                        exit 1
                        ;;
                esac
            }
        else
            echo >&2 "* $1: storing $3"
 +          echo >&2 "  $label_: $newshort_"
            git-update-ref -m "$rloga: storing head" "$1" "$2"
        fi
        ;;
@@@ -296,7 -287,6 +296,7 @@@ fetch_main () 
        # There are transports that can fetch only one head at a time...
        case "$remote" in
        http://* | https://* | ftp://*)
 +        proto=`expr "$remote" : '\([^:]*\):'`
          if [ -n "$GIT_SSL_NO_VERIFY" ]; then
              curl_extra_args="-k"
          fi
          done
          expr "z$head" : "z$_x40\$" >/dev/null ||
              die "Failed to fetch $remote_name from $remote"
 -        echo >&2 Fetching "$remote_name from $remote" using http
 +        echo >&2 "Fetching $remote_name from $remote using $proto"
          git-http-fetch -v -a "$head" "$remote/" || exit
          ;;
        rsync://*)
@@@ -427,7 -417,7 +427,7 @@@ case "$no_tags$tags" i
                sed -ne 's|^\([0-9a-f]*\)[      ]\(refs/tags/.*\)^{}$|\1 \2|p' |
                while read sha1 name
                do
-                       test -f "$GIT_DIR/$name" && continue
+                       git-show-ref --verify --quiet -- $name && continue
                        git-check-ref-format "$name" || {
                                echo >&2 "warning: tag ${name} ignored"
                                continue
@@@ -446,10 -436,10 +446,10 @@@ esa
  
  # If the original head was empty (i.e. no "master" yet), or
  # if we were told not to worry, we do not have to check.
 -case ",$update_head_ok,$orig_head," in
 -*,, | t,* )
 +case "$orig_head" in
 +'')
        ;;
 -*)
 +?*)
        curr_head=$(git-rev-parse --verify HEAD 2>/dev/null)
        if test "$curr_head" != "$orig_head"
        then
diff --combined git-revert.sh
index 4fd81b6ed60e5877df85c1052057b0ad5410f4fe,066e67753e939c3697082d48d6caee6e4b303796..6eab3c72df0db0994a352836018a7fc35ba1eae3
@@@ -7,20 -7,18 +7,20 @@@
  case "$0" in
  *-revert* )
        test -t 0 && edit=-e
 +      replay=
        me=revert
        USAGE='[--edit | --no-edit] [-n] <commit-ish>' ;;
  *-cherry-pick* )
 +      replay=t
        edit=
        me=cherry-pick
 -      USAGE='[--edit] [-n] [-r] <commit-ish>'  ;;
 +      USAGE='[--edit] [-n] [-r] [-x] <commit-ish>'  ;;
  * )
        die "What are you talking about?" ;;
  esac
  . git-sh-setup
  
 -no_commit= replay=
 +no_commit=
  while case "$#" in 0) break ;; esac
  do
        case "$1" in
        --n|--no|--no-|--no-e|--no-ed|--no-edi|--no-edit)
                edit=
                ;;
 -      -r|--r|--re|--rep|--repl|--repla|--replay)
 -              replay=t
 +      -r)
 +              : no-op ;;
 +      -x|--i-really-want-to-expose-my-private-commit-object-name)
 +              replay=
                ;;
        -*)
                usage
@@@ -125,7 -121,7 +125,7 @@@ cherry-pick
        git-cat-file commit $commit | sed -e '1,/^$/d'
        case "$replay" in
        '')
 -              echo "(cherry picked from $commit commit)"
 +              echo "(cherry picked from commit $commit)"
                test "$rev" = "$commit" ||
                echo "(original 'git cherry-pick' arguments: $@)"
                ;;
@@@ -145,9 -141,18 +145,18 @@@ git-read-tree -m -u --aggressive $base 
  result=$(git-write-tree 2>/dev/null) || {
      echo >&2 "Simple $me fails; trying Automatic $me."
      git-merge-index -o git-merge-one-file -a || {
+           mv -f .msg "$GIT_DIR/MERGE_MSG"
+           {
+               echo '
+ Conflicts:
+ '
+               git ls-files --unmerged |
+               sed -e 's/^[^   ]*      /       /' |
+               uniq
+           } >>"$GIT_DIR/MERGE_MSG"
            echo >&2 "Automatic $me failed.  After resolving the conflicts,"
            echo >&2 "mark the corrected paths with 'git-update-index <paths>'"
-           echo >&2 "and commit with 'git commit -F .msg'"
+           echo >&2 "and commit the result."
            case "$me" in
            cherry-pick)
                echo >&2 "You may choose to use the following when making"
diff --combined git.c
index 6475847b7a06750f8095c363dbc7414213042cca,f197169df278ccf5560b9aa61f81ac35526a34e4..af181d93b1ca5908ea58acea73394b1f36554b39
--- 1/git.c
--- 2/git.c
+++ b/git.c
@@@ -16,7 -16,7 +16,7 @@@
  #include "builtin.h"
  
  const char git_usage_string[] =
 -      "git [--version] [--exec-path[=GIT_EXEC_PATH]] [--help] COMMAND [ ARGS ]";
 +      "git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate] [--bare] [--git-dir=GIT_DIR] [--help] COMMAND [ARGS]";
  
  static void prepend_to_path(const char *dir, int len)
  {
@@@ -219,15 -219,15 +219,16 @@@ static void handle_internal_command(in
                int option;
        } commands[] = {
                { "add", cmd_add, RUN_SETUP },
 +              { "annotate", cmd_annotate, },
                { "apply", cmd_apply },
                { "archive", cmd_archive },
+               { "branch", cmd_branch },
                { "cat-file", cmd_cat_file, RUN_SETUP },
                { "checkout-index", cmd_checkout_index, RUN_SETUP },
                { "check-ref-format", cmd_check_ref_format },
                { "commit-tree", cmd_commit_tree, RUN_SETUP },
                { "count-objects", cmd_count_objects, RUN_SETUP },
 -              { "diff", cmd_diff, RUN_SETUP },
 +              { "diff", cmd_diff, RUN_SETUP | USE_PAGER },
                { "diff-files", cmd_diff_files, RUN_SETUP },
                { "diff-index", cmd_diff_index, RUN_SETUP },
                { "diff-stages", cmd_diff_stages, RUN_SETUP },
                { "show", cmd_show, RUN_SETUP | USE_PAGER },
                { "stripspace", cmd_stripspace },
                { "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
 -              { "tar-tree", cmd_tar_tree, RUN_SETUP },
 +              { "tar-tree", cmd_tar_tree },
                { "unpack-objects", cmd_unpack_objects, RUN_SETUP },
                { "update-index", cmd_update_index, RUN_SETUP },
                { "update-ref", cmd_update_ref, RUN_SETUP },
                { "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 f2b1c29bd763fcfec45be05e9f56b7c4f5503995,1fcf3a91127250448a659fe0d48393c34ecd7c47..de1d6a4b1c3f51f8763484b6efea0a8ccd289bb3
@@@ -9,26 -9,12 +9,26 @@@ static const char receive_pack_usage[] 
  
  static const char *unpacker[] = { "unpack-objects", NULL };
  
 +static int deny_non_fast_forwards = 0;
  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 receive_pack_config(const char *var, const char *value)
 +{
 +      git_default_config(var, value);
 +
 +      if (strcmp(var, "receive.denynonfastforwards") == 0)
 +      {
 +              deny_non_fast_forwards = git_config_bool(var, value);
 +              return 0;
 +      }
 +
 +      return 0;
 +}
 +
+ 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);
@@@ -41,9 -27,9 +41,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);
  
  }
  
@@@ -57,34 -43,6 +57,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,
@@@ -121,8 -79,8 +93,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, "
                        return error("denying non-fast forward;"
                                     " you should pull first");
        }
-       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 (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";
@@@ -349,10 -275,11 +289,11 @@@ 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);
  
 -      git_config(git_default_config);
+       setup_ident();
 +      git_config(receive_pack_config);
  
        write_head_info();
  
diff --combined revision.c
index 04fa7e517153d2fa8a08da961070e8c54372cc5e,d87cb6cd6474375c85855670fef713288af2fb34..3dbc26c49c585088ff4861992ce70a94465df401
@@@ -418,6 -418,9 +418,6 @@@ static void limit_list(struct rev_info 
  
                if (revs->max_age != -1 && (commit->date < revs->max_age))
                        obj->flags |= UNINTERESTING;
 -              if (revs->unpacked &&
 -                  has_sha1_pack(obj->sha1, revs->ignore_packed))
 -                      obj->flags |= UNINTERESTING;
                add_parents_to_list(revs, commit, &list);
                if (obj->flags & UNINTERESTING) {
                        mark_parents_uninteresting(commit);
  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, "");
@@@ -476,7 -479,7 +476,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)
@@@ -729,7 -732,6 +729,7 @@@ int setup_revisions(int argc, const cha
        int i, flags, seen_dashdash, show_merge;
        const char **unrecognized = argv + 1;
        int left = 1;
 +      int all_match = 0;
  
        /* First, search for "--" */
        seen_dashdash = 0;
                                add_message_grep(revs, arg+7);
                                continue;
                        }
 +                      if (!strcmp(arg, "--all-match")) {
 +                              all_match = 1;
 +                              continue;
 +                      }
  
                        opts = diff_opt_parse(&revs->diffopt, argv+i, argc-i);
                        if (opts > 0) {
                add_pending_object(revs, object, def);
        }
  
 -      if (revs->topo_order || revs->unpacked)
 +      if (revs->topo_order)
                revs->limited = 1;
  
        if (revs->prune_data) {
        if (diff_setup_done(&revs->diffopt) < 0)
                die("diff_setup_done failed");
  
 -      if (revs->grep_filter)
 +      if (revs->grep_filter) {
 +              revs->grep_filter->all_match = all_match;
                compile_grep_patterns(revs->grep_filter);
 +      }
  
        return left;
  }
@@@ -1146,18 -1142,17 +1146,18 @@@ struct commit *get_revision(struct rev_
                 * that we'd otherwise have done in limit_list().
                 */
                if (!revs->limited) {
 -                      if ((revs->unpacked &&
 -                           has_sha1_pack(commit->object.sha1,
 -                                         revs->ignore_packed)) ||
 -                          (revs->max_age != -1 &&
 -                           (commit->date < revs->max_age)))
 +                      if (revs->max_age != -1 &&
 +                          (commit->date < revs->max_age))
                                continue;
                        add_parents_to_list(revs, commit, &revs->commits);
                }
                if (commit->object.flags & SHOWN)
                        continue;
  
 +              if (revs->unpacked && has_sha1_pack(commit->object.sha1,
 +                                                  revs->ignore_packed))
 +                  continue;
 +
                /* We want to show boundary commits only when their
                 * children are shown.  When path-limiter is in effect,
                 * rewrite_parents() drops some commits from getting shown,
diff --combined sha1_name.c
index 6ffee22081aee3fc7b27b9ccc93c4c721652ec4b,5cf5578af1e346788bd6276a26d996cb83a2208d..6d7cd78381414aa2fef31d31d46fbb24b0aaab1d
@@@ -157,7 -157,7 +157,7 @@@ static int get_short_sha1(const char *n
        char canonical[40];
        unsigned char res[20];
  
 -      if (len < MINIMUM_ABBREV)
 +      if (len < MINIMUM_ABBREV || len > 40)
                return -1;
        hashclr(res);
        memset(canonical, 'x', 40);
@@@ -247,26 -247,25 +247,25 @@@ 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;
-       int refs_found = 0, am;
-       unsigned long at_time = (unsigned long)-1;
+       const char **p, *ref;
+       char *real_ref = NULL;
+       int refs_found = 0;
+       int at, reflog_len;
        unsigned char *this_result;
        unsigned char sha1_from_ref[20];
  
        if (len == 40 && !get_sha1_hex(str, sha1))
                return 0;
  
-       /* At a given period of time? "@{2 hours ago}" */
-       for (am = 1; am < len - 1; am++) {
-               if (str[am] == '@' && str[am+1] == '{' && str[len-1] == '}') {
-                       int date_len = len - am - 3;
-                       char *date_spec = xmalloc(date_len + 1);
-                       strlcpy(date_spec, str + am + 2, date_len + 1);
-                       at_time = approxidate(date_spec);
-                       free(date_spec);
-                       len = am;
-                       break;
+       /* basic@{time or number} format to query ref-log */
+       reflog_len = at = 0;
+       if (str[len-1] == '}') {
+               for (at = 1; at < len - 1; at++) {
+                       if (str[at] == '@' && str[at+1] == '{') {
+                               reflog_len = (len-1) - (at+2);
+                               len = at;
+                               break;
+                       }
                }
        }
  
  
        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 (warn_ambiguous_refs && refs_found > 1)
                fprintf(stderr, warning, len, str);
  
-       if (at_time != (unsigned long)-1) {
-               read_ref_at(
-                       real_path + strlen(git_path(".")) - 1,
-                       at_time,
-                       sha1);
+       if (reflog_len) {
+               /* Is it asking for N-th entry, or approxidate? */
+               int nth, i;
+               unsigned long at_time;
+               for (i = nth = 0; 0 <= nth && i < reflog_len; i++) {
+                       char ch = str[at+2+i];
+                       if ('0' <= ch && ch <= '9')
+                               nth = nth * 10 + ch - '0';
+                       else
+                               nth = -1;
+               }
+               if (0 <= nth)
+                       at_time = 0;
+               else
+                       at_time = approxidate(str + at + 2);
+               read_ref_at(real_ref, at_time, nth, sha1);
        }
  
-       free(real_path);
+       free(real_ref);
        return 0;
  }
  
diff --combined upload-pack.c
index 9ec3775049a44bf1ffdc145240e6d7cdea303b91,9412a9b2604af161bd8f88c27750e95a24a78097..ddaa72f0a98e9b7f424279b74798bc3cfaadbd48
@@@ -16,7 -16,7 +16,7 @@@ static const char upload_pack_usage[] 
  #define OUR_REF (1U << 1)
  #define WANTED (1U << 2)
  static int multi_ack, nr_our_refs;
 -static int use_thin_pack;
 +static int use_thin_pack, use_ofs_delta;
  static struct object_array have_obj;
  static struct object_array want_obj;
  static unsigned int timeout;
@@@ -137,9 -137,7 +137,9 @@@ static void create_pack_file(void
                close(pu_pipe[1]);
                close(pe_pipe[0]);
                close(pe_pipe[1]);
 -              execl_git_cmd("pack-objects", "--stdout", "--progress", NULL);
 +              execl_git_cmd("pack-objects", "--stdout", "--progress",
 +                            use_ofs_delta ? "--delta-base-offset" : NULL,
 +                            NULL);
                kill(pid_rev_list, SIGKILL);
                die("git-upload-pack: unable to exec git-pack-objects");
        }
@@@ -395,8 -393,6 +395,8 @@@ static void receive_needs(void
                        multi_ack = 1;
                if (strstr(line+45, "thin-pack"))
                        use_thin_pack = 1;
 +              if (strstr(line+45, "ofs-delta"))
 +                      use_ofs_delta = 1;
                if (strstr(line+45, "side-band-64k"))
                        use_sideband = LARGE_PACKET_MAX;
                else if (strstr(line+45, "side-band"))
        }
  }
  
- static int send_ref(const char *refname, const unsigned char *sha1)
+ static int send_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
  {
 -      static const char *capabilities = "multi_ack thin-pack side-band side-band-64k";
 +      static const char *capabilities = "multi_ack thin-pack side-band side-band-64k ofs-delta";
        struct object *o = parse_object(sha1);
  
        if (!o)
  static void upload_pack(void)
  {
        reset_timeout();
-       head_ref(send_ref);
-       for_each_ref(send_ref);
+       head_ref(send_ref, NULL);
+       for_each_ref(send_ref, NULL);
        packet_flush(1);
        receive_needs();
        if (want_obj.nr) {
diff --combined wt-status.c
index 3952809c2a2d5526e5b97ad57a53b601906e01a2,d8e284c311cb480f77085b0ba563cfa999920a43..7dd68575d1909d1a48246814c83d407f8225ea9d
@@@ -41,10 -41,8 +41,8 @@@ void wt_status_prepare(struct wt_statu
  
        s->is_initial = get_sha1("HEAD", sha1) ? 1 : 0;
  
-       head = resolve_ref(git_path("HEAD"), sha1, 0);
-       s->branch = head ?
-                   strdup(head + strlen(get_git_dir()) + 1) :
-                   NULL;
+       head = resolve_ref("HEAD", sha1, 0, NULL);
+       s->branch = head ? xstrdup(head) : NULL;
  
        s->reference = "HEAD";
        s->amend = 0;
@@@ -72,25 -70,25 +70,25 @@@ static void wt_status_print_filepair(in
        color_printf(color(WT_STATUS_HEADER), "#\t");
        switch (p->status) {
        case DIFF_STATUS_ADDED:
 -              color_printf(c, "new file: %s", p->one->path); break;
 +              color_printf(c, "new file:   %s", p->one->path); break;
        case DIFF_STATUS_COPIED:
 -              color_printf(c, "copied: %s -> %s",
 +              color_printf(c, "copied:     %s -> %s",
                                p->one->path, p->two->path);
                break;
        case DIFF_STATUS_DELETED:
 -              color_printf(c, "deleted: %s", p->one->path); break;
 +              color_printf(c, "deleted:    %s", p->one->path); break;
        case DIFF_STATUS_MODIFIED:
 -              color_printf(c, "modified: %s", p->one->path); break;
 +              color_printf(c, "modified:   %s", p->one->path); break;
        case DIFF_STATUS_RENAMED:
 -              color_printf(c, "renamed: %s -> %s",
 +              color_printf(c, "renamed:    %s -> %s",
                                p->one->path, p->two->path);
                break;
        case DIFF_STATUS_TYPE_CHANGED:
                color_printf(c, "typechange: %s", p->one->path); break;
        case DIFF_STATUS_UNKNOWN:
 -              color_printf(c, "unknown: %s", p->one->path); break;
 +              color_printf(c, "unknown:    %s", p->one->path); break;
        case DIFF_STATUS_UNMERGED:
 -              color_printf(c, "unmerged: %s", p->one->path); break;
 +              color_printf(c, "unmerged:   %s", p->one->path); break;
        default:
                die("bug: unhandled diff status %c", p->status);
        }