diff --git a/Library/Homebrew/cmd/update-bash.sh b/Library/Homebrew/cmd/update-bash.sh
new file mode 100755
index 0000000000000000000000000000000000000000..83355202b656759f9688d14c752483ac24134327
--- /dev/null
+++ b/Library/Homebrew/cmd/update-bash.sh
@@ -0,0 +1,280 @@
+#!/bin/bash
+
+if [ -z "$HOMEBREW_BREW_FILE" ]
+then
+  echo "Error: $(basename "$0") must be called from brew!" >&2
+  exit 1
+fi
+
+brew() {
+  "$HOMEBREW_BREW_FILE" "$@"
+}
+
+which_git() {
+  local which_git
+  which_git="$(which git 2>/dev/null)"
+  if [ -n "$which_git" ] && [ "/usr/bin/git" = "$which_git" ]
+  then
+    local active_developer_dir
+    active_developer_dir="$('/usr/bin/xcode-select' -print-path 2>/dev/null)"
+    if [ -n "$active_developer_dir" ] && [ -x "$active_developer_dir/usr/bin/git" ]
+    then
+      which_git="$active_developer_dir/usr/bin/git"
+    else
+      which_git=""
+    fi
+  fi
+  echo "$which_git"
+}
+
+git_init_if_necessary() {
+  if ! [ -d ".git" ]
+  then
+    git init -q
+    git config --bool core.autocrlf false
+    git config remote.origin.url https://github.com/Homebrew/homebrew.git
+    git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
+  fi
+
+  if git remote show origin -n | grep -q "mxcl/homebrew"
+  then
+    git remote set-url origin https://github.com/Homebrew/homebrew.git
+    git remote set-url --delete origin ".*mxcl\/homebrew.*"
+  fi
+}
+
+repo_var() {
+  echo "$1" |
+    sed -e "s|$HOMEBREW_PREFIX||g" \
+        -e 's|Library/Taps/||g' \
+        -e 's|[^a-z0-9]|_|g' |
+    tr "[:lower:]" "[:upper:]"
+}
+
+upstream_branch() {
+  local upstream_branch
+  upstream_branch="$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null |
+                     sed -e 's|refs/remotes/origin/||' )"
+  [ -z "$upstream_branch" ] && upstream_branch="master"
+  echo "$upstream_branch"
+}
+
+read_current_revision() {
+  git rev-parse -q --verify HEAD
+}
+
+# Don't warn about QUIET_ARGS; they need to be unquoted.
+# shellcheck disable=SC2086
+pop_stash() {
+  [ -z "$STASHED" ] && return
+  git stash pop $QUIET_ARGS
+  if [ -n "$HOMEBREW_VERBOSE" ]
+  then
+    echo "Restoring your stashed changes to $DIR:"
+    git status --short --untracked-files
+  fi
+  unset STASHED
+}
+
+pop_stash_message() {
+  [ -z "$STASHED" ] && return
+  echo "To restore the stashed changes to $DIR run:"
+  echo "  'cd $DIR && git stash pop'"
+  unset STASHED
+}
+
+# Don't warn about QUIET_ARGS; they need to be unquoted.
+# shellcheck disable=SC2086
+reset_on_interrupt() {
+  [ -z "$INITIAL_BRANCH" ] || git checkout "$INITIAL_BRANCH"
+  git reset --hard "$INITIAL_REVISION" $QUIET_ARGS
+  if [ -n "$INITIAL_BRANCH" ]
+  then
+    pop_stash
+  else
+    pop_stash_message
+  fi
+}
+
+# Don't warn about QUIET_ARGS; they need to be unquoted.
+# shellcheck disable=SC2086
+pull() {
+  local DIR="$1"
+  cd "$DIR" || return
+  TAP_VAR=$(repo_var "$DIR")
+  unset STASHED
+
+  # The upstream repository's default branch may not be master;
+  # check refs/remotes/origin/HEAD to see what the default
+  # origin branch name is, and use that. If not set, fall back to "master".
+  INITIAL_BRANCH="$(git symbolic-ref --short HEAD 2>/dev/null)"
+  UPSTREAM_BRANCH="$(upstream_branch)"
+
+  if [ -n "$(git status --untracked-files=all --porcelain 2>/dev/null)" ]
+  then
+    if [ -n "$HOMEBREW_VERBOSE" ]
+    then
+      echo "Stashing uncommitted changes to $DIR."
+      git status --short --untracked-files=all
+    fi
+    git -c "user.email=brew-update@localhost" \
+        -c "user.name=brew update" \
+        stash save --include-untracked $QUIET_ARGS
+    git reset --hard $QUIET_ARGS
+    STASHED="1"
+  fi
+
+  # Used for testing purposes, e.g., for testing formula migration after
+  # renaming it in the currently checked-out branch. To test run
+  # "brew update --simulate-from-current-branch"
+  if [ -n "$HOMEBREW_SIMULATE_FROM_CURRENT_BRANCH" ]
+  then
+    INITIAL_REVISION="$(git rev-parse -q --verify "$(upstream_branch)")"
+    CURRENT_REVISION="$(read_current_revision)"
+    export HOMEBREW_UPDATE_AFTER"$TAP_VAR"="$(git rev-parse "$UPSTREAM_BRANCH")"
+    if ! git merge-base --is-ancestor "$INITIAL_REVISION" "$CURRENT_REVISION"
+    then
+      echo "Your HEAD is not a descendant of $UPSTREAM_BRANCH!" >&2
+      exit 1
+    fi
+    return
+  fi
+
+  if [ "$INITIAL_BRANCH" != "$UPSTREAM_BRANCH" ] && [ -n "$INITIAL_BRANCH" ]
+  then
+    # Recreate and check out `#{upstream_branch}` if unable to fast-forward
+    # it to `origin/#{@upstream_branch}`. Otherwise, just check it out.
+    if git merge-base --is-ancestor "$UPSTREAM_BRANCH" "origin/$UPSTREAM_BRANCH" &>/dev/null
+    then
+      git checkout --force "$UPSTREAM_BRANCH" $QUIET_ARGS
+    else
+      git checkout --force -B "$UPSTREAM_BRANCH" "origin/$UPSTREAM_BRANCH" $QUIET_ARGS
+    fi
+  fi
+
+  INITIAL_REVISION="$(read_current_revision)"
+
+  # ensure we don't munge line endings on checkout
+  git config core.autocrlf false
+
+  trap reset_on_interrupt SIGINT
+
+  if [ -n "$HOMEBREW_REBASE" ]
+  then
+    git rebase $QUIET_ARGS "origin/$UPSTREAM_BRANCH"
+  else
+    git merge --no-edit --ff $QUIET_ARGS "origin/$UPSTREAM_BRANCH"
+  fi
+
+  trap - SIGINT
+
+  CURRENT_REVISION="$(read_current_revision)"
+  export HOMEBREW_UPDATE_AFTER"$TAP_VAR"="$(git rev-parse "$UPSTREAM_BRANCH")"
+
+  if [ "$INITIAL_BRANCH" != "$UPSTREAM_BRANCH" ] && [ -n "$INITIAL_BRANCH" ]
+  then
+    git checkout "$INITIAL_BRANCH" $QUIET_ARGS
+    pop_stash
+  else
+    pop_stash_message
+  fi
+}
+
+update-bash() {
+  if [ -z "$HOMEBREW_DEVELOPER" ]
+  then
+    echo "This command is currently only for Homebrew developers' use." >&2
+    exit 1
+  fi
+
+  for i in "$@"
+  do
+    case "$i" in
+      update|update-bash) shift ;;
+      --help) brew update --help; exit $? ;;
+      --verbose) HOMEBREW_VERBOSE=1 ;;
+      --debug) HOMEBREW_DEBUG=1;;
+      --rebase) HOMEBREW_REBASE=1 ;;
+      --simulate-from-current-branch) HOMEBREW_SIMULATE_FROM_CURRENT_BRANCH=1 ;;
+      --*) ;;
+      -*v*) HOMEBREW_VERBOSE=1 ;;
+      -*v*) HOMEBREW_DEBUG=1 ;;
+      -*) ;;
+      *)
+        echo "This command updates brew itself, and does not take formula names." >&2
+        echo "Use 'brew upgrade <formula>'." >&2
+        exit 1
+        ;;
+    esac
+  done
+
+  if [ -n "$HOMEBREW_DEBUG" ]
+  then
+    set -x
+  fi
+
+  # check permissions
+  if [ "$HOMEBREW_PREFIX" = "/usr/local" ] && ! test -w /usr/local
+  then
+    echo "Error: /usr/local must be writable!" >&2
+    exit 1
+  fi
+
+  if ! test -w "$HOMEBREW_REPOSITORY"
+  then
+    echo "Error: $HOMEBREW_REPOSITORY must be writable!" >&2
+    exit 1
+  fi
+
+  if [ -z "$(which_git)" ]
+  then
+    brew install git
+    if [ -z "$(which_git)" ]
+    then
+      echo "Error: Git must be installed and in your PATH!" >&2
+      exit 1
+    fi
+  fi
+
+  if [ -z "$HOMEBREW_VERBOSE" ]
+  then
+    QUIET_ARGS="-q"
+  fi
+
+  # ensure GIT_CONFIG is unset as we need to operate on .git/config
+  unset GIT_CONFIG
+
+  cd "$HOMEBREW_REPOSITORY" || {
+    echo "Error: failed to cd to $HOMEBREW_REPOSITORY!" >&2
+    exit 1
+  }
+  git_init_if_necessary
+
+  for DIR in "$HOMEBREW_REPOSITORY" "$HOMEBREW_LIBRARY"/Taps/*/*
+  do
+    [ -d "$DIR/.git" ] || continue
+    cd "$DIR" || continue
+    TAP_VAR=$(repo_var "$DIR")
+    export HOMEBREW_UPDATE_BEFORE"$TAP_VAR"="$(git rev-parse "$(upstream_branch)")"
+    UPSTREAM_BRANCH="$(upstream_branch)"
+    # the refspec ensures that the default upstream branch gets updated
+    git fetch $QUIET_ARGS origin \
+      "refs/heads/$UPSTREAM_BRANCH:refs/remotes/origin/$UPSTREAM_BRANCH" &
+  done
+
+  wait
+
+  for DIR in "$HOMEBREW_REPOSITORY" "$HOMEBREW_LIBRARY"/Taps/*/*
+  do
+    [ -d "$DIR/.git" ] || continue
+    pull "$DIR"
+  done
+
+  cd "$HOMEBREW_REPOSITORY" || {
+    echo "Error: failed to cd to $HOMEBREW_REPOSITORY!" >&2
+    exit 1
+  }
+
+  brew update-report "$@"
+  return $?
+}
diff --git a/Library/Homebrew/cmd/update-report.rb b/Library/Homebrew/cmd/update-report.rb
new file mode 100644
index 0000000000000000000000000000000000000000..b40aae4223f78c670d7df0b1bb7f2affe09fea16
--- /dev/null
+++ b/Library/Homebrew/cmd/update-report.rb
@@ -0,0 +1,351 @@
+require "cmd/tap"
+require "formula_versions"
+require "migrator"
+require "formulary"
+require "descriptions"
+
+module Homebrew
+  def update_report
+    unless ENV["HOMEBREW_DEVELOPER"]
+      odie "This command is currently only for Homebrew developers' use."
+    end
+
+    # migrate to new directories based tap structure
+    migrate_taps
+
+    report = Report.new
+    master_updater = Reporter.new(HOMEBREW_REPOSITORY)
+    master_updated = master_updater.updated?
+    if master_updated
+      initial_short = shorten_revision(master_updater.initial_revision)
+      current_short = shorten_revision(master_updater.current_revision)
+      puts "Updated Homebrew from #{initial_short} to #{current_short}."
+    end
+    report.update(master_updater.report)
+
+    # rename Taps directories
+    # this procedure will be removed in the future if it seems unnecessasry
+    rename_taps_dir_if_necessary
+
+    updated_taps = []
+    Tap.each do |tap|
+      tap.path.cd do
+        updater = Reporter.new(tap.path)
+        updated_taps << tap.name if updater.updated?
+        report.update(updater.report) do |_key, oldval, newval|
+          oldval.concat(newval)
+        end
+      end
+    end
+    unless updated_taps.empty?
+      puts "Updated #{updated_taps.size} tap#{plural(updated_taps.size)} " \
+           "(#{updated_taps.join(", ")})."
+    end
+    puts "Already up-to-date." unless master_updated || !updated_taps.empty?
+
+    Tap.clear_cache
+    Tap.each(&:link_manpages)
+
+    # automatically tap any migrated formulae's new tap
+    report.select_formula(:D).each do |f|
+      next unless (dir = HOMEBREW_CELLAR/f).exist?
+      migration = TAP_MIGRATIONS[f]
+      next unless migration
+      tap = Tap.fetch(*migration.split("/"))
+      tap.install unless tap.installed?
+
+      # update tap for each Tab
+      tabs = dir.subdirs.map { |d| Tab.for_keg(Keg.new(d)) }
+      next if tabs.first.source["tap"] != "Homebrew/homebrew"
+      tabs.each { |tab| tab.source["tap"] = "#{tap.user}/homebrew-#{tap.repo}" }
+      tabs.each(&:write)
+    end if load_tap_migrations
+
+    load_formula_renames
+    report.update_renamed
+
+    # Migrate installed renamed formulae from core and taps.
+    report.select_formula(:R).each do |oldname, newname|
+      if oldname.include?("/")
+        user, repo, oldname = oldname.split("/", 3)
+        newname = newname.split("/", 3).last
+      else
+        user = "homebrew"
+        repo = "homebrew"
+      end
+
+      next unless (dir = HOMEBREW_CELLAR/oldname).directory? && !dir.subdirs.empty?
+
+      begin
+        f = Formulary.factory("#{user}/#{repo}/#{newname}")
+      # short term fix to prevent situation like https://github.com/Homebrew/homebrew/issues/45616
+      rescue Exception
+      end
+
+      next unless f
+
+      begin
+        migrator = Migrator.new(f)
+        migrator.migrate
+      rescue Migrator::MigratorDifferentTapsError
+      end
+    end
+
+    if report.empty?
+      puts "No changes to formulae." if master_updated || !updated_taps.empty?
+    else
+      report.dump
+    end
+    Descriptions.update_cache(report)
+  end
+
+  private
+
+  def shorten_revision(revision)
+    `git rev-parse --short #{revision}`.chomp
+  end
+
+  def rename_taps_dir_if_necessary
+    Dir.glob("#{HOMEBREW_LIBRARY}/Taps/*/") do |tapd|
+      begin
+        if File.directory?(tapd + "/.git")
+          tapd_basename = File.basename(tapd)
+          if tapd_basename.include?("-")
+            # only replace the *last* dash: yes, tap filenames suck
+            user, repo = tapd_basename.reverse.sub("-", "/").reverse.split("/")
+
+            FileUtils.mkdir_p("#{HOMEBREW_LIBRARY}/Taps/#{user.downcase}")
+            FileUtils.mv(tapd, "#{HOMEBREW_LIBRARY}/Taps/#{user.downcase}/homebrew-#{repo.downcase}")
+
+            if tapd_basename.count("-") >= 2
+              opoo "Homebrew changed the structure of Taps like <someuser>/<sometap>. "\
+                + "So you may need to rename #{HOMEBREW_LIBRARY}/Taps/#{user.downcase}/homebrew-#{repo.downcase} manually."
+            end
+          else
+            opoo "Homebrew changed the structure of Taps like <someuser>/<sometap>. "\
+              "#{tapd} is incorrect name format. You may need to rename it like <someuser>/<sometap> manually."
+          end
+        end
+      rescue => ex
+        onoe ex.message
+        next # next tap directory
+      end
+    end
+  end
+
+  def load_tap_migrations
+    load "tap_migrations.rb"
+  rescue LoadError
+    false
+  end
+
+  def load_formula_renames
+    load "formula_renames.rb"
+  rescue LoadError
+    false
+  end
+end
+
+class Reporter
+  attr_reader :initial_revision, :current_revision, :repository
+
+  def self.repository_variable(repository)
+    repository.to_s.
+      gsub("#{HOMEBREW_PREFIX}", "").
+      gsub("Library/Taps/", "").
+      gsub(/[^a-z0-9]/, "_").
+      upcase
+  end
+
+  def initialize(repository)
+    @repository = repository
+
+    repo_var = Reporter.repository_variable(@repository)
+    initial_revision_var = "HOMEBREW_UPDATE_BEFORE#{repo_var}"
+    @initial_revision = ENV[initial_revision_var].to_s
+    if @initial_revision.empty?
+      raise "#{initial_revision_var} is unset!" if ARGV.homebrew_developer?
+      raise "update-report should not be called directly!"
+    end
+
+    current_revision_var = "HOMEBREW_UPDATE_AFTER#{repo_var}"
+    @current_revision = ENV[current_revision_var].to_s
+    if @current_revision.empty?
+      raise "#{current_revision_var} is unset!" if ARGV.homebrew_developer?
+      raise "update-report should not be called directly!"
+    end
+  end
+
+  def report
+    map = Hash.new { |h, k| h[k] = [] }
+
+    if initial_revision && initial_revision != current_revision
+      wc_revision = read_current_revision
+
+      diff.each_line do |line|
+        status, *paths = line.split
+        src = paths.first
+        dst = paths.last
+
+        next unless File.extname(dst) == ".rb"
+        next unless paths.any? { |p| File.dirname(p) == formula_directory }
+
+        case status
+        when "A", "D"
+          map[status.to_sym] << repository.join(src)
+        when "M"
+          file = repository.join(src)
+          begin
+            formula = Formulary.factory(file)
+            new_version = if wc_revision == current_revision
+              formula.pkg_version
+            else
+              FormulaVersions.new(formula).formula_at_revision(@current_revision, &:pkg_version)
+            end
+            old_version = FormulaVersions.new(formula).formula_at_revision(@initial_revision, &:pkg_version)
+            next if new_version == old_version
+          # short term fix to prevent situation like https://github.com/Homebrew/homebrew/issues/45616
+          rescue Exception => e
+            onoe e if ARGV.homebrew_developer?
+          end
+          map[:M] << file
+        when /^R\d{0,3}/
+          map[:D] << repository.join(src) if File.dirname(src) == formula_directory
+          map[:A] << repository.join(dst) if File.dirname(dst) == formula_directory
+        end
+      end
+    end
+
+    map
+  end
+
+  def updated?
+    initial_revision && initial_revision != current_revision
+  end
+
+  private
+
+  def formula_directory
+    if repository == HOMEBREW_REPOSITORY
+      "Library/Formula"
+    elsif repository.join("Formula").directory?
+      "Formula"
+    elsif repository.join("HomebrewFormula").directory?
+      "HomebrewFormula"
+    else
+      "."
+    end
+  end
+
+  def read_current_revision
+    `git rev-parse -q --verify HEAD`.chomp
+  end
+
+  def diff
+    Utils.popen_read(
+      "git", "diff-tree", "-r", "--name-status", "--diff-filter=AMDR",
+      "-M85%", initial_revision, current_revision
+    )
+  end
+
+  def `(cmd)
+    out = super
+    unless $?.success?
+      $stderr.puts(out) unless out.empty?
+      raise ErrorDuringExecution.new(cmd)
+    end
+    ohai(cmd, out) if ARGV.verbose?
+    out
+  end
+end
+
+class Report
+  def initialize
+    @hash = {}
+  end
+
+  def fetch(*args, &block)
+    @hash.fetch(*args, &block)
+  end
+
+  def update(*args, &block)
+    @hash.update(*args, &block)
+  end
+
+  def empty?
+    @hash.empty?
+  end
+
+  def dump
+    # Key Legend: Added (A), Copied (C), Deleted (D), Modified (M), Renamed (R)
+
+    dump_formula_report :A, "New Formulae"
+    dump_formula_report :M, "Updated Formulae"
+    dump_formula_report :R, "Renamed Formulae"
+    dump_formula_report :D, "Deleted Formulae"
+  end
+
+  def update_renamed
+    renamed_formulae = []
+
+    fetch(:D, []).each do |path|
+      case path.to_s
+      when HOMEBREW_TAP_PATH_REGEX
+        oldname = path.basename(".rb").to_s
+        next unless newname = Tap.fetch($1, $2).formula_renames[oldname]
+      else
+        oldname = path.basename(".rb").to_s
+        next unless newname = CoreFormulaRepository.instance.formula_renames[oldname]
+      end
+
+      if fetch(:A, []).include?(newpath = path.dirname.join("#{newname}.rb"))
+        renamed_formulae << [path, newpath]
+      end
+    end
+
+    unless renamed_formulae.empty?
+      @hash[:A] -= renamed_formulae.map(&:last) if @hash[:A]
+      @hash[:D] -= renamed_formulae.map(&:first) if @hash[:D]
+      @hash[:R] = renamed_formulae
+    end
+  end
+
+  def select_formula(key)
+    fetch(key, []).map do |path, newpath|
+      if path.to_s =~ HOMEBREW_TAP_PATH_REGEX
+        tap = Tap.fetch($1, $2)
+        if newpath
+          ["#{tap}/#{path.basename(".rb")}", "#{tap}/#{newpath.basename(".rb")}"]
+        else
+          "#{tap}/#{path.basename(".rb")}"
+        end
+      elsif newpath
+        ["#{path.basename(".rb")}", "#{newpath.basename(".rb")}"]
+      else
+        path.basename(".rb").to_s
+      end
+    end.sort
+  end
+
+  def dump_formula_report(key, title)
+    formula = select_formula(key).map do |name, new_name|
+      # Format list items of renamed formulae
+      if key == :R
+        new_name = pretty_installed(new_name) if installed?(name)
+        "#{name} -> #{new_name}"
+      else
+        installed?(name) ? pretty_installed(name) : name
+      end
+    end
+
+    unless formula.empty?
+      # Dump formula list.
+      ohai title
+      puts_columns(formula)
+    end
+  end
+
+  def installed?(formula)
+    (HOMEBREW_CELLAR/formula.split("/").last).directory?
+  end
+end
diff --git a/Library/Homebrew/test/test_update_report.rb b/Library/Homebrew/test/test_update_report.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6f3d70afae32c56d699b455a03d74cbc354ed4b7
--- /dev/null
+++ b/Library/Homebrew/test/test_update_report.rb
@@ -0,0 +1,106 @@
+require "testing_env"
+require "cmd/update-report"
+require "formula_versions"
+require "yaml"
+
+class ReportTests < Homebrew::TestCase
+  class ReporterMock < ::Reporter
+    attr_accessor :diff, :expected, :called
+
+    def initialize(repository)
+      repo_var = Reporter.repository_variable(repository)
+      ENV["HOMEBREW_UPDATE_BEFORE#{repo_var}"] = "abcdef12"
+      ENV["HOMEBREW_UPDATE_AFTER#{repo_var}"] = "abcdef12"
+      super
+      @outputs = Hash.new { |h, k| h[k] = [] }
+      @expected = []
+      @called = []
+    end
+
+    def in_repo_expect(cmd, output = "")
+      @expected << cmd
+      @outputs[cmd] << output
+    end
+
+    def `(*args)
+      cmd = args.join(" ")
+      if @expected.include?(cmd) && !@outputs[cmd].empty?
+        @called << cmd
+        @outputs[cmd].shift
+      else
+        raise "#{inspect} unexpectedly called backticks: `#{cmd}`"
+      end
+    end
+    alias_method :safe_system, :`
+    alias_method :system, :`
+
+    def inspect
+      "#<#{self.class.name}>"
+    end
+  end
+
+  def fixture(name)
+    self.class.fixture_data[name] || ""
+  end
+
+  def self.fixture_data
+    @fixture_data ||= YAML.load_file("#{TEST_DIRECTORY}/fixtures/updater_fixture.yaml")
+  end
+
+  def setup
+    @updater = ReporterMock.new(HOMEBREW_REPOSITORY)
+    @report = Report.new
+  end
+
+  def teardown
+    FileUtils.rm_rf HOMEBREW_LIBRARY.join("Taps")
+  end
+
+  def perform_update(fixture_name = "")
+    Formulary.stubs(:factory).returns(stub(:pkg_version => "1.0"))
+    FormulaVersions.stubs(:new).returns(stub(:formula_at_revision => "2.0"))
+    @updater.diff = fixture(fixture_name)
+    @report.update(@updater.report)
+    assert_equal @updater.expected, @updater.called
+  end
+
+  def test_update_homebrew_without_any_changes
+    perform_update
+    assert_empty @report
+  end
+
+  def test_update_homebrew_without_formulae_changes
+    perform_update("update_git_diff_output_without_formulae_changes")
+    assert_empty @report.select_formula(:M)
+    assert_empty @report.select_formula(:A)
+    assert_empty @report.select_formula(:D)
+  end
+
+  def test_update_homebrew_with_changed_filetype
+    perform_update("update_git_diff_output_with_changed_filetype")
+  end
+
+  def test_update_homebrew_with_restructured_tap
+    repo = HOMEBREW_LIBRARY.join("Taps", "foo", "bar")
+    @updater = ReporterMock.new(repo)
+    repo.join("Formula").mkpath
+
+    perform_update("update_git_diff_output_with_restructured_tap")
+  end
+
+  def test_update_homebrew_simulate_homebrew_php_restructuring
+    repo = HOMEBREW_LIBRARY.join("Taps", "foo", "bar")
+    @updater = ReporterMock.new(repo)
+    repo.join("Formula").mkpath
+
+    perform_update("update_git_diff_simulate_homebrew_php_restructuring")
+  end
+
+  def test_update_homebrew_with_tap_formulae_changes
+    repo = HOMEBREW_LIBRARY.join("Taps", "foo", "bar")
+    @updater = ReporterMock.new(repo)
+    repo.join("Formula").mkpath
+
+    perform_update("update_git_diff_output_with_tap_formulae_changes")
+  end
+end