Let me try to explain in more detail.
The standard mechanism you cite does two things: 1) it identifies the hash of the most recent commit before the deadline (as measured by the clock on GitHub’s servers) as the “submission”; 2) it allows further commits after the deadline, whose hashes aren’t separately stored at wall-clock times in the way that is done in (1) at the submission deadline.
We need to consider two cases separately: that where a student submits before the deadline, and that where a student submits after the deadline. If a student submits before the deadline, the “submission” mechanism will at least reveal when a student has modified commit history after the deadline, as the commit hash recorded as the submission won’t match that of the modified history. So (1) is adequate to detect this sort of cheating for submissions before the deadline (but I’d argue that prevention rather than detection is preferable…and protected branches would prevent force pushes).
Now the post-deadline case: in my class, when a student submits after the deadline, I reduce the grade by 10% for each 24-hour period or fraction thereof that elapses between the deadline and when the student submits. To do so, I need a reliable indication of when the student has decided to submit after the deadline. I can’t merely grade the “last” submission after the deadline because it’s impossible to know whether a student intends to make further commits, and worse, if a student submitted before the deadline, and then later pushes a commit to GitHub after the deadline not intending for it to be graded (this is possible; students do all sorts of things unintentionally), there is a risk I could grade the post-deadline commit and apply a lateness penalty when the student may never have intended the post-deadline commit to be a submission at all.
So that there is a clear indication from a student that they intend for a post-deadline commit to be graded, I require students to include a reserved string (“LATESUBMIT”) in their commit log message for a commit after the deadline that they want to be graded. And they’re told only to make one commit with this label–and that if there’s more than one, only the earliest of them will be graded.
If students can force push, they can modify log messages on past commits, and add “LATESUBMIT” to an old commit’s log message in an attempt to create the appearance of a submit date in the past (when the rule in my class is that the time of submission is the time when the student declares that they wish to submit).
I believe students can also force push to change the timestamps on past commits (since these timestamps come from the client that is pushing). That’s another avenue for forging an earlier submission time for submissions made after the deadline.
If it were possible to specify that an organization’s new repos should have all branches protected by default, then force pushes wouldn’t be permitted, and commits to HEAD would be immutable. That would prevent adding “LATESUBMIT” to a commit’s log message after the fact, and would prevent students from changing the commit timestamps of past commits. (It would not, however, prevent students from forging timestamps on new commits to HEAD, so long as the new commits’ timestamps are after the timestamp of HEAD. My grading server could just use the event timestamps on pushes as the time of a submission rather than the commit timestamps, though.)
To be clear, I’m not proposing an intrusive global change to default repo policies on GitHub. All I’m suggesting is offering Organization admins the chance to configure an optional policy of disabling force pushes on all branches of all newly created repos owned by that Organization by default. It may be that other GitHub users, not just Classroom users, find the option of setting such a non-default policy useful–there are many Organizations that find force pushes problematic and want to disable them. I see no reason why this feature should be onerous to implement…and would welcome the reaction of a GitHub developer.
-Brad