---
 Makefile                                |   2 +-
 builtin.h                               |   1 +
 builtin/rebase.c (new)                  | 752 ++++++++++++++++++++++++++++++++
 commit.c                                |   4 +-
 commit.h                                |   4 +-
 contrib/examples/git-rebase.sh (new +x) | 532 ++++++++++++++++++++++
 git-rebase.sh (gone)                    | 532 ----------------------
 git.c                                   |   1 +
 8 files changed, 1291 insertions(+), 537 deletions(-)
 create mode 100644 builtin/rebase.c
 create mode 100755 contrib/examples/git-rebase.sh
 delete mode 100755 git-rebase.sh

diff --git a/Makefile b/Makefile
index 83972a2..223d50b 100644
--- a/Makefile
+++ b/Makefile
@@ -444,7 +444,6 @@ SCRIPT_SH += git-merge-resolve.sh
 SCRIPT_SH += git-mergetool.sh
 SCRIPT_SH += git-pull.sh
 SCRIPT_SH += git-quiltimport.sh
-SCRIPT_SH += git-rebase.sh
 SCRIPT_SH += git-rebase--am.sh
 SCRIPT_SH += git-rebase--interactive.sh
 SCRIPT_SH += git-rebase--merge.sh
@@ -903,6 +902,7 @@ BUILTIN_OBJS += builtin/prune-packed.o
 BUILTIN_OBJS += builtin/prune.o
 BUILTIN_OBJS += builtin/push.o
 BUILTIN_OBJS += builtin/read-tree.o
+BUILTIN_OBJS += builtin/rebase.o
 BUILTIN_OBJS += builtin/receive-pack.o
 BUILTIN_OBJS += builtin/reflog.o
 BUILTIN_OBJS += builtin/remote.o
diff --git a/builtin.h b/builtin.h
index 7e7bbd6..431bbbf 100644
--- a/builtin.h
+++ b/builtin.h
@@ -108,6 +108,7 @@ extern int cmd_prune(int argc, const char **argv, const 
char *prefix);
 extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);
 extern int cmd_push(int argc, const char **argv, const char *prefix);
 extern int cmd_read_tree(int argc, const char **argv, const char *prefix);
+extern int cmd_rebase(int argc, const char **argv, const char *prefix);
 extern int cmd_receive_pack(int argc, const char **argv, const char *prefix);
 extern int cmd_reflog(int argc, const char **argv, const char *prefix);
 extern int cmd_remote(int argc, const char **argv, const char *prefix);
diff --git a/builtin/rebase.c b/builtin/rebase.c
new file mode 100644
index 0000000..29eff0e
--- /dev/null
+++ b/builtin/rebase.c
@@ -0,0 +1,752 @@
+#include "cache.h"
+#include "parse-options.h"
+#include "argv-array.h"
+#include "run-command.h"
+#include "tree-walk.h"
+#include "unpack-trees.h"
+#include "diff.h"
+#include "commit.h"
+#include "revision.h"
+#include "submodule.h"
+#include "commit.h"
+#include "dir.h"
+
+#define REBASE_AM              1
+#define REBASE_MERGE           2
+#define REBASE_INTERACTIVE     3
+
+static const char * const builtin_rebase_usage[] = {
+       N_("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] 
[<upstream>] [<branch>]"),
+       N_("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] --root 
[<branch>]"),
+       N_("git rebase --continue | --abort | --skip | --edit-todo"),
+       NULL
+};
+
+/* These are exported as environment variables for git-rebase--*.sh */
+static int action_abort;
+static int action_continue;
+static int action_skip;
+static int autosquash;
+static int force_rebase;
+static int keep_empty;
+static int preserve_merges;
+static int quiet;
+static int rerere_autoupdate;
+static int root;
+static int verbose;
+static const char *exec_cmd;
+static const char *head_name;
+static const char *onto;
+static const char *orig_head;
+static struct strbuf revisions = STRBUF_INIT;
+static const char *state_basedir;
+static const char *strategy;
+static const char *strategy_opts;
+static const char *switch_to;
+static const char *squash_onto;
+
+static int do_merge;
+static int edit_todo;
+static int interactive_rebase;
+static int rebase_type;
+static int show_stat;
+
+static char *read_file(const char *name)
+{
+       struct strbuf sb = STRBUF_INIT;
+       if (strbuf_read_file(&sb,
+                            git_path("%s/%s", state_basedir, name),
+                            0) >= 0)
+               return strbuf_detach(&sb, NULL);
+       else
+               return NULL;
+}
+
+static char *read_file_or_die(const char *name)
+{
+       struct strbuf sb = STRBUF_INIT;
+       strbuf_read_file_or_die(&sb,
+                               git_path("%s/%s", state_basedir, name),
+                               0);
+       return strbuf_detach(&sb, NULL);
+}
+
+static void read_bool(const char *name, int *var)
+{
+       char *buf = read_file(name);
+       if (buf) {
+               *var = buf[0] && !isspace(buf[0]);
+               free(buf);
+       }
+}
+
+static int read_bool_or_die(const char *name)
+{
+       char *buf = read_file_or_die(name);
+       int ret = buf[0] && !isspace(buf[0]);
+       free(buf);
+       return ret;
+}
+
+/*
+ * Note:
+ *
+ * After git-rebase--*.sh are integrated, we should probably adopt
+ * git-config format and store everything in one file instead of so
+ * many like this. state_dir will be something different to avoid
+ * misuse by old rebase versions. This code will stay for a few major
+ * releases before being phased out.
+ */
+static void read_basic_state()
+{
+       head_name = read_file_or_die("head-name");
+       onto = read_file_or_die("onto");
+       /*
+        * We always write to orig-head, but interactive rebase used
+        * to write to head. Fall back to reading from head to cover
+        * for the case that the user upgraded git with an ongoing
+        * interactive rebase.
+        */
+       if ((orig_head = read_file("orig-head")) == NULL)
+               orig_head = read_file_or_die("head");
+       quiet = read_bool_or_die("quiet");
+       read_bool("verbose", &verbose);
+       strategy = read_file("strategy");
+       strategy_opts = read_file("strategy_opts");
+       read_bool("allow_rerere_autoupdate", &rerere_autoupdate);
+}
+
+static void push_env_string(struct argv_array *argv,
+                           const char *name,
+                           const char *value)
+{
+       struct strbuf sb = STRBUF_INIT;
+       strbuf_addf(&sb, "%s=%s", name, value);
+       argv_array_push(argv, sb.buf);
+       strbuf_release(&sb);
+}
+
+static void push_env_bool(struct argv_array *argv,
+                         const char *name,
+                         int value)
+{
+       struct strbuf sb = STRBUF_INIT;
+       strbuf_addf(&sb, "%s=%s", name, value ? "t" : "");
+       argv_array_push(argv, sb.buf);
+       strbuf_release(&sb);
+}
+
+static int run_specific_rebase()
+{
+       struct child_process cmd;
+       struct argv_array env = ARGV_ARRAY_INIT;
+       const char *argv[2];
+       int ret;
+
+       if (interactive_rebase == -1) {
+               argv_array_push(&env, "GIT_EDITOR=:");
+               autosquash = 0;
+       }
+       push_env_bool(&env, "git_quiet", quiet);
+       if (action_continue)
+               argv_array_push(&env, "action=continue");
+       else if (action_skip)
+               argv_array_push(&env, "action=skip");
+       else if (action_abort)
+               argv_array_push(&env, "action=abort");
+       else if (edit_todo)
+               argv_array_push(&env, "action=edit-todo");
+       else
+               argv_array_push(&env, "action=");
+       push_env_bool(&env,   "allow_rerere_autoupdate", rerere_autoupdate);
+       push_env_bool(&env,   "autosquash",              autosquash);
+       push_env_string(&env, "cmd",                     exec_cmd);
+       push_env_bool(&env,   "force_rebase",            force_rebase);
+       push_env_string(&env, "git_am_opt", ""/* git_am_opt */);
+       push_env_string(&env, "head_name",               head_name);
+       push_env_bool(&env,   "keep_empty",              keep_empty);
+       push_env_string(&env, "onto",                    onto);
+       push_env_string(&env, "orig_head",               orig_head);
+       push_env_bool(&env,   "preserve_merges",         preserve_merges);
+       push_env_bool(&env,   "rebase_root",             root);
+       push_env_string(&env, "revisions",               revisions.buf);
+       push_env_string(&env, "squash_onto",             squash_onto);
+       push_env_string(&env, "state_dir", git_path("%s", state_basedir));
+       push_env_string(&env, "strategy", strategy);
+       push_env_string(&env, "strategy_opts", strategy_opts);
+       push_env_string(&env, "switch_to", switch_to);
+       /* upstream */
+       push_env_bool(&env, "verbose", verbose);
+
+       switch (rebase_type) {
+       case REBASE_INTERACTIVE: argv[0] = "rebase--interactive"; break;
+       case REBASE_AM:          argv[0] = "rebase--am";          break;
+       case REBASE_MERGE:       argv[0] = "rebase--merge";       break;
+       default:
+               die("BUG: unsupported rebase type %d", rebase_type);
+       }
+       argv[1] = NULL;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.in  = 0;
+       cmd.out = 1;
+       cmd.err = 2;
+       cmd.git_cmd = 1;
+       cmd.env = env.argv;
+       cmd.argv = argv;
+       ret = run_command(&cmd);
+       if (ret)
+               die_errno("failed to run %s", argv[0]);
+
+       argv_array_clear(&env);
+       return ret;
+}
+
+static int do_continue()
+{
+       unsigned char sha1[20];
+       if (get_sha1("HEAD", sha1))
+               die(_("Cannot read HEAD"));
+       if (read_cache_unmerged()) {
+               printf(_("You must edit all merge conflicts and then\n"
+                        "mark them as resolved using 'git add'\n"));
+               return 1;
+       }
+       read_basic_state();
+       return run_specific_rebase();
+}
+
+static int do_skip()
+{
+       int ret, error = 0;
+       unsigned char sha1[20];
+       if (get_sha1("HEAD", sha1))
+               die(_("Cannot read HEAD"));
+
+       ret = reset_tree(lookup_commit(sha1)->tree, quiet, 1, &error);
+       if (ret)
+               return ret;
+       read_basic_state();
+       return run_specific_rebase();
+}
+
+static int do_abort()
+{
+       int ret, error = 0;
+       unsigned char sha1[20];
+       const char *rerere[] = { "rerere", "clear", NULL };
+       struct strbuf path = STRBUF_INIT;
+
+       ret = run_command_v_opt(rerere, RUN_GIT_CMD);
+       if (ret)
+               return ret;
+       read_basic_state();
+       if (!prefixcmp(head_name, "refs/"))
+               create_symref("HEAD", head_name, "rebase: aborting");
+
+       if (get_sha1(orig_head, sha1))
+               die(_("Cannot read %s"), orig_head);
+
+       ret = reset_tree(lookup_commit(sha1)->tree, quiet, 1, &error);
+       if (ret)
+               return ret;
+
+       strbuf_addstr(&path, git_path("%s", state_basedir));
+       remove_dir_recursively(&path, 0);
+       strbuf_release(&path);
+       return 0;
+}
+
+static int do_edit_todo()
+{
+       if (rebase_type != REBASE_INTERACTIVE)
+               die(_("The --edit-todo action can only be "
+                     "used during interactive rebase."));
+       return run_specific_rebase();
+}
+
+static void error_on_missing_default_upstream()
+{
+       unsigned char sha1[20];
+       const char *head = resolve_ref_unsafe("HEAD", sha1, 0, NULL);
+       if (!head)
+               die(_("Failed to resolve HEAD as a valid ref."));
+       if (!strcmp(head, "HEAD")) {
+               printf(_("You are not currently on a branch. Please specify 
which\n"
+                        "branch you want to rebase against. See git-rebase(1) 
for details.\n"
+                        "\n"
+                        "    git rebase <branch>\n"));
+               return;
+       }
+
+       if (!prefixcmp(head, "refs/heads/"))
+               head += strlen("refs/heads/");
+       printf(_("There is no tracking information for the current branch.\n"
+                "Please specify which branch you want to rebase against.\n"
+                "See git-rebase(1) for details\n"
+                "\n"
+                "    git rebase <branch>\n"
+                "\n"
+                "If you wish to set tracking information for this branch you 
can do so with:\n"
+                "\n"
+                "    git branch --set-upstream-to=$remote/<branch> %s\n"),
+              head);
+}
+
+static int determine_upstream(int argc, const char **argv,
+                             const struct option *options,
+                             const char **upstream_name,
+                             const char **upstream_arg)
+{
+       int consumed = 0;
+       if (!root) {
+               unsigned char sha1[20];
+               if (argc) {
+                       *upstream_name = argv[0];
+                       argv++;
+                       argc--;
+                       consumed++;
+               } else {
+                       *upstream_name = "@{upstream}";
+                       if (get_sha1(*upstream_name, sha1)) {
+                               error_on_missing_default_upstream();
+                               exit(1);
+                       }
+               }
+               if (get_sha1(*upstream_name, sha1))
+                       die(_("Failed to resolve %s."), *upstream_name);
+               lookup_commit_or_die(sha1, *upstream_name);
+               *upstream_arg = *upstream_name;
+               return consumed;
+       }
+
+       if (!onto) {
+               unsigned char sha1[20];
+               struct strbuf sb = STRBUF_INIT;
+               if (commit_tree(&sb, EMPTY_TREE_SHA1_BIN, NULL, sha1, NULL, 
NULL))
+                       die(_("failed to create empty-tree commit"));
+               onto = xstrdup(sha1_to_hex(sha1));
+               squash_onto = onto;
+       }
+       if (argc > 1)
+               usage_with_options(builtin_rebase_usage,
+                                  options);
+       *upstream_arg = "--root";
+       return consumed;
+}
+
+static void require_clean_work_tree()
+{
+       struct rev_info rev;
+       unsigned char sha1[20];
+       int err = 0;
+
+       if (get_sha1("HEAD", sha1))
+               die("HEAD is not a valid ref");
+
+       if (read_cache() < 0)
+               die(_("unable to read index file"));
+       refresh_cache(REFRESH_QUIET | REFRESH_IGNORE_SUBMODULES);
+
+       init_revisions(&rev, NULL);
+       DIFF_OPT_SET(&rev.diffopt, QUICK);
+       DIFF_OPT_SET(&rev.diffopt, OVERRIDE_SUBMODULE_CONFIG);
+       handle_ignore_submodules_arg(&rev.diffopt, "all");
+       diff_setup_done(&rev.diffopt);
+       run_diff_files(&rev, 0);
+       if (DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES)) {
+               fputs(_("Cannot rebase: You have unstaged changes.\n"), stderr);
+               err = 1;
+       }
+
+       init_revisions(&rev, NULL);
+       DIFF_OPT_SET(&rev.diffopt, QUICK);
+       DIFF_OPT_SET(&rev.diffopt, OVERRIDE_SUBMODULE_CONFIG);
+       handle_ignore_submodules_arg(&rev.diffopt, "all");
+       diff_setup_done(&rev.diffopt);
+       add_head_to_pending(&rev);
+       run_diff_index(&rev, 1);
+       if (DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES)) {
+               const char *msg = err ?
+                       _("Additionally, your index contains uncommitted 
changes.\n") :
+                       _("Cannot rebase: Your index contains uncommitted 
changes.\n");
+               fputs(msg, stderr);
+               err = 1;
+       }
+
+       if (err) {
+               fputs(_("Please commit or stash them.\n"), stderr);
+               exit(1);
+       }
+}
+
+static void run_pre_rebase_hook(int argc, const char **argv,
+                               const char *upstream_arg)
+{
+       /*
+       if test -z "$ok_to_skip_pre_rebase" &&
+          test -x "$GIT_DIR/hooks/pre-rebase"
+       then
+               "$GIT_DIR/hooks/pre-rebase" ${1+"$@"} ||
+               die "$(gettext "The pre-rebase hook refused to rebase.")"
+       fi
+        */
+}
+
+static int do_rebase(int argc, const char **argv,
+                    const struct option *options)
+{
+       const char *upstream_name = NULL;
+       const char *upstream_arg = NULL;
+       const char *branch_name;
+       const char *onto_name;
+       unsigned char onto_sha1[20];
+
+       int n;
+       if (root && !onto && !interactive_rebase)
+               interactive_rebase = -1; /* implied */
+
+       if (interactive_rebase) {
+               rebase_type = REBASE_INTERACTIVE;
+               state_basedir = "rebase-merge";
+       } else if (do_merge) {
+               rebase_type = REBASE_MERGE;
+               state_basedir = "rebase-merge";
+       } else {
+               rebase_type = REBASE_AM;
+               state_basedir = "rebase-apply";
+       }
+
+       n = determine_upstream(argc, argv, options,
+                              &upstream_name, &upstream_arg);
+       argc += n;
+       argv += n;
+
+       if (root)
+               upstream_arg = "--root";
+
+       /* Make sure the branch to rebase onto is valid. */
+       onto_name = onto ? onto : upstream_name;
+       if (strstr(onto, "...")) {
+               /*
+case "$onto_name" in
+*...*)
+       if      left=${onto_name%...*} right=${onto_name#*...} &&
+               onto=$(git merge-base --all ${left:-HEAD} ${right:-HEAD})
+       then
+               case "$onto" in
+               ?*"$LF"?*)
+                       die "$(eval_gettext "\$onto_name: there are more than 
one merge bases")"
+                       ;;
+               '')
+                       die "$(eval_gettext "\$onto_name: there is no merge 
base")"
+                       ;;
+               esac
+       else
+               die "$(eval_gettext "\$onto_name: there is no merge base")"
+       fi
+       ;;
+               */
+       } else {
+               if (get_sha1(onto_name, onto_sha1) || !lookup_commit(onto_sha1))
+                       die(_("Does not point to a valid commit: %s"), 
onto_name);
+       }
+
+       /*
+        * If the branch to rebase is given, that is the branch we
+        * will rebase
+        *
+        * $branch_name -- branch being rebased, or HEAD (already
+        * detached)
+        *
+        * $orig_head -- commit object name of tip of the branch
+        * before rebasing
+        *
+        * $head_name -- refs/heads/<that-branch> or "detached HEAD"
+        */
+       switch (argc) {
+       case 1:
+               /* Is it "rebase other $branchname" or "rebase other $commit"? 
*/
+               branch_name = argv[0];
+               switch_to = argv[0];
+               /*
+       if git show-ref --verify --quiet -- "refs/heads/$1" &&
+          orig_head=$(git rev-parse -q --verify "refs/heads/$1")
+       then
+               head_name="refs/heads/$1"
+       elif orig_head=$(git rev-parse -q --verify "$1")
+       then
+               head_name="detached HEAD"
+       else
+               die "$(eval_gettext "fatal: no such branch: \$branch_name")"
+       fi
+        */
+               break;
+
+       case 0:
+               /*
+       # Do not need to switch branches, we are already on it.
+       if branch_name=`git symbolic-ref -q HEAD`
+       then
+               head_name=$branch_name
+               branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'`
+       else
+               head_name="detached HEAD"
+               branch_name=HEAD ;# detached
+       fi
+       orig_head=$(git rev-parse --verify "${branch_name}^0") || exit
+                */
+               break;
+       default:
+               die("BUG: unexpected number of arguments left to parse");
+       }
+
+       require_clean_work_tree();
+
+       /*
+        * Now we are rebasing commits $upstream..$orig_head (or with
+        * --root, everything leading up to $orig_head) on top of
+        * $onto
+        */
+
+       /*
+        * Check if we are already based on $onto with linear history,
+        * but this should be done only when upstream and onto are the
+        * same and if this is not an interactive rebase.
+        */
+
+       /*
+mb=$(git merge-base "$onto" "$orig_head")
+if test "$type" != interactive && test "$upstream" = "$onto" &&
+       test "$mb" = "$onto" &&
+       # linear history?
+       ! (git rev-list --parents "$onto".."$orig_head" | sane_grep " .* ") > 
/dev/null
+then
+       if test -z "$force_rebase"
+       then
+               # Lazily switch to the target branch if needed...
+               test -z "$switch_to" || git checkout "$switch_to" --
+               say "$(eval_gettext "Current branch \$branch_name is up to 
date.")"
+               exit 0
+       else
+               say "$(eval_gettext "Current branch \$branch_name is up to 
date, rebase forced.")"
+       fi
+fi
+       */
+
+       /* If a hook exists, give it a chance to interrupt */
+       run_pre_rebase_hook(argc, argv, upstream_arg);
+
+       /*
+if test -n "$diffstat"
+then
+       if test -n "$verbose"
+       then
+               echo "$(eval_gettext "Changes from \$mb to \$onto:")"
+       fi
+       # We want color (if set), but no pager
+       GIT_PAGER='' git diff --stat --summary "$mb" "$onto"
+fi
+       */
+
+       if (rebase_type == REBASE_INTERACTIVE)
+               return run_specific_rebase();
+
+       /* Detach HEAD and reset the tree */
+       /*
+say "$(gettext "First, rewinding head to replay your work on top of it...")"
+git checkout -q "$onto^0" || die "could not detach HEAD"
+git update-ref ORIG_HEAD $orig_head
+       */
+
+       /*
+        * If the $onto is a proper descendant of the tip of the
+        * branch, then we just fast-forwarded.
+        */
+       if (!hashcmp(mb, orig_head)) {
+               printf(_("Fast-forwarded %s to %s."), branch_name, onto_name);
+               move_to_original_branch();
+               return 0;
+       }
+
+       if (root)
+               strbuf_addf(&revisions, "%s..%s", onto, orig_head);
+       else
+               strbuf_addf(&revisions, "%s..%s", upstream, orig_head);
+
+       return run_specific_rebase();
+}
+
+static int git_rebase_config(const char *name, const char *value, void *data)
+{
+       if (!strcmp(name, "rebase.stat")) {
+               show_stat = git_config_bool(name, value);
+               return 0;
+       } else if (!strcmp(name, "rebase.autosquash")) {
+               autosquash = git_config_bool(name, value);
+               return 0;
+       }
+       return git_default_config(name, value, data);
+}
+
+int cmd_rebase(int argc, const char **argv, const char *prefix)
+{
+       const char *whitespace_opt = NULL;
+       int committer_date_is_author_date = 0;
+       int context_opt = 0;
+       int ignore_date = 0;
+       int ignore_whitespace = 0;
+       int no_ff = 0;
+       int pre_rebase = 1;
+       struct option options[] = {
+               OPT__VERBOSE(&verbose,
+                            N_("display a diffstat of what changed upstream")),
+               OPT__QUIET(&quiet,
+                          N_("be quiet. implies --no-stat")),
+               OPT_STRING(0, "onto", &onto, "ref",
+                          N_("rebase onto given branch instead of upstream")),
+               OPT_BOOL('p', "preserve-merges", &preserve_merges,
+                        N_("try to recreate merges instead of ignoring them")),
+               OPT_STRING('s', "stragegy", &strategy, "strategy",
+                          N_("use the given merge strategy")),
+               { OPTION_SET_INT, 0, "no-ff", &no_ff, NULL,
+                 N_("cherry-pick all commits, even if unchanged"),
+                 PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
+               OPT_BOOL('m', "merge", &do_merge,
+                        N_("use merging strategies to rebase")),
+               OPT_BOOL('i', "interactive", &interactive_rebase,
+                        N_("let the user edit the list of commits to rebase")),
+               OPT_STRING('x', "exec", &exec_cmd, "command",
+                          N_("add exec lines after each commit of the editable 
list")),
+               OPT_BOOL('k', "keep-empty", &keep_empty,
+                        N_("preserve empty commits during rebase")),
+               OPT_BOOL('f', "force-rebase", &force_rebase,
+                        N_("force rebase even if branch is up to date")),
+               OPT_STRING('X', "strategy-options", &strategy_opts, "options",
+                          N_("pass the argument through to the merge 
strategy")),
+               { OPTION_SET_INT, 0, "stat", &show_stat, NULL,
+                 N_("display a diffstat of what changed upstream"),
+                 PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
+               OPT_SET_INT('n', "no-stat", &show_stat,
+                           N_("do not show diffstat of what changed 
upstream"), 0),
+               OPT_BOOL(0, "verify", &pre_rebase,
+                        N_("allow pre-rebase hook to run")),
+               OPT_BOOL(0, "rerere-autoupdate", &rerere_autoupdate,
+                        N_("allow rerere to update index with resolved 
conflicts")),
+               OPT_BOOL(0, "root", &root,
+                        N_("rebase all reachable commits up to the root(s)")),
+               OPT_BOOL(0, "autosquash", &autosquash,
+                        N_("move commits that begin with squash!/fixup! under 
-i")),
+               OPT_BOOL(0, "committer-date-is-author-date", 
&committer_date_is_author_date,
+                        N_("lie about committer date")),
+               OPT_BOOL(0, "ignore-date", &ignore_date,
+                        N_("use current timestamp for author date")),
+               OPT_STRING(0, "whitespace", &whitespace_opt, "mode",
+                          N_("detect new or modified lines that have 
whitespace errors")),
+               OPT_INTEGER('C', NULL, &context_opt,
+                           N_("ensure at least <n> lines of context match by 
'git apply'")),
+               OPT_BOOL(0, "ignore-whitespace", &ignore_whitespace,
+                        N_("ignore changes in whitespace when finding 
context")),
+
+               OPT_GROUP("Actions"),
+               OPT_BOOL(0, "continue", &action_continue,
+                        N_("continue")),
+               OPT_BOOL(0, "abort", &action_abort,
+                        N_("abort and check out the original branch")),
+               OPT_BOOL(0, "skip", &action_skip,
+                        N_("skip current patch and continue")),
+               OPT_BOOL(0, "edit-todo", &edit_todo,
+                        N_("edit the todo list during an interactive rebase")),
+               OPT_END()
+       };
+       struct stat st;
+       int action_nr, in_progress;
+
+       if (!stat(git_path("rebase-apply"), &st) && S_ISDIR(st.st_mode)) {
+               if (!access(git_path("rebase-apply/applying"), F_OK))
+                       die(_("It looks like git-am is in progress. Cannot 
rebase."));
+               rebase_type = REBASE_AM;
+               state_basedir = "rebase-apply";
+               in_progress = 1;
+       } else if (!stat(git_path("rebase-merge"), &st) &&
+                  S_ISDIR(st.st_mode)) {
+               if (!access(git_path("rebase-merge/interactive"), F_OK)) {
+                       rebase_type = REBASE_INTERACTIVE;
+                       interactive_rebase = 1; /* explicit */
+               } else
+                       rebase_type = REBASE_MERGE;
+               state_basedir = "rebase-merge";
+               in_progress = 1;
+       } else
+               in_progress = 0;
+
+       git_config(git_rebase_config, NULL);
+       gitmodules_config();
+
+       argc = parse_options(argc, argv, prefix, options,
+                            builtin_rebase_usage, 0);
+
+       action_nr = action_continue + action_skip + action_abort + edit_todo;
+       if ((action_nr != 1 && action_nr != 0) || argc > 2)
+               usage_with_options(builtin_rebase_usage, options);
+
+       if (verbose && quiet)
+               die(_("--quiet and --verbose are incompatible"));
+       else if (verbose)
+               show_stat = 1;
+       else if (quiet)
+               show_stat = 0;
+
+       if (preserve_merges && !interactive_rebase)
+               interactive_rebase = -1; /* implied */
+
+       if (strategy_opts) {
+               if (!strategy)
+                       strategy = "recursive";
+               /* validate strategy options */
+       }
+
+       if (strategy)
+               do_merge = 1;
+
+       if (!strcmp(whitespace_opt, "fix") ||
+           !strcmp(whitespace_opt, "strip") ||
+           committer_date_is_author_date ||
+           no_ff)
+               force_rebase = 1;
+
+       if (exec_cmd && interactive_rebase != 1)
+               die(_("The --exec option must be used with the --interactive 
option"));
+
+       if (action_nr) {
+               if (!in_progress)
+                       die(_("No rebase in progress?"));
+               if (rebase_type == REBASE_INTERACTIVE)
+                       ; /* GIT_REFLOG_ACTION = "rebase -i ($action)" */
+
+               if (action_continue)
+                       return do_continue();
+               else if (action_skip)
+                       return do_skip();
+               else if (action_abort)
+                       return do_abort();
+               else if (edit_todo)
+                       return do_edit_todo();
+               else
+                       die("BUG: how do you get here?");
+       }
+
+       if (in_progress)
+               die(_("It seems that there is already a %s directory, and\n"
+                     "I wonder if you are in the middle of another rebase. If 
that is the\n"
+                     "case, please try\n"
+                     "\tgit rebase (--continue | --abort | --skip)\n"
+                     "If that is not the case, please\n"
+                     "\trm -rf \"%s/%s\""
+                     "and run me again. I am stopping in case you still have 
something\n"
+                     "valuable there."),
+                   state_basedir,
+                   get_git_dir(), state_basedir);
+
+       return do_rebase(argc, argv, options);
+}
diff --git a/commit.c b/commit.c
index e8eb0ae..395a860 100644
--- a/commit.c
+++ b/commit.c
@@ -1135,7 +1135,7 @@ void free_commit_extra_headers(struct commit_extra_header 
*extra)
        }
 }
 
-int commit_tree(const struct strbuf *msg, unsigned char *tree,
+int commit_tree(const struct strbuf *msg, const unsigned char *tree,
                struct commit_list *parents, unsigned char *ret,
                const char *author, const char *sign_commit)
 {
@@ -1238,7 +1238,7 @@ static const char commit_utf8_warn[] =
 "You may want to amend it after fixing the message, or set the config\n"
 "variable i18n.commitencoding to the encoding your project uses.\n";
 
-int commit_tree_extended(const struct strbuf *msg, unsigned char *tree,
+int commit_tree_extended(const struct strbuf *msg, const unsigned char *tree,
                         struct commit_list *parents, unsigned char *ret,
                         const char *author, const char *sign_commit,
                         struct commit_extra_header *extra)
diff --git a/commit.h b/commit.h
index 0f469e5..058886f 100644
--- a/commit.h
+++ b/commit.h
@@ -193,11 +193,11 @@ struct commit_extra_header {
 extern void append_merge_tag_headers(struct commit_list *parents,
                                     struct commit_extra_header ***tail);
 
-extern int commit_tree(const struct strbuf *msg, unsigned char *tree,
+extern int commit_tree(const struct strbuf *msg, const unsigned char *tree,
                       struct commit_list *parents, unsigned char *ret,
                       const char *author, const char *sign_commit);
 
-extern int commit_tree_extended(const struct strbuf *msg, unsigned char *tree,
+extern int commit_tree_extended(const struct strbuf *msg, const unsigned char 
*tree,
                                struct commit_list *parents, unsigned char *ret,
                                const char *author, const char *sign_commit,
                                struct commit_extra_header *);
diff --git a/contrib/examples/git-rebase.sh b/contrib/examples/git-rebase.sh
new file mode 100755
index 0000000..38530e8
--- /dev/null
+++ b/contrib/examples/git-rebase.sh
@@ -0,0 +1,532 @@
+#!/bin/sh
+#
+# Copyright (c) 2005 Junio C Hamano.
+#
+
+SUBDIRECTORY_OK=Yes
+OPTIONS_KEEPDASHDASH=
+OPTIONS_SPEC="\
+git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>] 
[<branch>]
+git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>]
+git-rebase --continue | --abort | --skip | --edit-todo
+--
+ Available options are
+v,verbose!         display a diffstat of what changed upstream
+q,quiet!           be quiet. implies --no-stat
+onto=!             rebase onto given branch instead of upstream
+p,preserve-merges! try to recreate merges instead of ignoring them
+s,strategy=!       use the given merge strategy
+no-ff!             cherry-pick all commits, even if unchanged
+m,merge!           use merging strategies to rebase
+i,interactive!     let the user edit the list of commits to rebase
+x,exec=!           add exec lines after each commit of the editable list
+k,keep-empty      preserve empty commits during rebase
+f,force-rebase!    force rebase even if branch is up to date
+X,strategy-option=! pass the argument through to the merge strategy
+stat!              display a diffstat of what changed upstream
+n,no-stat!         do not show diffstat of what changed upstream
+verify             allow pre-rebase hook to run
+rerere-autoupdate  allow rerere to update index with resolved conflicts
+root!              rebase all reachable commits up to the root(s)
+autosquash         move commits that begin with squash!/fixup! under -i
+committer-date-is-author-date! passed to 'git am'
+ignore-date!       passed to 'git am'
+whitespace=!       passed to 'git apply'
+ignore-whitespace! passed to 'git apply'
+C=!                passed to 'git apply'
+ Actions:
+continue!          continue
+abort!             abort and check out the original branch
+skip!              skip current patch and continue
+edit-todo!         edit the todo list during an interactive rebase
+"
+. git-sh-setup
+. git-sh-i18n
+set_reflog_action rebase
+require_work_tree_exists
+cd_to_toplevel
+
+LF='
+'
+ok_to_skip_pre_rebase=
+unset onto
+cmd=
+strategy=
+strategy_opts=
+do_merge=
+merge_dir="$GIT_DIR"/rebase-merge
+apply_dir="$GIT_DIR"/rebase-apply
+verbose=
+diffstat=
+test "$(git config --bool rebase.stat)" = true && diffstat=t
+git_am_opt=
+rebase_root=
+force_rebase=
+allow_rerere_autoupdate=
+# Non-empty if a rebase was in progress when 'git rebase' was invoked
+in_progress=
+# One of {am, merge, interactive}
+type=
+# One of {"$GIT_DIR"/rebase-apply, "$GIT_DIR"/rebase-merge}
+state_dir=
+# One of {'', continue, skip, abort}, as parsed from command line
+action=
+preserve_merges=
+autosquash=
+keep_empty=
+test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
+
+read_basic_state () {
+       head_name=$(cat "$state_dir"/head-name) &&
+       onto=$(cat "$state_dir"/onto) &&
+       # We always write to orig-head, but interactive rebase used to write to
+       # head. Fall back to reading from head to cover for the case that the
+       # user upgraded git with an ongoing interactive rebase.
+       if test -f "$state_dir"/orig-head
+       then
+               orig_head=$(cat "$state_dir"/orig-head)
+       else
+               orig_head=$(cat "$state_dir"/head)
+       fi &&
+       GIT_QUIET=$(cat "$state_dir"/quiet) &&
+       test -f "$state_dir"/verbose && verbose=t
+       test -f "$state_dir"/strategy && strategy="$(cat "$state_dir"/strategy)"
+       test -f "$state_dir"/strategy_opts &&
+               strategy_opts="$(cat "$state_dir"/strategy_opts)"
+       test -f "$state_dir"/allow_rerere_autoupdate &&
+               allow_rerere_autoupdate="$(cat 
"$state_dir"/allow_rerere_autoupdate)"
+}
+
+output () {
+       case "$verbose" in
+       '')
+               output=$("$@" 2>&1 )
+               status=$?
+               test $status != 0 && printf "%s\n" "$output"
+               return $status
+               ;;
+       *)
+               "$@"
+               ;;
+       esac
+}
+
+move_to_original_branch () {
+       case "$head_name" in
+       refs/*)
+               message="rebase finished: $head_name onto $onto"
+               git update-ref -m "$message" \
+                       $head_name $(git rev-parse HEAD) $orig_head &&
+               git symbolic-ref \
+                       -m "rebase finished: returning to $head_name" \
+                       HEAD $head_name ||
+               die "$(gettext "Could not move back to $head_name")"
+               ;;
+       esac
+}
+
+run_specific_rebase () {
+       if [ "$interactive_rebase" = implied ]; then
+               GIT_EDITOR=:
+               export GIT_EDITOR
+               autosquash=
+       fi
+       git_quiet=$GIT_QUIET
+       export GIT_PAGER
+       export action allow_rerere_autoupdate git_am_opt git_quiet head_name 
keep_empty
+       export onto orig_head rebase_root revisions
+       export state_dir verbose strategy strategy_opts
+       export autosquash cmd force_rebase preserve_merges squash_onto 
switch_to upstream
+       exec git-rebase--$type
+}
+
+run_pre_rebase_hook () {
+       if test -z "$ok_to_skip_pre_rebase" &&
+          test -x "$GIT_DIR/hooks/pre-rebase"
+       then
+               "$GIT_DIR/hooks/pre-rebase" ${1+"$@"} ||
+               die "$(gettext "The pre-rebase hook refused to rebase.")"
+       fi
+}
+
+test -f "$apply_dir"/applying &&
+       die "$(gettext "It looks like git-am is in progress. Cannot rebase.")"
+
+if test -d "$apply_dir"
+then
+       type=am
+       state_dir="$apply_dir"
+elif test -d "$merge_dir"
+then
+       if test -f "$merge_dir"/interactive
+       then
+               type=interactive
+               interactive_rebase=explicit
+       else
+               type=merge
+       fi
+       state_dir="$merge_dir"
+fi
+test -n "$type" && in_progress=t
+
+total_argc=$#
+while test $# != 0
+do
+       case "$1" in
+       --no-verify)
+               ok_to_skip_pre_rebase=yes
+               ;;
+       --verify)
+               ok_to_skip_pre_rebase=
+               ;;
+       --continue|--skip|--abort|--edit-todo)
+               test $total_argc -eq 2 || usage
+               action=${1##--}
+               ;;
+       --onto)
+               test 2 -le "$#" || usage
+               onto="$2"
+               shift
+               ;;
+       -x)
+               test 2 -le "$#" || usage
+               cmd="${cmd}exec $2${LF}"
+               shift
+               ;;
+       -i)
+               interactive_rebase=explicit
+               ;;
+       -k)
+               keep_empty=yes
+               ;;
+       -p)
+               preserve_merges=t
+               test -z "$interactive_rebase" && interactive_rebase=implied
+               ;;
+       --autosquash)
+               autosquash=t
+               ;;
+       --no-autosquash)
+               autosquash=
+               ;;
+       -M|-m)
+               do_merge=t
+               ;;
+       -X)
+               shift
+               strategy_opts="$strategy_opts $(git rev-parse --sq-quote 
"--$1")"
+               do_merge=t
+               test -z "$strategy" && strategy=recursive
+               ;;
+       -s)
+               shift
+               strategy="$1"
+               do_merge=t
+               ;;
+       -n)
+               diffstat=
+               ;;
+       --stat)
+               diffstat=t
+               ;;
+       -v)
+               verbose=t
+               diffstat=t
+               GIT_QUIET=
+               ;;
+       -q)
+               GIT_QUIET=t
+               git_am_opt="$git_am_opt -q"
+               verbose=
+               diffstat=
+               ;;
+       --whitespace)
+               shift
+               git_am_opt="$git_am_opt --whitespace=$1"
+               case "$1" in
+               fix|strip)
+                       force_rebase=t
+                       ;;
+               esac
+               ;;
+       --ignore-whitespace)
+               git_am_opt="$git_am_opt $1"
+               ;;
+       --committer-date-is-author-date|--ignore-date)
+               git_am_opt="$git_am_opt $1"
+               force_rebase=t
+               ;;
+       -C)
+               shift
+               git_am_opt="$git_am_opt -C$1"
+               ;;
+       --root)
+               rebase_root=t
+               ;;
+       -f|--no-ff)
+               force_rebase=t
+               ;;
+       --rerere-autoupdate|--no-rerere-autoupdate)
+               allow_rerere_autoupdate="$1"
+               ;;
+       --)
+               shift
+               break
+               ;;
+       esac
+       shift
+done
+test $# -gt 2 && usage
+
+if test -n "$cmd" &&
+   test "$interactive_rebase" != explicit
+then
+       die "$(gettext "The --exec option must be used with the --interactive 
option")"
+fi
+
+if test -n "$action"
+then
+       test -z "$in_progress" && die "$(gettext "No rebase in progress?")"
+       # Only interactive rebase uses detailed reflog messages
+       if test "$type" = interactive && test "$GIT_REFLOG_ACTION" = rebase
+       then
+               GIT_REFLOG_ACTION="rebase -i ($action)"
+               export GIT_REFLOG_ACTION
+       fi
+fi
+
+if test "$action" = "edit-todo" && test "$type" != "interactive"
+then
+       die "$(gettext "The --edit-todo action can only be used during 
interactive rebase.")"
+fi
+
+case "$action" in
+continue)
+       # Sanity check
+       git rev-parse --verify HEAD >/dev/null ||
+               die "$(gettext "Cannot read HEAD")"
+       git update-index --ignore-submodules --refresh &&
+       git diff-files --quiet --ignore-submodules || {
+               echo "$(gettext "You must edit all merge conflicts and then
+mark them as resolved using git add")"
+               exit 1
+       }
+       read_basic_state
+       run_specific_rebase
+       ;;
+skip)
+       output git reset --hard HEAD || exit $?
+       read_basic_state
+       run_specific_rebase
+       ;;
+abort)
+       git rerere clear
+       read_basic_state
+       case "$head_name" in
+       refs/*)
+               git symbolic-ref -m "rebase: aborting" HEAD $head_name ||
+               die "$(eval_gettext "Could not move back to \$head_name")"
+               ;;
+       esac
+       output git reset --hard $orig_head
+       rm -r "$state_dir"
+       exit
+       ;;
+edit-todo)
+       run_specific_rebase
+       ;;
+esac
+
+# Make sure no rebase is in progress
+if test -n "$in_progress"
+then
+       state_dir_base=${state_dir##*/}
+       cmd_live_rebase="git rebase (--continue | --abort | --skip)"
+       cmd_clear_stale_rebase="rm -fr \"$state_dir\""
+       die "
+$(eval_gettext 'It seems that there is already a $state_dir_base directory, and
+I wonder if you are in the middle of another rebase.  If that is the
+case, please try
+       $cmd_live_rebase
+If that is not the case, please
+       $cmd_clear_stale_rebase
+and run me again.  I am stopping in case you still have something
+valuable there.')"
+fi
+
+if test -n "$rebase_root" && test -z "$onto"
+then
+       test -z "$interactive_rebase" && interactive_rebase=implied
+fi
+
+if test -n "$interactive_rebase"
+then
+       type=interactive
+       state_dir="$merge_dir"
+elif test -n "$do_merge"
+then
+       type=merge
+       state_dir="$merge_dir"
+else
+       type=am
+       state_dir="$apply_dir"
+fi
+
+if test -z "$rebase_root"
+then
+       case "$#" in
+       0)
+               if ! upstream_name=$(git rev-parse --symbolic-full-name \
+                       --verify -q @{upstream} 2>/dev/null)
+               then
+                       . git-parse-remote
+                       error_on_missing_default_upstream "rebase" "rebase" \
+                               "against" "git rebase <branch>"
+               fi
+               ;;
+       *)      upstream_name="$1"
+               shift
+               ;;
+       esac
+       upstream=`git rev-parse --verify "${upstream_name}^0"` ||
+       die "$(eval_gettext "invalid upstream \$upstream_name")"
+       upstream_arg="$upstream_name"
+else
+       if test -z "$onto"
+       then
+               empty_tree=`git hash-object -t tree /dev/null`
+               onto=`git commit-tree $empty_tree </dev/null`
+               squash_onto="$onto"
+       fi
+       unset upstream_name
+       unset upstream
+       test $# -gt 1 && usage
+       upstream_arg=--root
+fi
+
+# Make sure the branch to rebase onto is valid.
+onto_name=${onto-"$upstream_name"}
+case "$onto_name" in
+*...*)
+       if      left=${onto_name%...*} right=${onto_name#*...} &&
+               onto=$(git merge-base --all ${left:-HEAD} ${right:-HEAD})
+       then
+               case "$onto" in
+               ?*"$LF"?*)
+                       die "$(eval_gettext "\$onto_name: there are more than 
one merge bases")"
+                       ;;
+               '')
+                       die "$(eval_gettext "\$onto_name: there is no merge 
base")"
+                       ;;
+               esac
+       else
+               die "$(eval_gettext "\$onto_name: there is no merge base")"
+       fi
+       ;;
+*)
+       onto=$(git rev-parse --verify "${onto_name}^0") ||
+       die "$(eval_gettext "Does not point to a valid commit: \$onto_name")"
+       ;;
+esac
+
+# If the branch to rebase is given, that is the branch we will rebase
+# $branch_name -- branch being rebased, or HEAD (already detached)
+# $orig_head -- commit object name of tip of the branch before rebasing
+# $head_name -- refs/heads/<that-branch> or "detached HEAD"
+switch_to=
+case "$#" in
+1)
+       # Is it "rebase other $branchname" or "rebase other $commit"?
+       branch_name="$1"
+       switch_to="$1"
+
+       if git show-ref --verify --quiet -- "refs/heads/$1" &&
+          orig_head=$(git rev-parse -q --verify "refs/heads/$1")
+       then
+               head_name="refs/heads/$1"
+       elif orig_head=$(git rev-parse -q --verify "$1")
+       then
+               head_name="detached HEAD"
+       else
+               die "$(eval_gettext "fatal: no such branch: \$branch_name")"
+       fi
+       ;;
+0)
+       # Do not need to switch branches, we are already on it.
+       if branch_name=`git symbolic-ref -q HEAD`
+       then
+               head_name=$branch_name
+               branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'`
+       else
+               head_name="detached HEAD"
+               branch_name=HEAD ;# detached
+       fi
+       orig_head=$(git rev-parse --verify "${branch_name}^0") || exit
+       ;;
+*)
+       die "BUG: unexpected number of arguments left to parse"
+       ;;
+esac
+
+require_clean_work_tree "rebase" "$(gettext "Please commit or stash them.")"
+
+# Now we are rebasing commits $upstream..$orig_head (or with --root,
+# everything leading up to $orig_head) on top of $onto
+
+# Check if we are already based on $onto with linear history,
+# but this should be done only when upstream and onto are the same
+# and if this is not an interactive rebase.
+mb=$(git merge-base "$onto" "$orig_head")
+if test "$type" != interactive && test "$upstream" = "$onto" &&
+       test "$mb" = "$onto" &&
+       # linear history?
+       ! (git rev-list --parents "$onto".."$orig_head" | sane_grep " .* ") > 
/dev/null
+then
+       if test -z "$force_rebase"
+       then
+               # Lazily switch to the target branch if needed...
+               test -z "$switch_to" || git checkout "$switch_to" --
+               say "$(eval_gettext "Current branch \$branch_name is up to 
date.")"
+               exit 0
+       else
+               say "$(eval_gettext "Current branch \$branch_name is up to 
date, rebase forced.")"
+       fi
+fi
+
+# If a hook exists, give it a chance to interrupt
+run_pre_rebase_hook "$upstream_arg" "$@"
+
+if test -n "$diffstat"
+then
+       if test -n "$verbose"
+       then
+               echo "$(eval_gettext "Changes from \$mb to \$onto:")"
+       fi
+       # We want color (if set), but no pager
+       GIT_PAGER='' git diff --stat --summary "$mb" "$onto"
+fi
+
+test "$type" = interactive && run_specific_rebase
+
+# Detach HEAD and reset the tree
+say "$(gettext "First, rewinding head to replay your work on top of it...")"
+git checkout -q "$onto^0" || die "could not detach HEAD"
+git update-ref ORIG_HEAD $orig_head
+
+# If the $onto is a proper descendant of the tip of the branch, then
+# we just fast-forwarded.
+if test "$mb" = "$orig_head"
+then
+       say "$(eval_gettext "Fast-forwarded \$branch_name to \$onto_name.")"
+       move_to_original_branch
+       exit 0
+fi
+
+if test -n "$rebase_root"
+then
+       revisions="$onto..$orig_head"
+else
+       revisions="$upstream..$orig_head"
+fi
+
+run_specific_rebase
diff --git a/git-rebase.sh b/git-rebase.sh
deleted file mode 100755
index 38530e8..0000000
--- a/git-rebase.sh
+++ /dev/null
@@ -1,532 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2005 Junio C Hamano.
-#
-
-SUBDIRECTORY_OK=Yes
-OPTIONS_KEEPDASHDASH=
-OPTIONS_SPEC="\
-git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>] 
[<branch>]
-git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>]
-git-rebase --continue | --abort | --skip | --edit-todo
---
- Available options are
-v,verbose!         display a diffstat of what changed upstream
-q,quiet!           be quiet. implies --no-stat
-onto=!             rebase onto given branch instead of upstream
-p,preserve-merges! try to recreate merges instead of ignoring them
-s,strategy=!       use the given merge strategy
-no-ff!             cherry-pick all commits, even if unchanged
-m,merge!           use merging strategies to rebase
-i,interactive!     let the user edit the list of commits to rebase
-x,exec=!           add exec lines after each commit of the editable list
-k,keep-empty      preserve empty commits during rebase
-f,force-rebase!    force rebase even if branch is up to date
-X,strategy-option=! pass the argument through to the merge strategy
-stat!              display a diffstat of what changed upstream
-n,no-stat!         do not show diffstat of what changed upstream
-verify             allow pre-rebase hook to run
-rerere-autoupdate  allow rerere to update index with resolved conflicts
-root!              rebase all reachable commits up to the root(s)
-autosquash         move commits that begin with squash!/fixup! under -i
-committer-date-is-author-date! passed to 'git am'
-ignore-date!       passed to 'git am'
-whitespace=!       passed to 'git apply'
-ignore-whitespace! passed to 'git apply'
-C=!                passed to 'git apply'
- Actions:
-continue!          continue
-abort!             abort and check out the original branch
-skip!              skip current patch and continue
-edit-todo!         edit the todo list during an interactive rebase
-"
-. git-sh-setup
-. git-sh-i18n
-set_reflog_action rebase
-require_work_tree_exists
-cd_to_toplevel
-
-LF='
-'
-ok_to_skip_pre_rebase=
-unset onto
-cmd=
-strategy=
-strategy_opts=
-do_merge=
-merge_dir="$GIT_DIR"/rebase-merge
-apply_dir="$GIT_DIR"/rebase-apply
-verbose=
-diffstat=
-test "$(git config --bool rebase.stat)" = true && diffstat=t
-git_am_opt=
-rebase_root=
-force_rebase=
-allow_rerere_autoupdate=
-# Non-empty if a rebase was in progress when 'git rebase' was invoked
-in_progress=
-# One of {am, merge, interactive}
-type=
-# One of {"$GIT_DIR"/rebase-apply, "$GIT_DIR"/rebase-merge}
-state_dir=
-# One of {'', continue, skip, abort}, as parsed from command line
-action=
-preserve_merges=
-autosquash=
-keep_empty=
-test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
-
-read_basic_state () {
-       head_name=$(cat "$state_dir"/head-name) &&
-       onto=$(cat "$state_dir"/onto) &&
-       # We always write to orig-head, but interactive rebase used to write to
-       # head. Fall back to reading from head to cover for the case that the
-       # user upgraded git with an ongoing interactive rebase.
-       if test -f "$state_dir"/orig-head
-       then
-               orig_head=$(cat "$state_dir"/orig-head)
-       else
-               orig_head=$(cat "$state_dir"/head)
-       fi &&
-       GIT_QUIET=$(cat "$state_dir"/quiet) &&
-       test -f "$state_dir"/verbose && verbose=t
-       test -f "$state_dir"/strategy && strategy="$(cat "$state_dir"/strategy)"
-       test -f "$state_dir"/strategy_opts &&
-               strategy_opts="$(cat "$state_dir"/strategy_opts)"
-       test -f "$state_dir"/allow_rerere_autoupdate &&
-               allow_rerere_autoupdate="$(cat 
"$state_dir"/allow_rerere_autoupdate)"
-}
-
-output () {
-       case "$verbose" in
-       '')
-               output=$("$@" 2>&1 )
-               status=$?
-               test $status != 0 && printf "%s\n" "$output"
-               return $status
-               ;;
-       *)
-               "$@"
-               ;;
-       esac
-}
-
-move_to_original_branch () {
-       case "$head_name" in
-       refs/*)
-               message="rebase finished: $head_name onto $onto"
-               git update-ref -m "$message" \
-                       $head_name $(git rev-parse HEAD) $orig_head &&
-               git symbolic-ref \
-                       -m "rebase finished: returning to $head_name" \
-                       HEAD $head_name ||
-               die "$(gettext "Could not move back to $head_name")"
-               ;;
-       esac
-}
-
-run_specific_rebase () {
-       if [ "$interactive_rebase" = implied ]; then
-               GIT_EDITOR=:
-               export GIT_EDITOR
-               autosquash=
-       fi
-       git_quiet=$GIT_QUIET
-       export GIT_PAGER
-       export action allow_rerere_autoupdate git_am_opt git_quiet head_name 
keep_empty
-       export onto orig_head rebase_root revisions
-       export state_dir verbose strategy strategy_opts
-       export autosquash cmd force_rebase preserve_merges squash_onto 
switch_to upstream
-       exec git-rebase--$type
-}
-
-run_pre_rebase_hook () {
-       if test -z "$ok_to_skip_pre_rebase" &&
-          test -x "$GIT_DIR/hooks/pre-rebase"
-       then
-               "$GIT_DIR/hooks/pre-rebase" ${1+"$@"} ||
-               die "$(gettext "The pre-rebase hook refused to rebase.")"
-       fi
-}
-
-test -f "$apply_dir"/applying &&
-       die "$(gettext "It looks like git-am is in progress. Cannot rebase.")"
-
-if test -d "$apply_dir"
-then
-       type=am
-       state_dir="$apply_dir"
-elif test -d "$merge_dir"
-then
-       if test -f "$merge_dir"/interactive
-       then
-               type=interactive
-               interactive_rebase=explicit
-       else
-               type=merge
-       fi
-       state_dir="$merge_dir"
-fi
-test -n "$type" && in_progress=t
-
-total_argc=$#
-while test $# != 0
-do
-       case "$1" in
-       --no-verify)
-               ok_to_skip_pre_rebase=yes
-               ;;
-       --verify)
-               ok_to_skip_pre_rebase=
-               ;;
-       --continue|--skip|--abort|--edit-todo)
-               test $total_argc -eq 2 || usage
-               action=${1##--}
-               ;;
-       --onto)
-               test 2 -le "$#" || usage
-               onto="$2"
-               shift
-               ;;
-       -x)
-               test 2 -le "$#" || usage
-               cmd="${cmd}exec $2${LF}"
-               shift
-               ;;
-       -i)
-               interactive_rebase=explicit
-               ;;
-       -k)
-               keep_empty=yes
-               ;;
-       -p)
-               preserve_merges=t
-               test -z "$interactive_rebase" && interactive_rebase=implied
-               ;;
-       --autosquash)
-               autosquash=t
-               ;;
-       --no-autosquash)
-               autosquash=
-               ;;
-       -M|-m)
-               do_merge=t
-               ;;
-       -X)
-               shift
-               strategy_opts="$strategy_opts $(git rev-parse --sq-quote 
"--$1")"
-               do_merge=t
-               test -z "$strategy" && strategy=recursive
-               ;;
-       -s)
-               shift
-               strategy="$1"
-               do_merge=t
-               ;;
-       -n)
-               diffstat=
-               ;;
-       --stat)
-               diffstat=t
-               ;;
-       -v)
-               verbose=t
-               diffstat=t
-               GIT_QUIET=
-               ;;
-       -q)
-               GIT_QUIET=t
-               git_am_opt="$git_am_opt -q"
-               verbose=
-               diffstat=
-               ;;
-       --whitespace)
-               shift
-               git_am_opt="$git_am_opt --whitespace=$1"
-               case "$1" in
-               fix|strip)
-                       force_rebase=t
-                       ;;
-               esac
-               ;;
-       --ignore-whitespace)
-               git_am_opt="$git_am_opt $1"
-               ;;
-       --committer-date-is-author-date|--ignore-date)
-               git_am_opt="$git_am_opt $1"
-               force_rebase=t
-               ;;
-       -C)
-               shift
-               git_am_opt="$git_am_opt -C$1"
-               ;;
-       --root)
-               rebase_root=t
-               ;;
-       -f|--no-ff)
-               force_rebase=t
-               ;;
-       --rerere-autoupdate|--no-rerere-autoupdate)
-               allow_rerere_autoupdate="$1"
-               ;;
-       --)
-               shift
-               break
-               ;;
-       esac
-       shift
-done
-test $# -gt 2 && usage
-
-if test -n "$cmd" &&
-   test "$interactive_rebase" != explicit
-then
-       die "$(gettext "The --exec option must be used with the --interactive 
option")"
-fi
-
-if test -n "$action"
-then
-       test -z "$in_progress" && die "$(gettext "No rebase in progress?")"
-       # Only interactive rebase uses detailed reflog messages
-       if test "$type" = interactive && test "$GIT_REFLOG_ACTION" = rebase
-       then
-               GIT_REFLOG_ACTION="rebase -i ($action)"
-               export GIT_REFLOG_ACTION
-       fi
-fi
-
-if test "$action" = "edit-todo" && test "$type" != "interactive"
-then
-       die "$(gettext "The --edit-todo action can only be used during 
interactive rebase.")"
-fi
-
-case "$action" in
-continue)
-       # Sanity check
-       git rev-parse --verify HEAD >/dev/null ||
-               die "$(gettext "Cannot read HEAD")"
-       git update-index --ignore-submodules --refresh &&
-       git diff-files --quiet --ignore-submodules || {
-               echo "$(gettext "You must edit all merge conflicts and then
-mark them as resolved using git add")"
-               exit 1
-       }
-       read_basic_state
-       run_specific_rebase
-       ;;
-skip)
-       output git reset --hard HEAD || exit $?
-       read_basic_state
-       run_specific_rebase
-       ;;
-abort)
-       git rerere clear
-       read_basic_state
-       case "$head_name" in
-       refs/*)
-               git symbolic-ref -m "rebase: aborting" HEAD $head_name ||
-               die "$(eval_gettext "Could not move back to \$head_name")"
-               ;;
-       esac
-       output git reset --hard $orig_head
-       rm -r "$state_dir"
-       exit
-       ;;
-edit-todo)
-       run_specific_rebase
-       ;;
-esac
-
-# Make sure no rebase is in progress
-if test -n "$in_progress"
-then
-       state_dir_base=${state_dir##*/}
-       cmd_live_rebase="git rebase (--continue | --abort | --skip)"
-       cmd_clear_stale_rebase="rm -fr \"$state_dir\""
-       die "
-$(eval_gettext 'It seems that there is already a $state_dir_base directory, and
-I wonder if you are in the middle of another rebase.  If that is the
-case, please try
-       $cmd_live_rebase
-If that is not the case, please
-       $cmd_clear_stale_rebase
-and run me again.  I am stopping in case you still have something
-valuable there.')"
-fi
-
-if test -n "$rebase_root" && test -z "$onto"
-then
-       test -z "$interactive_rebase" && interactive_rebase=implied
-fi
-
-if test -n "$interactive_rebase"
-then
-       type=interactive
-       state_dir="$merge_dir"
-elif test -n "$do_merge"
-then
-       type=merge
-       state_dir="$merge_dir"
-else
-       type=am
-       state_dir="$apply_dir"
-fi
-
-if test -z "$rebase_root"
-then
-       case "$#" in
-       0)
-               if ! upstream_name=$(git rev-parse --symbolic-full-name \
-                       --verify -q @{upstream} 2>/dev/null)
-               then
-                       . git-parse-remote
-                       error_on_missing_default_upstream "rebase" "rebase" \
-                               "against" "git rebase <branch>"
-               fi
-               ;;
-       *)      upstream_name="$1"
-               shift
-               ;;
-       esac
-       upstream=`git rev-parse --verify "${upstream_name}^0"` ||
-       die "$(eval_gettext "invalid upstream \$upstream_name")"
-       upstream_arg="$upstream_name"
-else
-       if test -z "$onto"
-       then
-               empty_tree=`git hash-object -t tree /dev/null`
-               onto=`git commit-tree $empty_tree </dev/null`
-               squash_onto="$onto"
-       fi
-       unset upstream_name
-       unset upstream
-       test $# -gt 1 && usage
-       upstream_arg=--root
-fi
-
-# Make sure the branch to rebase onto is valid.
-onto_name=${onto-"$upstream_name"}
-case "$onto_name" in
-*...*)
-       if      left=${onto_name%...*} right=${onto_name#*...} &&
-               onto=$(git merge-base --all ${left:-HEAD} ${right:-HEAD})
-       then
-               case "$onto" in
-               ?*"$LF"?*)
-                       die "$(eval_gettext "\$onto_name: there are more than 
one merge bases")"
-                       ;;
-               '')
-                       die "$(eval_gettext "\$onto_name: there is no merge 
base")"
-                       ;;
-               esac
-       else
-               die "$(eval_gettext "\$onto_name: there is no merge base")"
-       fi
-       ;;
-*)
-       onto=$(git rev-parse --verify "${onto_name}^0") ||
-       die "$(eval_gettext "Does not point to a valid commit: \$onto_name")"
-       ;;
-esac
-
-# If the branch to rebase is given, that is the branch we will rebase
-# $branch_name -- branch being rebased, or HEAD (already detached)
-# $orig_head -- commit object name of tip of the branch before rebasing
-# $head_name -- refs/heads/<that-branch> or "detached HEAD"
-switch_to=
-case "$#" in
-1)
-       # Is it "rebase other $branchname" or "rebase other $commit"?
-       branch_name="$1"
-       switch_to="$1"
-
-       if git show-ref --verify --quiet -- "refs/heads/$1" &&
-          orig_head=$(git rev-parse -q --verify "refs/heads/$1")
-       then
-               head_name="refs/heads/$1"
-       elif orig_head=$(git rev-parse -q --verify "$1")
-       then
-               head_name="detached HEAD"
-       else
-               die "$(eval_gettext "fatal: no such branch: \$branch_name")"
-       fi
-       ;;
-0)
-       # Do not need to switch branches, we are already on it.
-       if branch_name=`git symbolic-ref -q HEAD`
-       then
-               head_name=$branch_name
-               branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'`
-       else
-               head_name="detached HEAD"
-               branch_name=HEAD ;# detached
-       fi
-       orig_head=$(git rev-parse --verify "${branch_name}^0") || exit
-       ;;
-*)
-       die "BUG: unexpected number of arguments left to parse"
-       ;;
-esac
-
-require_clean_work_tree "rebase" "$(gettext "Please commit or stash them.")"
-
-# Now we are rebasing commits $upstream..$orig_head (or with --root,
-# everything leading up to $orig_head) on top of $onto
-
-# Check if we are already based on $onto with linear history,
-# but this should be done only when upstream and onto are the same
-# and if this is not an interactive rebase.
-mb=$(git merge-base "$onto" "$orig_head")
-if test "$type" != interactive && test "$upstream" = "$onto" &&
-       test "$mb" = "$onto" &&
-       # linear history?
-       ! (git rev-list --parents "$onto".."$orig_head" | sane_grep " .* ") > 
/dev/null
-then
-       if test -z "$force_rebase"
-       then
-               # Lazily switch to the target branch if needed...
-               test -z "$switch_to" || git checkout "$switch_to" --
-               say "$(eval_gettext "Current branch \$branch_name is up to 
date.")"
-               exit 0
-       else
-               say "$(eval_gettext "Current branch \$branch_name is up to 
date, rebase forced.")"
-       fi
-fi
-
-# If a hook exists, give it a chance to interrupt
-run_pre_rebase_hook "$upstream_arg" "$@"
-
-if test -n "$diffstat"
-then
-       if test -n "$verbose"
-       then
-               echo "$(eval_gettext "Changes from \$mb to \$onto:")"
-       fi
-       # We want color (if set), but no pager
-       GIT_PAGER='' git diff --stat --summary "$mb" "$onto"
-fi
-
-test "$type" = interactive && run_specific_rebase
-
-# Detach HEAD and reset the tree
-say "$(gettext "First, rewinding head to replay your work on top of it...")"
-git checkout -q "$onto^0" || die "could not detach HEAD"
-git update-ref ORIG_HEAD $orig_head
-
-# If the $onto is a proper descendant of the tip of the branch, then
-# we just fast-forwarded.
-if test "$mb" = "$orig_head"
-then
-       say "$(eval_gettext "Fast-forwarded \$branch_name to \$onto_name.")"
-       move_to_original_branch
-       exit 0
-fi
-
-if test -n "$rebase_root"
-then
-       revisions="$onto..$orig_head"
-else
-       revisions="$upstream..$orig_head"
-fi
-
-run_specific_rebase
diff --git a/git.c b/git.c
index ed66c66..a4cb4a8 100644
--- a/git.c
+++ b/git.c
@@ -379,6 +379,7 @@ static void handle_internal_command(int argc, const char 
**argv)
                { "prune-packed", cmd_prune_packed, RUN_SETUP },
                { "push", cmd_push, RUN_SETUP },
                { "read-tree", cmd_read_tree, RUN_SETUP },
+               { "rebase", cmd_rebase, RUN_SETUP | NEED_WORK_TREE },
                { "receive-pack", cmd_receive_pack },
                { "reflog", cmd_reflog, RUN_SETUP },
                { "remote", cmd_remote, RUN_SETUP },
-- 
2.3.0.rc1.137.g477eb31

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to