Forking a system is, as you suggest, often a good way to provide a layer of security to a consensus system. The thought is that if someone spends some resources to attack the system and put it in a state that the users consider wrong, a new version of that system can be deployed, ideally with any resources still held by the attacker deleted or reassigned, and the users will just ignore the old system and move to the new system.
In practice, forking can mean a few different things.
If you have your own network, like the Bitcoin network or the Ethereum network, you can fork by changing the rules that some of the nodes follow. This splits the system into two different networks, which share the same state at the block before they split, but have divergent state thereafter.
If you're intending your code to run on top of an existing network like Ethereum, you can't change the rules of that network when you fork, and all your data is stored on a single, consistent ledger. Since you can't fork the ledger, you have to somehow create a new data structure on the existing ledger.
One option is that if your resources are all held by the same contract, you can simply deploy a new version of that contract, and everyone will move to that. This works if the main thing the contract is managing is a token, and you (the forking community) are able to persuade anyone interested in that token to move to the new contract. If this is a normal ERC20 token this probably won't work perfectly, as some contracts that talk to the token may not know about the fork, which will likely result in loss of funds, but it may be good enough for your purposes. There is more on the practicalities of this here: https://medium.com/@edmundedgar/what-happens-when-you-try-to-fork-an-ethereum-token-863e3defcf7
Another option is to manage all the branches in a single contract, and always force users to specify the branch. This is the strategy we use in the contract we describe here: https://decentralize.today/get-the-facts-hard-fork-all-the-things-3ea2233da0fd
A third option also maintains the forks in a single contract, but attempts to adjudicate between them to create a "true" fork. This is the strategy used by Augur: When a fork is triggered, users are required to migrate their token ("REP") into one branch or the other branch, and the system eventually treats the branch into which the most REP is migrated as the "true" branch. This has the advantage of exposing a single token interface to other contracts, and not needing other contracts talking to their contract to specify a branch, since there is a "best" branch. The disadvantage is that this process is quite disruptive, so it has to be protected with a system of bonds, which adds complexity and may fail to trigger if the bonds turn out to have been set at the wrong levels. It also can itself be gamed (at a cost) so there is a risk the system will end up in a state where the privileged branch is compromised.
Note that in all cases where there is no "true" branch, the system is likely to be unable to manage external resources like (for a system that runs on top of Ethereum) ETH. All these systems rely on having a native token which can be redefined at will by the community that uses it.