What about this?
SELECT m.timestamp, m.user, m.message, m.group_id, g.grp_timestamp
FROM messages AS m JOIN
(SELECT group_id, MIN(timestamp) AS grp_timestamp
FROM messages
GROUP BY group_id) AS g ON m.group_id = g.group_id
WHERE m.topic_id = ?
ORDER BY g.grp_timestamp, g.group_id, m.timestamp;
The logic is to identify the earliest timestamp for each group_id in the sub-query (presuming messages with no responses have a valid group_id assigned) and then sort first by the group timestamp, then by group ID (so that if two groups end up with the same timestamp somehow, the messages are still sorted correctly), and then by the message timestamp.
You might want to push the WHERE clause into the sub-select too.
If you want the most recent messages first, then basically, you apply DESC to the ORDER BY clause in the appropriate places.
SELECT m.timestamp, m.user, m.message, m.group_id, g.grp_timestamp
FROM messages AS m JOIN
(SELECT group_id, MIN(timestamp) AS grp_timestamp
FROM messages
GROUP BY group_id) AS g ON m.group_id = g.group_id
WHERE m.topic_id = ?
ORDER BY g.grp_timestamp DESC, g.group_id, m.timestamp DESC;
You might want the group with the most recent response to appear first; in that case, you need to adjust the aggregate from MIN to MAX:
SELECT m.timestamp, m.user, m.message, m.group_id, g.grp_timestamp
FROM messages AS m JOIN
(SELECT group_id, MAX(timestamp) AS grp_timestamp
FROM messages
GROUP BY group_id) AS g ON m.group_id = g.group_id
WHERE m.topic_id = ?
ORDER BY g.grp_timestamp DESC, g.group_id, m.timestamp;
As long as you are OK with the responses appearing in chronological order, I think that does the trick. If the responses must appear in reverse chronological order with the original message appearing first, you have some difficulties. If you tagged the messages with 'L' for 'leader' and 'F' for 'follower' in the messages table, then you can use that column to do the sorting. If you have to dynamically determine whether a message is a leader or follower, you have to work harder.