Merge branch 'rr/rebase-reflog-message-reword'
authorJunio C Hamano <gitster@pobox.com>
Thu, 18 Jul 2013 19:48:20 +0000 (12:48 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 18 Jul 2013 19:48:20 +0000 (12:48 -0700)
"git rebase [-i]" used to leave just "rebase" as its reflog message
for some operations. This rewords them to be more informative.

* rr/rebase-reflog-message-reword:
rebase -i: use a better reflog message
rebase: use a better reflog message

1  2 
git-rebase--interactive.sh
git-rebase.sh
t/t3404-rebase-interactive.sh
index 157690b6858bdd8497be0bcea6f2385d86dc3f33,a975529353e7b1e1bb32c462c0dbae34f0a1644f..83d6d4676bc1cadcec5ea5889fcf4a0769ee8d31
@@@ -80,18 -80,6 +80,18 @@@ amend="$state_dir"/amen
  rewritten_list="$state_dir"/rewritten-list
  rewritten_pending="$state_dir"/rewritten-pending
  
 +strategy_args=
 +if test -n "$do_merge"
 +then
 +      strategy_args=${strategy:+--strategy=$strategy}
 +      eval '
 +              for strategy_opt in '"$strategy_opts"'
 +              do
 +                      strategy_args="$strategy_args -X$(git rev-parse --sq-quote "${strategy_opt#--}")"
 +              done
 +      '
 +fi
 +
  GIT_CHERRY_PICK_HELP="$resolvemsg"
  export GIT_CHERRY_PICK_HELP
  
@@@ -251,7 -239,7 +251,7 @@@ pick_one () 
  
        test -d "$rewritten" &&
                pick_one_preserving_merges "$@" && return
 -      output git cherry-pick $empty_args $ff "$@"
 +      output eval git cherry-pick "$strategy_args" $empty_args $ff "$@"
  }
  
  pick_one_preserving_merges () {
                        msg_content="$(commit_message $sha1)"
                        # No point in merging the first parent, that's HEAD
                        new_parents=${new_parents# $first_parent}
 -                      if ! do_with_author output \
 -                              git merge --no-ff ${strategy:+-s $strategy} -m \
 -                                      "$msg_content" $new_parents
 +                      if ! do_with_author output eval \
 +                      'git merge --no-ff $strategy_args -m "$msg_content" $new_parents'
                        then
                                printf "%s\n" "$msg_content" > "$GIT_DIR"/MERGE_MSG
                                die_with_patch $sha1 "Error redoing merge $sha1"
                        echo "$sha1 $(git rev-parse HEAD^0)" >> "$rewritten_list"
                        ;;
                *)
 -                      output git cherry-pick "$@" ||
 +                      output eval git cherry-pick "$strategy_args" "$@" ||
                                die_with_patch $sha1 "Could not pick $sha1"
                        ;;
                esac
@@@ -639,16 -628,17 +639,16 @@@ do_next () 
                "$GIT_DIR"/hooks/post-rewrite rebase < "$rewritten_list"
                true # we don't care if this hook failed
        fi &&
 -      rm -rf "$state_dir" &&
 -      git gc --auto &&
        warn "Successfully rebased and updated $head_name."
  
 -      exit
 +      return 1 # not failure; just to break the do_rest loop
  }
  
 +# can only return 0, when the infinite loop breaks
  do_rest () {
        while :
        do
 -              do_next
 +              do_next || break
        done
  }
  
@@@ -700,22 -690,8 +700,22 @@@ rearrange_squash () 
                case "$message" in
                "squash! "*|"fixup! "*)
                        action="${message%%!*}"
 -                      rest="${message#*! }"
 -                      echo "$sha1 $action $rest"
 +                      rest=$message
 +                      prefix=
 +                      # skip all squash! or fixup! (but save for later)
 +                      while :
 +                      do
 +                              case "$rest" in
 +                              "squash! "*|"fixup! "*)
 +                                      prefix="$prefix${rest%%!*},"
 +                                      rest="${rest#*! }"
 +                                      ;;
 +                              *)
 +                                      break
 +                                      ;;
 +                              esac
 +                      done
 +                      echo "$sha1 $action $prefix $rest"
                        # if it's a single word, try to resolve to a full sha1 and
                        # emit a second copy. This allows us to match on both message
                        # and on sha1 prefix
                                if test -n "$fullsha"; then
                                        # prefix the action to uniquely identify this line as
                                        # intended for full sha1 match
 -                                      echo "$sha1 +$action $fullsha"
 +                                      echo "$sha1 +$action $prefix $fullsha"
                                fi
                        fi
                esac
                esac
                printf '%s\n' "$pick $sha1 $message"
                used="$used$sha1 "
 -              while read -r squash action msg_content
 +              while read -r squash action msg_prefix msg_content
                do
                        case " $used" in
                        *" $squash "*) continue ;;
                                case "$message" in "$msg_content"*) emit=1;; esac ;;
                        esac
                        if test $emit = 1; then
 -                              printf '%s\n' "$action $squash $action! $msg_content"
 +                              real_prefix=$(echo "$msg_prefix" | sed "s/,/! /g")
 +                              printf '%s\n' "$action $squash ${real_prefix}$msg_content"
                                used="$used$squash "
                        fi
                done <"$1.sq"
@@@ -830,13 -805,11 +830,13 @@@ first and then run 'git rebase --contin
  
        require_clean_work_tree "rebase"
        do_rest
 +      return 0
        ;;
  skip)
        git rerere clear
  
        do_rest
 +      return 0
        ;;
  edit-todo)
        git stripspace --strip-comments <"$todo" >"$todo".new
@@@ -864,12 -837,15 +864,15 @@@ comment_for_reflog star
  
  if test ! -z "$switch_to"
  then
+       GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to"
        output git checkout "$switch_to" -- ||
-               die "Could not checkout $switch_to"
+       die "Could not checkout $switch_to"
+       comment_for_reflog start
  fi
  
  orig_head=$(git rev-parse --verify HEAD) || die "No HEAD?"
 -mkdir "$state_dir" || die "Could not create temporary $state_dir"
 +mkdir -p "$state_dir" || die "Could not create temporary $state_dir"
  
  : > "$state_dir"/interactive || die "Could not mark as interactive"
  write_basic_state
@@@ -1007,6 -983,7 +1010,7 @@@ has_action "$todo" |
  
  test -d "$rewritten" || test -n "$force_rebase" || skip_unnecessary_picks
  
+ GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name"
  output git checkout $onto || die_abort "could not detach HEAD"
  git update-ref ORIG_HEAD $orig_head
  do_rest
diff --combined git-rebase.sh
index 81b0346a5da2386c94f72ac777f11887fef7fa70,79f526eb9a9e5859cb09d88913228beb62dd4405..0039ecfb407960444c31d48767b65cf773a3243a
@@@ -13,7 -13,6 +13,7 @@@ git-rebase --continue | --abort | --ski
   Available options are
  v,verbose!         display a diffstat of what changed upstream
  q,quiet!           be quiet. implies --no-stat
 +autostash!         automatically stash/stash pop before and after
  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
@@@ -65,7 -64,6 +65,7 @@@ apply_dir="$GIT_DIR"/rebase-appl
  verbose=
  diffstat=
  test "$(git config --bool rebase.stat)" = true && diffstat=t
 +autostash="$(git config --bool rebase.autostash || echo false)"
  git_am_opt=
  rebase_root=
  force_rebase=
@@@ -84,8 -82,6 +84,8 @@@ keep_empty
  test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
  
  read_basic_state () {
 +      test -f "$state_dir/head-name" &&
 +      test -f "$state_dir/onto" &&
        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
@@@ -147,26 -143,6 +147,26 @@@ move_to_original_branch () 
        esac
  }
  
 +finish_rebase () {
 +      if test -f "$state_dir/autostash"
 +      then
 +              stash_sha1=$(cat "$state_dir/autostash")
 +              if git stash apply $stash_sha1 2>&1 >/dev/null
 +              then
 +                      echo "$(gettext 'Applied autostash.')"
 +              else
 +                      git stash store -m "autostash" -q $stash_sha1 ||
 +                      die "$(eval_gettext "Cannot store \$stash_sha1")"
 +                      gettext 'Applying autostash resulted in conflicts.
 +Your changes are safe in the stash.
 +You can run "git stash pop" or "git stash drop" it at any time.
 +'
 +              fi
 +      fi
 +      git gc --auto &&
 +      rm -rf "$state_dir"
 +}
 +
  run_specific_rebase () {
        if [ "$interactive_rebase" = implied ]; then
                GIT_EDITOR=:
                autosquash=
        fi
        . git-rebase--$type
 +      ret=$?
 +      if test $ret -eq 0
 +      then
 +              finish_rebase
 +      fi
 +      exit $ret
  }
  
  run_pre_rebase_hook () {
@@@ -271,9 -241,6 +271,9 @@@ d
        --stat)
                diffstat=t
                ;;
 +      --autostash)
 +              autostash=true
 +              ;;
        -v)
                verbose=t
                diffstat=t
@@@ -374,7 -341,7 +374,7 @@@ abort
                ;;
        esac
        output git reset --hard $orig_head
 -      rm -r "$state_dir"
 +      finish_rebase
        exit
        ;;
  edit-todo)
@@@ -433,7 -400,7 +433,7 @@@ the
                shift
                ;;
        esac
 -      upstream=`git rev-parse --verify "${upstream_name}^0"` ||
 +      upstream=$(peel_committish "${upstream_name}") ||
        die "$(eval_gettext "invalid upstream \$upstream_name")"
        upstream_arg="$upstream_name"
  else
@@@ -469,7 -436,7 +469,7 @@@ case "$onto_name" i
        fi
        ;;
  *)
 -      onto=$(git rev-parse --verify "${onto_name}^0") ||
 +      onto=$(peel_committish "$onto_name") ||
        die "$(eval_gettext "Does not point to a valid commit: \$onto_name")"
        ;;
  esac
@@@ -513,18 -480,6 +513,18 @@@ case "$#" i
        ;;
  esac
  
 +if test "$autostash" = true && ! (require_clean_work_tree) 2>/dev/null
 +then
 +      stash_sha1=$(git stash create "autostash") ||
 +      die "$(gettext 'Cannot autostash')"
 +
 +      mkdir -p "$state_dir" &&
 +      echo $stash_sha1 >"$state_dir/autostash" &&
 +      stash_abbrev=$(git rev-parse --short $stash_sha1) &&
 +      echo "$(eval_gettext 'Created autostash: $stash_abbrev')" &&
 +      git reset --hard
 +fi
 +
  require_clean_work_tree "rebase" "$(gettext "Please commit or stash them.")"
  
  # Now we are rebasing commits $upstream..$orig_head (or with --root,
@@@ -542,9 -497,10 +542,11 @@@ the
        if test -z "$force_rebase"
        then
                # Lazily switch to the target branch if needed...
-               test -z "$switch_to" || git checkout "$switch_to" --
+               test -z "$switch_to" ||
+               GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to" \
+                       git checkout "$switch_to" --
                say "$(eval_gettext "Current branch \$branch_name is up to date.")"
 +              finish_rebase
                exit 0
        else
                say "$(eval_gettext "Current branch \$branch_name is up to date, rebase forced.")"
@@@ -568,7 -524,9 +570,9 @@@ test "$type" = interactive && run_speci
  
  # 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_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" \
+       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
@@@ -577,7 -535,6 +581,7 @@@ if test "$mb" = "$orig_head
  then
        say "$(eval_gettext "Fast-forwarded \$branch_name to \$onto_name.")"
        move_to_original_branch
 +      finish_rebase
        exit 0
  fi
  
index 8a6ec039fe57f6a042fb3fe2e3f4c5807cfe4d68,971e21414ce2847a7b54a8bf122ab3f57e4868b3..49ccb38f8856e6e5fa00961c6e9117f94c6ae233
@@@ -477,11 -477,19 +477,11 @@@ test_expect_success 'interrupted squas
        test $one = $(git rev-parse HEAD~2)
  '
  
 -test_expect_success 'ignore patch if in upstream' '
 -      HEAD=$(git rev-parse HEAD) &&
 -      git checkout -b has-cherry-picked HEAD^ &&
 +test_expect_success '--continue tries to commit, even for "edit"' '
        echo unrelated > file7 &&
        git add file7 &&
        test_tick &&
        git commit -m "unrelated change" &&
 -      git cherry-pick $HEAD &&
 -      EXPECT_COUNT=1 git rebase -i $HEAD &&
 -      test $HEAD = $(git rev-parse HEAD^)
 -'
 -
 -test_expect_success '--continue tries to commit, even for "edit"' '
        parent=$(git rev-parse HEAD^) &&
        test_tick &&
        FAKE_LINES="edit 1" git rebase -i HEAD^ &&
@@@ -684,7 -692,7 +684,7 @@@ test_expect_success 'rebase -i can cop
        test_commit n2 &&
        test_commit n3 &&
        git notes add -m"a note" n3 &&
 -      git rebase --onto n1 n2 &&
 +      git rebase -i --onto n1 n2 &&
        test "a note" = "$(git notes show HEAD)"
  '
  
@@@ -926,6 -934,21 +926,21 @@@ test_expect_success 'rebase --edit-tod
        test L = $(git cat-file commit HEAD | sed -ne \$p)
  '
  
+ test_expect_success 'rebase -i produces readable reflog' '
+       git reset --hard &&
+       git branch -f branch-reflog-test H &&
+       git rebase -i --onto I F branch-reflog-test &&
+       cat >expect <<-\EOF &&
+       rebase -i (start): checkout I
+       rebase -i (pick): G
+       rebase -i (pick): H
+       rebase -i (finish): returning to refs/heads/branch-reflog-test
+       EOF
+       tail -n 4 .git/logs/HEAD |
+       sed -e "s/.*    //" >actual &&
+       test_cmp expect actual
+ '
  test_expect_success 'rebase -i respects core.commentchar' '
        git reset --hard &&
        git checkout E^0 &&
        test B = $(git cat-file commit HEAD^ | sed -ne \$p)
  '
  
 +test_expect_success 'rebase -i, with <onto> and <upstream> specified as :/quuxery' '
 +      test_when_finished "git branch -D torebase" &&
 +      git checkout -b torebase branch1 &&
 +      upstream=$(git rev-parse ":/J") &&
 +      onto=$(git rev-parse ":/A") &&
 +      git rebase --onto $onto $upstream &&
 +      git reset --hard branch1 &&
 +      git rebase --onto ":/A" ":/J" &&
 +      git checkout branch1
 +'
 +
 +test_expect_success 'rebase -i with --strategy and -X' '
 +      git checkout -b conflict-merge-use-theirs conflict-branch &&
 +      git reset --hard HEAD^ &&
 +      echo five >conflict &&
 +      echo Z >file1 &&
 +      git commit -a -m "one file conflict" &&
 +      EDITOR=true git rebase -i --strategy=recursive -Xours conflict-branch &&
 +      test $(git show conflict-branch:conflict) = $(cat conflict) &&
 +      test $(cat file1) = Z
 +'
 +
  test_done