Merge branch 'em/newer-freebsd-shells-are-fine-with-returns' into maint
authorJunio C Hamano <gitster@pobox.com>
Wed, 6 Jul 2016 20:06:41 +0000 (13:06 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 6 Jul 2016 20:06:41 +0000 (13:06 -0700)
Comments about misbehaving FreeBSD shells have been clarified with
the version number (9.x and before are broken, newer ones are OK).

* em/newer-freebsd-shells-are-fine-with-returns:
rebase: update comment about FreeBSD /bin/sh

1  2 
git-rebase--interactive.sh
git-rebase--merge.sh
index 6e96abcc3c6b942eed3e8c522f089d823b02a1fa,56d99662f4bf62236328011636f4250d8ca1a57f..05f22e43ccfe485b2a676f96ddec1a99f7a84612
@@@ -77,18 -77,17 +77,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
 +# Work around Git for Windows' Bash whose "read" does not strip CRLF
 +# and leaves CR at the end instead.
 +cr=$(printf "\015")
 +
 +strategy_args=${strategy:+--strategy=$strategy}
 +test -n "$strategy_opts" &&
 +eval '
 +      for strategy_opt in '"$strategy_opts"'
 +      do
 +              strategy_args="$strategy_args -X$(git rev-parse --sq-quote "${strategy_opt#--}")"
 +      done
 +'
  
  GIT_CHERRY_PICK_HELP="$resolvemsg"
  export GIT_CHERRY_PICK_HELP
@@@ -153,21 -152,11 +153,21 @@@ Commands
   s, squash = use commit, but meld into previous commit
   f, fixup = like "squash", but discard this commit's log message
   x, exec = run command (the rest of the line) using shell
 + d, drop = remove commit
  
  These lines can be re-ordered; they are executed from top to bottom.
  
 +EOF
 +      if test $(get_missing_commit_check_level) = error
 +      then
 +              git stripspace --comment-lines >>"$todo" <<\EOF
 +Do not remove any line. Use 'drop' explicitly to remove a commit.
 +EOF
 +      else
 +              git stripspace --comment-lines >>"$todo" <<\EOF
  If you remove a line here THAT COMMIT WILL BE LOST.
  EOF
 +      fi
  }
  
  make_patch () {
  die_with_patch () {
        echo "$1" > "$state_dir"/stopped-sha
        make_patch "$1"
 -      git rerere
        die "$2"
  }
  
@@@ -515,11 -505,7 +515,11 @@@ do_next () 
        rm -f "$msg" "$author_script" "$amend" "$state_dir"/stopped-sha || exit
        read -r command sha1 rest < "$todo"
        case "$command" in
 -      "$comment_char"*|''|noop)
 +      "$comment_char"*|''|noop|drop|d)
 +              mark_action_done
 +              ;;
 +      "$cr")
 +              # Work around CR left by "read" (e.g. with Git for Windows' Bash).
                mark_action_done
                ;;
        pick|p)
  
                mark_action_done
                do_pick $sha1 "$rest"
 -              warn "Stopped at $sha1... $rest"
 +              sha1_abbrev=$(git rev-parse --short $sha1)
 +              warn "Stopped at $sha1_abbrev... $rest"
                exit_with_patch $sha1 0
                ;;
        squash|s|fixup|f)
                read -r command rest < "$todo"
                mark_action_done
                printf 'Executing: %s\n' "$rest"
 -              ${SHELL:-@SHELL_PATH@} -c "$rest" # Actual execution
 +              "${SHELL:-@SHELL_PATH@}" -c "$rest" # Actual execution
                status=$?
                # Run in subshell because require_clean_work_tree can die.
                dirty=f
                git notes copy --for-rewrite=rebase < "$rewritten_list" ||
                true # we don't care if this copying failed
        } &&
 -      if test -x "$GIT_DIR"/hooks/post-rewrite &&
 -              test -s "$rewritten_list"; then
 -              "$GIT_DIR"/hooks/post-rewrite rebase < "$rewritten_list"
 +      hook="$(git rev-parse --git-path hooks/post-rewrite)"
 +      if test -x "$hook" && test -s "$rewritten_list"; then
 +              "$hook" rebase < "$rewritten_list"
                true # we don't care if this hook failed
        fi &&
        warn "Successfully rebased and updated $head_name."
@@@ -734,8 -719,8 +734,8 @@@ transform_todo_ids () 
                        # that do not have a SHA-1 at the beginning of $rest.
                        ;;
                *)
 -                      sha1=$(git rev-parse --verify --quiet "$@" ${rest%% *}) &&
 -                      rest="$sha1 ${rest#* }"
 +                      sha1=$(git rev-parse --verify --quiet "$@" ${rest%%[     ]*}) &&
 +                      rest="$sha1 ${rest#*[    ]}"
                        ;;
                esac
                printf '%s\n' "$command${rest:+ }$rest"
@@@ -755,15 -740,10 +755,15 @@@ collapse_todo_ids() 
  # "pick sha1 fixup!/squash! msg" appears in it so that the latter
  # comes immediately after the former, and change "pick" to
  # "fixup"/"squash".
 +#
 +# Note that if the config has specified a custom instruction format
 +# each log message will be re-retrieved in order to normalize the
 +# autosquash arrangement
  rearrange_squash () {
        # extract fixup!/squash! lines and resolve any referenced sha1's
        while read -r pick sha1 message
        do
 +              test -z "${format}" || message=$(git log -n 1 --format="%s" ${sha1})
                case "$message" in
                "squash! "*|"fixup! "*)
                        action="${message%%!*}"
                *" $sha1 "*) continue ;;
                esac
                printf '%s\n' "$pick $sha1 $message"
 +              test -z "${format}" || message=$(git log -n 1 --format="%s" ${sha1})
                used="$used$sha1 "
                while read -r squash action msg_prefix msg_content
                do
                                case "$message" in "$msg_content"*) emit=1;; esac ;;
                        esac
                        if test $emit = 1; then
 -                              real_prefix=$(echo "$msg_prefix" | sed "s/,/! /g")
 -                              printf '%s\n' "$action $squash ${real_prefix}$msg_content"
 +                              if test -n "${format}"
 +                              then
 +                                      msg_content=$(git log -n 1 --format="${format}" ${squash})
 +                              else
 +                                      msg_content="$(echo "$msg_prefix" | sed "s/,/! /g")$msg_content"
 +                              fi
 +                              printf '%s\n' "$action $squash $msg_content"
                                used="$used$squash "
                        fi
                done <"$1.sq"
@@@ -859,187 -833,13 +859,187 @@@ add_exec_commands () 
        mv "$1.new" "$1"
  }
  
 +# Check if the SHA-1 passed as an argument is a
 +# correct one, if not then print $2 in "$todo".badsha
 +# $1: the SHA-1 to test
 +# $2: the line number of the input
 +# $3: the input filename
 +check_commit_sha () {
 +      badsha=0
 +      if test -z "$1"
 +      then
 +              badsha=1
 +      else
 +              sha1_verif="$(git rev-parse --verify --quiet $1^{commit})"
 +              if test -z "$sha1_verif"
 +              then
 +                      badsha=1
 +              fi
 +      fi
 +
 +      if test $badsha -ne 0
 +      then
 +              line="$(sed -n -e "${2}p" "$3")"
 +              warn "Warning: the SHA-1 is missing or isn't" \
 +                      "a commit in the following line:"
 +              warn " - $line"
 +              warn
 +      fi
 +
 +      return $badsha
 +}
 +
 +# prints the bad commits and bad commands
 +# from the todolist in stdin
 +check_bad_cmd_and_sha () {
 +      retval=0
 +      lineno=0
 +      while read -r command rest
 +      do
 +              lineno=$(( $lineno + 1 ))
 +              case $command in
 +              "$comment_char"*|''|noop|x|exec)
 +                      # Doesn't expect a SHA-1
 +                      ;;
 +              "$cr")
 +                      # Work around CR left by "read" (e.g. with Git for
 +                      # Windows' Bash).
 +                      ;;
 +              pick|p|drop|d|reword|r|edit|e|squash|s|fixup|f)
 +                      if ! check_commit_sha "${rest%%[        ]*}" "$lineno" "$1"
 +                      then
 +                              retval=1
 +                      fi
 +                      ;;
 +              *)
 +                      line="$(sed -n -e "${lineno}p" "$1")"
 +                      warn "Warning: the command isn't recognized" \
 +                              "in the following line:"
 +                      warn " - $line"
 +                      warn
 +                      retval=1
 +                      ;;
 +              esac
 +      done <"$1"
 +      return $retval
 +}
 +
 +# Print the list of the SHA-1 of the commits
 +# from stdin to stdout
 +todo_list_to_sha_list () {
 +      git stripspace --strip-comments |
 +      while read -r command sha1 rest
 +      do
 +              case $command in
 +              "$comment_char"*|''|noop|x|"exec")
 +                      ;;
 +              *)
 +                      long_sha=$(git rev-list --no-walk "$sha1" 2>/dev/null)
 +                      printf "%s\n" "$long_sha"
 +                      ;;
 +              esac
 +      done
 +}
 +
 +# Use warn for each line in stdin
 +warn_lines () {
 +      while read -r line
 +      do
 +              warn " - $line"
 +      done
 +}
 +
 +# Switch to the branch in $into and notify it in the reflog
 +checkout_onto () {
 +      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
 +}
 +
 +get_missing_commit_check_level () {
 +      check_level=$(git config --get rebase.missingCommitsCheck)
 +      check_level=${check_level:-ignore}
 +      # Don't be case sensitive
 +      printf '%s' "$check_level" | tr 'A-Z' 'a-z'
 +}
 +
 +# Check if the user dropped some commits by mistake
 +# Behaviour determined by rebase.missingCommitsCheck.
 +# Check if there is an unrecognized command or a
 +# bad SHA-1 in a command.
 +check_todo_list () {
 +      raise_error=f
 +
 +      check_level=$(get_missing_commit_check_level)
 +
 +      case "$check_level" in
 +      warn|error)
 +              # Get the SHA-1 of the commits
 +              todo_list_to_sha_list <"$todo".backup >"$todo".oldsha1
 +              todo_list_to_sha_list <"$todo" >"$todo".newsha1
 +
 +              # Sort the SHA-1 and compare them
 +              sort -u "$todo".oldsha1 >"$todo".oldsha1+
 +              mv "$todo".oldsha1+ "$todo".oldsha1
 +              sort -u "$todo".newsha1 >"$todo".newsha1+
 +              mv "$todo".newsha1+ "$todo".newsha1
 +              comm -2 -3 "$todo".oldsha1 "$todo".newsha1 >"$todo".miss
 +
 +              # Warn about missing commits
 +              if test -s "$todo".miss
 +              then
 +                      test "$check_level" = error && raise_error=t
 +
 +                      warn "Warning: some commits may have been dropped" \
 +                              "accidentally."
 +                      warn "Dropped commits (newer to older):"
 +
 +                      # Make the list user-friendly and display
 +                      opt="--no-walk=sorted --format=oneline --abbrev-commit --stdin"
 +                      git rev-list $opt <"$todo".miss | warn_lines
 +
 +                      warn "To avoid this message, use \"drop\" to" \
 +                              "explicitly remove a commit."
 +                      warn
 +                      warn "Use 'git config rebase.missingCommitsCheck' to change" \
 +                              "the level of warnings."
 +                      warn "The possible behaviours are: ignore, warn, error."
 +                      warn
 +              fi
 +              ;;
 +      ignore)
 +              ;;
 +      *)
 +              warn "Unrecognized setting $check_level for option" \
 +                      "rebase.missingCommitsCheck. Ignoring."
 +              ;;
 +      esac
 +
 +      if ! check_bad_cmd_and_sha "$todo"
 +      then
 +              raise_error=t
 +      fi
 +
 +      if test $raise_error = t
 +      then
 +              # Checkout before the first commit of the
 +              # rebase: this way git rebase --continue
 +              # will work correctly as it expects HEAD to be
 +              # placed before the commit of the next action
 +              checkout_onto
 +
 +              warn "You can fix this with 'git rebase --edit-todo'."
 +              die "Or you can abort the rebase with 'git rebase --abort'."
 +      fi
 +}
 +
  # The whole contents of this file is run by dot-sourcing it from
  # inside a shell function.  It used to be that "return"s we see
  # below were not inside any function, and expected to return
  # to the function that dot-sourced us.
  #
- # However, FreeBSD /bin/sh misbehaves on such a construct and
- # continues to run the statements that follow such a "return".
+ # However, older (9.x) versions of FreeBSD /bin/sh misbehave on such a
+ # construct and continue to run the statements that follow such a "return".
  # As a work-around, we introduce an extra layer of a function
  # here, and immediately call it after defining it.
  git_rebase__interactive () {
@@@ -1181,10 -981,7 +1181,10 @@@ els
        revisions=$onto...$orig_head
        shortrevisions=$shorthead
  fi
 -git rev-list $merges_option --pretty=oneline --reverse --left-right --topo-order \
 +format=$(git config --get rebase.instructionFormat)
 +# the 'rev-list .. | sed' requires %m to parse; the instruction requires %H to parse
 +git rev-list $merges_option --format="%m%H ${format:-%s}" \
 +      --reverse --left-right --topo-order \
        $revisions ${restrict_revision+^$restrict_revision} | \
        sed -n "s/^>//p" |
  while read -r sha1 rest
@@@ -1234,8 -1031,7 +1234,8 @@@ the
        git rev-list $revisions |
        while read rev
        do
 -              if test -f "$rewritten"/$rev && test "$(sane_grep "$rev" "$state_dir"/not-cherry-picks)" = ""
 +              if test -f "$rewritten"/$rev &&
 +                 ! sane_grep "$rev" "$state_dir"/not-cherry-picks >/dev/null
                then
                        # Use -f2 because if rev-list is telling us this commit is
                        # not worthwhile, we don't want to track its multiple heads,
@@@ -1284,13 -1080,13 +1284,13 @@@ git_sequence_editor "$todo" |
  has_action "$todo" ||
        return 2
  
 +check_todo_list
 +
  expand_todo_ids
  
  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
 +checkout_onto
  do_rest
  
  }
diff --combined git-rebase--merge.sh
index 8d43db9069f5c478fa6cb2deb6cf7d1d37f1e6b2,327b575d840024541c40b7c6da320fa7da33de8d..06a4723d4db3db74ea17ace60d824e83cdee25e9
@@@ -67,9 -67,7 +67,9 @@@ call_merge () 
                GIT_MERGE_VERBOSITY=1 && export GIT_MERGE_VERBOSITY
        fi
        test -z "$strategy" && strategy=recursive
 -      eval 'git-merge-$strategy' $strategy_opts '"$cmt^" -- "$hd" "$cmt"'
 +      # If cmt doesn't have a parent, don't include it as a base
 +      base=$(git rev-parse --verify --quiet $cmt^)
 +      eval 'git-merge-$strategy' $strategy_opts $base ' -- "$hd" "$cmt"'
        rv=$?
        case "$rv" in
        0)
@@@ -96,8 -94,10 +96,8 @@@ finish_rb_merge () 
        if test -s "$state_dir"/rewritten
        then
                git notes copy --for-rewrite=rebase <"$state_dir"/rewritten
 -              if test -x "$GIT_DIR"/hooks/post-rewrite
 -              then
 -                      "$GIT_DIR"/hooks/post-rewrite rebase <"$state_dir"/rewritten
 -              fi
 +              hook="$(git rev-parse --git-path hooks/post-rewrite)"
 +              test -x "$hook" && "$hook" rebase <"$state_dir"/rewritten
        fi
        say All done.
  }
  # below were not inside any function, and expected to return
  # to the function that dot-sourced us.
  #
- # However, FreeBSD /bin/sh misbehaves on such a construct and
- # continues to run the statements that follow such a "return".
+ # However, older (9.x) versions of FreeBSD /bin/sh misbehave on such a
+ # construct and continue to run the statements that follow such a "return".
  # As a work-around, we introduce an extra layer of a function
  # here, and immediately call it after defining it.
  git_rebase__merge () {