of a hidden ref (by default, such a request is rejected).
        see also `uploadpack.hiderefs`.
 
+uploadpack.keepalive::
+       When `upload-pack` has started `pack-objects`, there may be a
+       quiet period while `pack-objects` prepares the pack. Normally
+       it would output progress information, but if `--quiet` was used
+       for the fetch, `pack-objects` will output nothing at all until
+       the pack data begins. Some clients and networks may consider
+       the server to be hung and give up. Setting this option instructs
+       `upload-pack` to send an empty keepalive packet every
+       `uploadpack.keepalive` seconds. Setting this option to 0
+       disables keepalive packets entirely. The default is 0.
+
 url.<base>.insteadOf::
        Any URL that starts with this value will be rewritten to
        start, instead, with <base>. In cases where some site serves a
 
 static struct object_array want_obj;
 static struct object_array extra_edge_obj;
 static unsigned int timeout;
+static int keepalive = -1;
 /* 0 for no sideband,
  * otherwise maximum packet size (up to 65520 bytes).
  */
        while (1) {
                struct pollfd pfd[2];
                int pe, pu, pollsize;
+               int ret;
 
                reset_timeout();
 
                if (!pollsize)
                        break;
 
-               if (poll(pfd, pollsize, -1) < 0) {
+               ret = poll(pfd, pollsize, 1000 * keepalive);
+               if (ret < 0) {
                        if (errno != EINTR) {
                                error("poll failed, resuming: %s",
                                      strerror(errno));
                        if (sz < 0)
                                goto fail;
                }
+
+               /*
+                * We hit the keepalive timeout without saying anything; send
+                * an empty message on the data sideband just to let the other
+                * side know we're still working on it, but don't have any data
+                * yet.
+                *
+                * If we don't have a sideband channel, there's no room in the
+                * protocol to say anything, so those clients are just out of
+                * luck.
+                */
+               if (!ret && use_sideband) {
+                       static const char buf[] = "0005\1";
+                       write_or_die(1, buf, 5);
+               }
        }
 
        if (finish_command(&pack_objects)) {
 {
        if (!strcmp("uploadpack.allowtipsha1inwant", var))
                allow_tip_sha1_in_want = git_config_bool(var, value);
+       else if (!strcmp("uploadpack.keepalive", var)) {
+               keepalive = git_config_int(var, value);
+               if (!keepalive)
+                       keepalive = -1;
+       }
        return parse_hide_refs_config(var, value, "uploadpack");
 }