This is sometimes needed to work with old scripts that
        expect HEAD to be a symbolic link.
 
+core.alternateRefsCommand::
+       When advertising tips of available history from an alternate, use the shell to
+       execute the specified command instead of linkgit:git-for-each-ref[1]. The
+       first argument is the absolute path of the alternate. Output must contain one
+       hex object id per line (i.e., the same as produce by `git for-each-ref
+       --format='%(objectname)'`).
++
+Note that you cannot generally put `git for-each-ref` directly into the config
+value, as it does not take a repository path as an argument (but you can wrap
+the command above in a shell script).
+
 core.bare::
        If true this repository is assumed to be 'bare' and has no
        working directory associated with it.  If this is the case a
 
--- /dev/null
+#!/bin/sh
+
+test_description='git receive-pack with alternate ref filtering'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       test_commit base &&
+       git clone -s --bare . fork &&
+       git checkout -b public/branch master &&
+       test_commit public &&
+       git checkout -b private/branch master &&
+       test_commit private
+'
+
+extract_haves () {
+       depacketize | perl -lne '/^(\S+) \.have/ and print $1'
+}
+
+test_expect_success 'with core.alternateRefsCommand' '
+       write_script fork/alternate-refs <<-\EOF &&
+               git --git-dir="$1" for-each-ref \
+                       --format="%(objectname)" \
+                       refs/heads/public/
+       EOF
+       test_config -C fork core.alternateRefsCommand alternate-refs &&
+       git rev-parse public/branch >expect &&
+       printf "0000" | git receive-pack fork >actual &&
+       extract_haves <actual >actual.haves &&
+       test_cmp expect actual.haves
+'
+
+test_done
 
 static void fill_alternate_refs_command(struct child_process *cmd,
                                        const char *repo_path)
 {
-       cmd->git_cmd = 1;
-       argv_array_pushf(&cmd->args, "--git-dir=%s", repo_path);
-       argv_array_push(&cmd->args, "for-each-ref");
-       argv_array_push(&cmd->args, "--format=%(objectname)");
+       const char *value;
+
+       if (!git_config_get_value("core.alternateRefsCommand", &value)) {
+               cmd->use_shell = 1;
+
+               argv_array_push(&cmd->args, value);
+               argv_array_push(&cmd->args, repo_path);
+       } else {
+               cmd->git_cmd = 1;
+
+               argv_array_pushf(&cmd->args, "--git-dir=%s", repo_path);
+               argv_array_push(&cmd->args, "for-each-ref");
+               argv_array_push(&cmd->args, "--format=%(objectname)");
+       }
+
        cmd->env = local_repo_env;
        cmd->out = -1;
 }