You can keep your buffers in sRGB and convert from gamma to linear in the shader when reading a texture, and back to gamma on output. Newer GPUs even have hardware support for doing these conversions automatically. In Direct3D 10/11 you can activate this by setting up your textures and render targets with sRGB formats. It also works with blending (blending will be done in linear space).
Older (Direct3D 9) GPUs may also support gamma conversions on read and write, but still do blending in linear space, which limits the usefulness of this approach, since e.g. additive blending for accumulating light will not be correct.
Beyond that, if 8-bit sRGB isn't enough precision for you (e.g. you're doing math that introduces banding even in 8-bit sRGB, or you want to do HDR) then floating-point render targets are probably the best way.
Some GPUs/platforms support integer render targets with more than 8 bits per channel. For example, there is an R10G10B10A2 format seen sometimes. However, 10 bits still probably aren't enough to avoid the banding. This article calculates that the a minimum linear-space precision of 12 bits is needed to match 8 bits of sRGB. Some GPUs even have a 16-bit integer render target format, but I don't think this is widely supported, and I'm not sure if you can do blending, bilinear filtering, etc. with these render targets.
It's also possible to use 8-bit framebuffers with the alpha channel used to improve precision, as in LogLUV or RGBM. But again, blending does not work with such encodings. Alpha compositing may work acceptably, but additive blending does not, so accumulating lights in such formats is challenging. You have to avoid using hardware blending and write shaders that decode, update, and re-encode the format.