Merge branch 'maint'
authorJunio C Hamano <gitster@pobox.com>
Mon, 24 Sep 2007 00:13:55 +0000 (17:13 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 24 Sep 2007 00:13:55 +0000 (17:13 -0700)
* maint:
git-svn: don't attempt to spawn pager if we don't want one
Supplant the "while case ... break ;; esac" idiom
User Manual: add a chapter for submodules
user-manual: don't assume refs are stored under .git/refs
Detect exec bit in more cases.
Conjugate "search" correctly in the git-prune-packed man page.
Move the paragraph specifying where the .idx and .pack files should be
Documentation/git-lost-found.txt: drop unnecessarily duplicated name.

1  2 
Documentation/git-pack-objects.txt
contrib/examples/git-reset.sh
contrib/fast-import/git-p4
git-commit.sh
git-rebase.sh
git-svn.perl
index 628f296ce1366f728d9a2321bd02e3db492adffb,d18259d93fe1daf1785f373b475add8ff9d2f213..5237ab0c046cb3b8468166684b04c9ef8d50e588
@@@ -25,16 -25,16 +25,16 @@@ is efficient to access.  The packed arc
  designed to be unpackable without having anything else, but for
  random access, accompanied with the pack index file (.idx).
  
+ Placing both in the pack/ subdirectory of $GIT_OBJECT_DIRECTORY (or
+ any of the directories on $GIT_ALTERNATE_OBJECT_DIRECTORIES)
+ enables git to read from such an archive.
  'git-unpack-objects' command can read the packed archive and
  expand the objects contained in the pack into "one-file
  one-object" format; this is typically done by the smart-pull
  commands when a pack is created on-the-fly for efficient network
  transport by their peers.
  
- Placing both in the pack/ subdirectory of $GIT_OBJECT_DIRECTORY (or
- any of the directories on $GIT_ALTERNATE_OBJECT_DIRECTORIES)
- enables git to read from such an archive.
  In a packed archive, an object is either stored as a compressed
  whole, or as a difference from some other object.  The latter is
  often called a delta.
@@@ -169,14 -169,6 +169,14 @@@ base-name:
        length, this option typically shrinks the resulting
        packfile by 3-5 per-cent.
  
 +--threads=<n>::
 +      Specifies the number of threads to spawn when searching for best
 +      delta matches.  This requires that pack-objects be compiled with
 +      pthreads otherwise this option is ignored with a warning.
 +      This is meant to reduce packing time on multiprocessor machines.
 +      The required amount of memory for the delta search window is
 +      however multiplied by the number of threads.
 +
  --index-version=<version>[,<offset>]::
        This is intended to be used by the test suite only. It allows
        to force the version for the generated pack index, and to force
index 1dc606fbd3fd29f5f4c9928a2518df46109ef449,0000000000000000000000000000000000000000..bafeb52cd113ad8a07ffd1912191f2bc17a7ef7a
mode 100755,000000..100755
--- /dev/null
@@@ -1,106 -1,0 +1,106 @@@
- while case $# in 0) break ;; esac
 +#!/bin/sh
 +#
 +# Copyright (c) 2005, 2006 Linus Torvalds and Junio C Hamano
 +#
 +USAGE='[--mixed | --soft | --hard]  [<commit-ish>] [ [--] <paths>...]'
 +SUBDIRECTORY_OK=Yes
 +. git-sh-setup
 +set_reflog_action "reset $*"
 +require_work_tree
 +
 +update= reset_type=--mixed
 +unset rev
 +
++while test $# != 0
 +do
 +      case "$1" in
 +      --mixed | --soft | --hard)
 +              reset_type="$1"
 +              ;;
 +      --)
 +              break
 +              ;;
 +      -*)
 +              usage
 +              ;;
 +      *)
 +              rev=$(git rev-parse --verify "$1") || exit
 +              shift
 +              break
 +              ;;
 +      esac
 +      shift
 +done
 +
 +: ${rev=HEAD}
 +rev=$(git rev-parse --verify $rev^0) || exit
 +
 +# Skip -- in "git reset HEAD -- foo" and "git reset -- foo".
 +case "$1" in --) shift ;; esac
 +
 +# git reset --mixed tree [--] paths... can be used to
 +# load chosen paths from the tree into the index without
 +# affecting the working tree nor HEAD.
 +if test $# != 0
 +then
 +      test "$reset_type" = "--mixed" ||
 +              die "Cannot do partial $reset_type reset."
 +
 +      git diff-index --cached $rev -- "$@" |
 +      sed -e 's/^:\([0-7][0-7]*\) [0-7][0-7]* \([0-9a-f][0-9a-f]*\) [0-9a-f][0-9a-f]* [A-Z]   \(.*\)$/\1 \2   \3/' |
 +      git update-index --add --remove --index-info || exit
 +      git update-index --refresh
 +      exit
 +fi
 +
 +cd_to_toplevel
 +
 +if test "$reset_type" = "--hard"
 +then
 +      update=-u
 +fi
 +
 +# Soft reset does not touch the index file nor the working tree
 +# at all, but requires them in a good order.  Other resets reset
 +# the index file to the tree object we are switching to.
 +if test "$reset_type" = "--soft"
 +then
 +      if test -f "$GIT_DIR/MERGE_HEAD" ||
 +         test "" != "$(git ls-files --unmerged)"
 +      then
 +              die "Cannot do a soft reset in the middle of a merge."
 +      fi
 +else
 +      git read-tree -v --reset $update "$rev" || exit
 +fi
 +
 +# Any resets update HEAD to the head being switched to.
 +if orig=$(git rev-parse --verify HEAD 2>/dev/null)
 +then
 +      echo "$orig" >"$GIT_DIR/ORIG_HEAD"
 +else
 +      rm -f "$GIT_DIR/ORIG_HEAD"
 +fi
 +git update-ref -m "$GIT_REFLOG_ACTION" HEAD "$rev"
 +update_ref_status=$?
 +
 +case "$reset_type" in
 +--hard )
 +      test $update_ref_status = 0 && {
 +              printf "HEAD is now at "
 +              GIT_PAGER= git log --max-count=1 --pretty=oneline \
 +                      --abbrev-commit HEAD
 +      }
 +      ;;
 +--soft )
 +      ;; # Nothing else to do
 +--mixed )
 +      # Report what has not been updated.
 +      git update-index --refresh
 +      ;;
 +esac
 +
 +rm -f "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/rr-cache/MERGE_RR" \
 +      "$GIT_DIR/SQUASH_MSG" "$GIT_DIR/MERGE_MSG"
 +
 +exit $update_ref_status
index adaaae66335c5d500f7bf852e2f46931949726a7,65c57ac4d8247ec279e4f018d36ef93dcca78061..557649a14ad0e3a7ab4d0f1b9b128d1ba64d0757
@@@ -63,6 -63,14 +63,14 @@@ def system(cmd)
      if os.system(cmd) != 0:
          die("command failed: %s" % cmd)
  
+ def isP4Exec(kind):
+     """Determine if a Perforce 'kind' should have execute permission
+     'p4 help filetypes' gives a list of the types.  If it starts with 'x',
+     or x follows one of a few letters.  Otherwise, if there is an 'x' after
+     a plus sign, it is also executable"""
+     return (re.search(r"(^[cku]?x)|\+.*x", kind) != None)
  def p4CmdList(cmd, stdin=None, stdin_mode='w+b'):
      cmd = "p4 -G %s" % cmd
      if verbose:
@@@ -281,19 -289,6 +289,19 @@@ def createOrUpdateBranchesFromOrigin(lo
  def originP4BranchesExist():
          return gitBranchExists("origin") or gitBranchExists("origin/p4") or gitBranchExists("origin/p4/master")
  
 +def p4ChangesForPaths(depotPaths, changeRange):
 +    assert depotPaths
 +    output = read_pipe_lines("p4 changes " + ' '.join (["%s...%s" % (p, changeRange)
 +                                                        for p in depotPaths]))
 +
 +    changes = []
 +    for line in output:
 +        changeNum = line.split(" ")[1]
 +        changes.append(int(changeNum))
 +
 +    changes.sort()
 +    return changes
 +
  class Command:
      def __init__(self):
          self.usage = "usage: %prog [options]"
@@@ -677,8 -672,9 +685,8 @@@ class P4Submit(Command)
              f.close();
  
          os.chdir(self.clientPath)
 -        response = raw_input("Do you want to sync %s with p4 sync? [y]es/[n]o " % self.clientPath)
 -        if response == "y" or response == "yes":
 -            system("p4 sync ...")
 +        print "Syncronizing p4 checkout..."
 +        system("p4 sync ...")
  
          if self.reset:
              self.firstTime = True
              else:
                  print "All changes applied!"
                  os.chdir(self.oldWorkingDirectory)
 -                response = raw_input("Do you want to sync from Perforce now using git-p4 rebase? [y]es/[n]o ")
 +
 +                sync = P4Sync()
 +                sync.run([])
 +
 +                response = raw_input("Do you want to rebase current HEAD from Perforce now using git-p4 rebase? [y]es/[n]o ")
                  if response == "y" or response == "yes":
                      rebase = P4Rebase()
 -                    rebase.run([])
 +                    rebase.rebase()
              os.remove(self.configFile)
  
          return True
@@@ -932,7 -924,7 +940,7 @@@ class P4Sync(Command)
                  data = file['data']
  
                  mode = "644"
-                 if file["type"].startswith("x"):
+                 if isP4Exec(file["type"]):
                      mode = "755"
                  elif file["type"] == "symlink":
                      mode = "120000"
          self.keepRepoPath = (d.has_key('options')
                               and ('keepRepoPath' in d['options']))
  
 +    def gitRefForBranch(self, branch):
 +        if branch == "main":
 +            return self.refPrefix + "master"
 +
 +        if len(branch) <= 0:
 +            return branch
 +
 +        return self.refPrefix + self.projectName + branch
 +
 +    def gitCommitByP4Change(self, ref, change):
 +        if self.verbose:
 +            print "looking in ref " + ref + " for change %s using bisect..." % change
 +
 +        earliestCommit = ""
 +        latestCommit = parseRevision(ref)
 +
 +        while True:
 +            if self.verbose:
 +                print "trying: earliest %s latest %s" % (earliestCommit, latestCommit)
 +            next = read_pipe("git rev-list --bisect %s %s" % (latestCommit, earliestCommit)).strip()
 +            if len(next) == 0:
 +                if self.verbose:
 +                    print "argh"
 +                return ""
 +            log = extractLogMessageFromGitCommit(next)
 +            settings = extractSettingsGitLog(log)
 +            currentChange = int(settings['change'])
 +            if self.verbose:
 +                print "current change %s" % currentChange
 +
 +            if currentChange == change:
 +                if self.verbose:
 +                    print "found %s" % next
 +                return next
 +
 +            if currentChange < change:
 +                earliestCommit = "^%s" % next
 +            else:
 +                latestCommit = "%s" % next
 +
 +        return ""
 +
 +    def importNewBranch(self, branch, maxChange):
 +        # make fast-import flush all changes to disk and update the refs using the checkpoint
 +        # command so that we can try to find the branch parent in the git history
 +        self.gitStream.write("checkpoint\n\n");
 +        self.gitStream.flush();
 +        branchPrefix = self.depotPaths[0] + branch + "/"
 +        range = "@1,%s" % maxChange
 +        #print "prefix" + branchPrefix
 +        changes = p4ChangesForPaths([branchPrefix], range)
 +        if len(changes) <= 0:
 +            return False
 +        firstChange = changes[0]
 +        #print "first change in branch: %s" % firstChange
 +        sourceBranch = self.knownBranches[branch]
 +        sourceDepotPath = self.depotPaths[0] + sourceBranch
 +        sourceRef = self.gitRefForBranch(sourceBranch)
 +        #print "source " + sourceBranch
 +
 +        branchParentChange = int(p4Cmd("changes -m 1 %s...@1,%s" % (sourceDepotPath, firstChange))["change"])
 +        #print "branch parent: %s" % branchParentChange
 +        gitParent = self.gitCommitByP4Change(sourceRef, branchParentChange)
 +        if len(gitParent) > 0:
 +            self.initialParents[self.gitRefForBranch(branch)] = gitParent
 +            #print "parent git commit: %s" % gitParent
 +
 +        self.importChanges(changes)
 +        return True
 +
 +    def importChanges(self, changes):
 +        cnt = 1
 +        for change in changes:
 +            description = p4Cmd("describe %s" % change)
 +            self.updateOptionDict(description)
 +
 +            if not self.silent:
 +                sys.stdout.write("\rImporting revision %s (%s%%)" % (change, cnt * 100 / len(changes)))
 +                sys.stdout.flush()
 +            cnt = cnt + 1
 +
 +            try:
 +                if self.detectBranches:
 +                    branches = self.splitFilesIntoBranches(description)
 +                    for branch in branches.keys():
 +                        ## HACK  --hwn
 +                        branchPrefix = self.depotPaths[0] + branch + "/"
 +
 +                        parent = ""
 +
 +                        filesForCommit = branches[branch]
 +
 +                        if self.verbose:
 +                            print "branch is %s" % branch
 +
 +                        self.updatedBranches.add(branch)
 +
 +                        if branch not in self.createdBranches:
 +                            self.createdBranches.add(branch)
 +                            parent = self.knownBranches[branch]
 +                            if parent == branch:
 +                                parent = ""
 +                            else:
 +                                fullBranch = self.projectName + branch
 +                                if fullBranch not in self.p4BranchesInGit:
 +                                    if not self.silent:
 +                                        print("\n    Importing new branch %s" % fullBranch);
 +                                    if self.importNewBranch(branch, change - 1):
 +                                        parent = ""
 +                                        self.p4BranchesInGit.append(fullBranch)
 +                                    if not self.silent:
 +                                        print("\n    Resuming with change %s" % change);
 +
 +                                if self.verbose:
 +                                    print "parent determined through known branches: %s" % parent
 +
 +                        branch = self.gitRefForBranch(branch)
 +                        parent = self.gitRefForBranch(parent)
 +
 +                        if self.verbose:
 +                            print "looking for initial parent for %s; current parent is %s" % (branch, parent)
 +
 +                        if len(parent) == 0 and branch in self.initialParents:
 +                            parent = self.initialParents[branch]
 +                            del self.initialParents[branch]
 +
 +                        self.commit(description, filesForCommit, branch, [branchPrefix], parent)
 +                else:
 +                    files = self.extractFilesFromCommit(description)
 +                    self.commit(description, files, self.branch, self.depotPaths,
 +                                self.initialParent)
 +                    self.initialParent = ""
 +            except IOError:
 +                print self.gitError.read()
 +                sys.exit(1)
 +
 +    def importHeadRevision(self, revision):
 +        print "Doing initial import of %s from revision %s into %s" % (' '.join(self.depotPaths), revision, self.branch)
 +
 +        details = { "user" : "git perforce import user", "time" : int(time.time()) }
 +        details["desc"] = ("Initial import of %s from the state at revision %s"
 +                           % (' '.join(self.depotPaths), revision))
 +        details["change"] = revision
 +        newestRevision = 0
 +
 +        fileCnt = 0
 +        for info in p4CmdList("files "
 +                              +  ' '.join(["%s...%s"
 +                                           % (p, revision)
 +                                           for p in self.depotPaths])):
 +
 +            if info['code'] == 'error':
 +                sys.stderr.write("p4 returned an error: %s\n"
 +                                 % info['data'])
 +                sys.exit(1)
 +
 +
 +            change = int(info["change"])
 +            if change > newestRevision:
 +                newestRevision = change
 +
 +            if info["action"] == "delete":
 +                # don't increase the file cnt, otherwise details["depotFile123"] will have gaps!
 +                #fileCnt = fileCnt + 1
 +                continue
 +
 +            for prop in ["depotFile", "rev", "action", "type" ]:
 +                details["%s%s" % (prop, fileCnt)] = info[prop]
 +
 +            fileCnt = fileCnt + 1
 +
 +        details["change"] = newestRevision
 +        self.updateOptionDict(details)
 +        try:
 +            self.commit(details, self.extractFilesFromCommit(details), self.branch, self.depotPaths)
 +        except IOError:
 +            print "IO error with git fast-import. Is your git version recent enough?"
 +            print self.gitError.read()
 +
 +
      def run(self, args):
          self.depotPaths = []
          self.changeRange = ""
  
              self.depotPaths = sorted(args)
  
 -        self.revision = ""
 +        revision = ""
          self.users = {}
  
          newPaths = []
                  if self.changeRange == "@all":
                      self.changeRange = ""
                  elif ',' not in self.changeRange:
 -                    self.revision = self.changeRange
 +                    revision = self.changeRange
                      self.changeRange = ""
                  p = p[:atIdx]
              elif p.find("#") != -1:
                  hashIdx = p.index("#")
 -                self.revision = p[hashIdx:]
 +                revision = p[hashIdx:]
                  p = p[:hashIdx]
              elif self.previousDepotPaths == []:
 -                self.revision = "#head"
 +                revision = "#head"
  
              p = re.sub ("\.\.\.$", "", p)
              if not p.endswith("/"):
          self.gitStream = importProcess.stdin
          self.gitError = importProcess.stderr
  
 -        if self.revision:
 -            print "Doing initial import of %s from revision %s into %s" % (' '.join(self.depotPaths), self.revision, self.branch)
 -
 -            details = { "user" : "git perforce import user", "time" : int(time.time()) }
 -            details["desc"] = ("Initial import of %s from the state at revision %s"
 -                               % (' '.join(self.depotPaths), self.revision))
 -            details["change"] = self.revision
 -            newestRevision = 0
 -
 -            fileCnt = 0
 -            for info in p4CmdList("files "
 -                                  +  ' '.join(["%s...%s"
 -                                               % (p, self.revision)
 -                                               for p in self.depotPaths])):
 -
 -                if info['code'] == 'error':
 -                    sys.stderr.write("p4 returned an error: %s\n"
 -                                     % info['data'])
 -                    sys.exit(1)
 -
 -
 -                change = int(info["change"])
 -                if change > newestRevision:
 -                    newestRevision = change
 -
 -                if info["action"] == "delete":
 -                    # don't increase the file cnt, otherwise details["depotFile123"] will have gaps!
 -                    #fileCnt = fileCnt + 1
 -                    continue
 -
 -                for prop in ["depotFile", "rev", "action", "type" ]:
 -                    details["%s%s" % (prop, fileCnt)] = info[prop]
 -
 -                fileCnt = fileCnt + 1
 -
 -            details["change"] = newestRevision
 -            self.updateOptionDict(details)
 -            try:
 -                self.commit(details, self.extractFilesFromCommit(details), self.branch, self.depotPaths)
 -            except IOError:
 -                print "IO error with git fast-import. Is your git version recent enough?"
 -                print self.gitError.read()
 -
 +        if revision:
 +            self.importHeadRevision(revision)
          else:
              changes = []
  
                  if self.verbose:
                      print "Getting p4 changes for %s...%s" % (', '.join(self.depotPaths),
                                                                self.changeRange)
 -                assert self.depotPaths
 -                output = read_pipe_lines("p4 changes " + ' '.join (["%s...%s" % (p, self.changeRange)
 -                                                                    for p in self.depotPaths]))
 -
 -                for line in output:
 -                    changeNum = line.split(" ")[1]
 -                    changes.append(int(changeNum))
 -
 -                changes.sort()
 +                changes = p4ChangesForPaths(self.depotPaths, self.changeRange)
  
                  if len(self.maxChanges) > 0:
                      changes = changes[:min(int(self.maxChanges), len(changes))]
  
              self.updatedBranches = set()
  
 -            cnt = 1
 -            for change in changes:
 -                description = p4Cmd("describe %s" % change)
 -                self.updateOptionDict(description)
 -
 -                if not self.silent:
 -                    sys.stdout.write("\rImporting revision %s (%s%%)" % (change, cnt * 100 / len(changes)))
 -                    sys.stdout.flush()
 -                cnt = cnt + 1
 -
 -                try:
 -                    if self.detectBranches:
 -                        branches = self.splitFilesIntoBranches(description)
 -                        for branch in branches.keys():
 -                            ## HACK  --hwn
 -                            branchPrefix = self.depotPaths[0] + branch + "/"
 -
 -                            parent = ""
 -
 -                            filesForCommit = branches[branch]
 -
 -                            if self.verbose:
 -                                print "branch is %s" % branch
 -
 -                            self.updatedBranches.add(branch)
 -
 -                            if branch not in self.createdBranches:
 -                                self.createdBranches.add(branch)
 -                                parent = self.knownBranches[branch]
 -                                if parent == branch:
 -                                    parent = ""
 -                                elif self.verbose:
 -                                    print "parent determined through known branches: %s" % parent
 -
 -                            # main branch? use master
 -                            if branch == "main":
 -                                branch = "master"
 -                            else:
 -
 -                                ## FIXME
 -                                branch = self.projectName + branch
 -
 -                            if parent == "main":
 -                                parent = "master"
 -                            elif len(parent) > 0:
 -                                ## FIXME
 -                                parent = self.projectName + parent
 -
 -                            branch = self.refPrefix + branch
 -                            if len(parent) > 0:
 -                                parent = self.refPrefix + parent
 -
 -                            if self.verbose:
 -                                print "looking for initial parent for %s; current parent is %s" % (branch, parent)
 -
 -                            if len(parent) == 0 and branch in self.initialParents:
 -                                parent = self.initialParents[branch]
 -                                del self.initialParents[branch]
 -
 -                            self.commit(description, filesForCommit, branch, [branchPrefix], parent)
 -                    else:
 -                        files = self.extractFilesFromCommit(description)
 -                        self.commit(description, files, self.branch, self.depotPaths,
 -                                    self.initialParent)
 -                        self.initialParent = ""
 -                except IOError:
 -                    print self.gitError.read()
 -                    sys.exit(1)
 +            self.importChanges(changes)
  
              if not self.silent:
                  print ""
                          sys.stdout.write("%s " % b)
                      sys.stdout.write("\n")
  
 -
          self.gitStream.close()
          if importProcess.wait() != 0:
              die("fast-import failed: %s" % self.gitError.read())
@@@ -1519,9 -1448,6 +1527,9 @@@ class P4Rebase(Command)
          sync = P4Sync()
          sync.run([])
  
 +        return self.rebase()
 +
 +    def rebase(self):
          [upstream, settings] = findUpstreamBranchPoint()
          if len(upstream) == 0:
              die("Cannot find upstream branchpoint for rebase")
diff --combined git-commit.sh
index 3e46dbba7428f849fe30a639864955d92d87ef32,7a7a2cb4b47c62d4826aabd9d90a7af26427f980..cb14f0621651d2006b08d1eddf67ab3269df84d0
@@@ -89,7 -89,7 +89,7 @@@ force_author
  only_include_assumed=
  untracked_files=
  templatefile="`git config commit.template`"
- while case "$#" in 0) break;; esac
+ while test $# != 0
  do
        case "$1" in
        -F|--F|-f|--f|--fi|--fil|--file)
                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
 +              logfile="${1#-[Ff]}"
                ;;
        --F=*|--f=*|--fi=*|--fil=*|--file=*)
                no_edit=t
                log_given=t$log_given
 -              logfile=`expr "z$1" : 'z-[^=]*=\(.*\)'`
 -              shift
 +              logfile="${1#*=}"
                ;;
        -a|--a|--al|--all)
                all=t
 -              shift
                ;;
        --au=*|--aut=*|--auth=*|--autho=*|--author=*)
 -              force_author=`expr "z$1" : 'z-[^=]*=\(.*\)'`
 -              shift
 +              force_author="${1#*=}"
                ;;
        --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
                ;;
        --int|--inte|--inter|--intera|--interac|--interact|--interacti|\
        --interactiv|--interactive)
                interactive=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
 +              log_message="${log_message:+${log_message}
  
 -$1"
 -              fi
 +}$1"
                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
 +              log_message="${log_message:+${log_message}
  
 -`expr "z$1" : 'z-m\(.*\)'`"
 -              fi
 +}${1#-m}"
                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
 +              log_message="${log_message:+${log_message}
  
 -`expr "z$1" : 'zq-[^=]*=\(.*\)'`"
 -              fi
 +}${1#*=}"
                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
                use_commit=HEAD
 -              shift
                ;;
        -c)
                case "$#" in 1) usage ;; esac
                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-[^=]*=\(.*\)'`
 +              use_commit="${1#*=}"
                no_edit=
 -              shift
                ;;
        --ree|--reed|--reedi|--reedit|--reedit-|--reedit-m|--reedit-me|\
        --reedit-mes|--reedit-mess|--reedit-messa|--reedit-messag|\
                log_given=t$log_given
                use_commit="$1"
                no_edit=
 -              shift
                ;;
        -C)
                case "$#" in 1) usage ;; esac
                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-[^=]*=\(.*\)'`
 +              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="$1"
                no_edit=t
 -              shift
                ;;
        -s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
                signoff=t
 -              shift
                ;;
        -t|--t|--te|--tem|--temp|--templ|--templa|--templat|--template)
                case "$#" in 1) usage ;; esac
                shift
                templatefile="$1"
                no_edit=
 -              shift
                ;;
        -q|--q|--qu|--qui|--quie|--quiet)
                quiet=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
                ;;
        esac
 +      shift
  done
  case "$edit_flag" in t) no_edit= ;; esac
  
@@@ -401,8 -441,12 +401,8 @@@ esa
  
  if test t = "$verify" && test -x "$GIT_DIR"/hooks/pre-commit
  then
 -      if test "$TMP_INDEX"
 -      then
 -              GIT_INDEX_FILE="$TMP_INDEX" "$GIT_DIR"/hooks/pre-commit
 -      else
 -              GIT_INDEX_FILE="$USE_INDEX" "$GIT_DIR"/hooks/pre-commit
 -      fi || exit
 +    GIT_INDEX_FILE="${TMP_INDEX:-${USE_INDEX}}" "$GIT_DIR"/hooks/pre-commit \
 +    || exit
  fi
  
  if test "$log_message" != ''
diff --combined git-rebase.sh
index c9942f24009bd01ee0fee8990f64e64d9e43364c,058fcacb7eea33128436fa04c0412370562e9ff0..1583402a060793c25e49c3446c2a35fe27101883
@@@ -122,15 -122,14 +122,14 @@@ finish_rb_merge () 
  
  is_interactive () {
        test -f "$dotest"/interactive ||
-       while case $#,"$1" in 0,|*,-i|*,--interactive) break ;; esac
-       do
+       while :; do case $#,"$1" in 0,|*,-i|*,--interactive) break ;; esac
                shift
        done && test -n "$1"
  }
  
  is_interactive "$@" && exec git-rebase--interactive "$@"
  
- while case "$#" in 0) break ;; esac
+ while test $# != 0
  do
        case "$1" in
        --continue)
        -v|--verbose)
                verbose=t
                ;;
 +      --whitespace=*)
 +              git_am_opt="$git_am_opt $1"
 +              ;;
        -C*)
 -              git_am_opt=$1
 -              shift
 +              git_am_opt="$git_am_opt $1"
                ;;
        -*)
                usage
diff --combined git-svn.perl
index 288d32cb160fcf1b7fdb8bbce9d800d971ced345,c015ea8580e8e19dc27a0f66af38995335df8c82..484b0576a8cdea3b0d2063ce73c8b8cb11a18f7c
@@@ -124,8 -124,7 +124,8 @@@ my %cmd = 
                        "Set an SVN repository to a git tree-ish",
                        { 'stdin|' => \$_stdin, %cmt_opts, %fc_opts, } ],
        'show-ignore' => [ \&cmd_show_ignore, "Show svn:ignore listings",
 -                      { 'revision|r=i' => \$_revision } ],
 +                      { 'revision|r=i' => \$_revision
 +                      } ],
        'multi-fetch' => [ \&cmd_multi_fetch,
                           "Deprecated alias for $0 fetch --all",
                           { 'revision|r=s' => \$_revision, %fc_opts } ],
                          'non-recursive' => \$Git::SVN::Log::non_recursive,
                          'authors-file|A=s' => \$_authors,
                          'color' => \$Git::SVN::Log::color,
 -                        'pager=s' => \$Git::SVN::Log::pager,
 +                        'pager=s' => \$Git::SVN::Log::pager
                        } ],
        'find-rev' => [ \&cmd_find_rev, "Translate between SVN revision numbers and tree-ish",
 -                      { } ],
 +                      {} ],
        'rebase' => [ \&cmd_rebase, "Fetch and rebase your working directory",
                        { 'merge|m|M' => \$_merge,
                          'verbose|v' => \$_verbose,
@@@ -812,8 -811,7 +812,8 @@@ sub cmt_metadata 
  
  sub working_head_info {
        my ($head, $refs) = @_;
 -      my ($fh, $ctx) = command_output_pipe('log', '--no-color', $head);
 +      my @args = ('log', '--no-color', '--first-parent');
 +      my ($fh, $ctx) = command_output_pipe(@args, $head);
        my $hash;
        my %max;
        while (<$fh>) {
@@@ -3578,7 -3576,7 +3578,7 @@@ sub config_pager 
  }
  
  sub run_pager {
-       return unless -t *STDOUT;
+       return unless -t *STDOUT && defined $pager;
        pipe my $rfd, my $wfd or return;
        defined(my $pid = fork) or ::fatal "Can't fork: $!\n";
        if (!$pid) {