Happy little accidents

Most of us are human, therefore we are bound to make mistakes. Version control is a tool that keeps us safe, well at least our projects.

Imagine you have a piece of code that is working perfectly fine, but now for some reason, you need to change it. If you are not using version control you might have to backup all of your code before trying anything new. Things like that can keep us from trying out better approaches because we might lose precious work. With version control this is a non issue, you can always go back to a previous state and start over. Or you can branch off and try something completely different that might replace your existing project with a new and improved version. It’s a lot less stressful than the manual copy and paste approach.

In this chapter I want to show you ways to deal with mistakes. No more fear of changing things, you can always back. Version control gives you a couple of extra lives :)

Reverting changes

The most obvious thing that might go wrong in your development process is that you have a lot of changes in your working tree and you have decided that they don’t make the cut. You want to get rid of them.

Here’s an example. Imagine you are writing a novel and some time light at night in some sleep depraved state you decide to rename the novel’s protagonist from “Sakura” to “Humungus”. It surely sounded like a great idea at the time so you fire up your text editor and make a search and replace over the whole project. What you didn’t remember is that the name “Humungus” is already mentioned throughout the novel but it’s late and you decide to go to sleep. The next morning you wake up and realize what a mess you have made. You can’t go search and replace “Humungus” with “Sakura” anymore and your text editor decides that undoing that change is not something it wants to do. Okay, I’m reaching there but let’s pretend, there are situations quite similar to this and some of you might have come across them, I certainly did, and they are no fun.

In a situation like this darcs revert is exactly what you want. It allows you to restore the state of the working tree as if you didn’t make any changes since the last record.

$ cat story.txt
Sakura was looking at her creation. She was quite happy with it.
$ sed -i '' 's/Sakura/Humungus/' story.txt
$ darcs whatsnew
hunk ./story.txt 1
-Sakura was looking at her creation. She was quite happy with it.
+Humungus was looking at her creation. She was quite happy with it.
$ darcs revert
hunk ./story.txt 1
-Sakura was looking at her creation. She was quite happy with it.
+Humungus was looking at her creation. She was quite happy with it.
Shall I revert this change? (1/1)  [ynW...], or ? for more options: y
Do you want to Revert these changes? [Yglqk...], or ? for more options: y
Finished reverting.
$ darcs whatsnew
No changes!

Done! darcs revert will prompt you for any unrecorded change, asking whether it should revert that change or not. Keep in mind that you can always hit ? if you are unsure about what the available options are. Here’s a look at what you can do when reverting.

How to use revert:
y: revert this change
n: don't revert it
w: wait and decide later, defaulting to no

e: interactively edit this change

s: don't revert the rest of the changes to this file
f: revert the rest of the changes to this file

v: view this change in full
p: view this change in full with pager
l: list all selected changes
x: view a summary of this change

d: revert selected changes, skipping all the remaining changes
a: revert all the remaining changes
q: cancel revert

j: skip to next change
k: back up to previous change
g: start over from the first change

?: show this help

<Space>: accept the current default (which is capitalized)

If you just want to get rid of all the unrecorded changes you made to your working tree without being prompted interactively you can just issue darcs revert --all or the short hand darcs revert -a and darcs will revert all the unrecorded changes in your working tree. Just like with record you can also pass a list of one or more files to revert to specify which the files for which you would like to revert your changes.

To unrecord local patches that have not been pushed yet you can use the --not-in-remote flag.

Unrevert

Even when correcting mistakes we are bound to make even more, thankfully darcs still has got our back with darcs unrevert. Whenever we revert something darcs keeps track of our last revert. So let’s say that we have just reverted our name change and decided we wanted to go back just to take another look.

$ darcs unrevert
-Sakura was looking at her creation. She was quite happy with it.
+Humungus was looking at her creation. She was quite happy with it.
Shall I unrevert this change? (1/1)  [ynW...], or ? for more options: y
Do you want to Unrevert these changes? [Yglqk...], or ? for more options: y

And just like that, we have undone our revert. Isn’t it nice to have an extra safe guard just in case something goes wrong?

Roll-over! Roll-over! Roll-back! rollback!

Another nice property of darcs is that every change has an inverse. Oh boy, math jargon again. Let me explain. A change describes something we have… well changed duh. Let’s say we have added a line “happy happy joy joy” to a file. The inverse of that change would be removing that line. So when you apply the inverse of a change, it takes back all the modifications of that that change. You can once again think of it in terms of numbers. When you have x + 3 you are adding 3 to some number x. You can get back to x by applying the inverse of 3 which is -3. It’s the same idea, just with changes.

$ echo "happy happy joy joy" >> story.txt
$ darcs record -m 'add some joy'
$ darcs log -v -p joy
patch 5ac28c7924511e5fffaf1f028b89158c429938a8
Author: raichoo@example.com
Date:   Wed Jun 27 16:31:28 CEST 2018
  * add some joy
    hunk ./story.txt 2
    +happy happy joy joy

So, a couple of weeks later we figure that maybe this is just way too much joy and we decide to roll back the change. We do that by using darcs rollback which takes some changes and applies their inverse to the working tree. Just like log rollback can take a -p flag to specify a pattern for selecting matching patches. I know that the patch name contains the word “joy” so I’m using that.

$ darcs rollback -p joy
patch 5ac28c7924511e5fffaf1f028b89158c429938a8
Author: raichoo@example.com
Date:   Wed Jun 27 16:31:28 CEST 2018
  * add some joy
Shall I rollback this patch? (1/1)  [ynW...], or ? for more options: y
Do you want to Rollback these patches? [Yglqk...], or ? for more options: y
hunk ./story.txt 2
+happy happy joy joy
Shall I rollback this change? (1/1)  [ynW...], or ? for more options: y
Do you want to Rollback these changes? [Yglqk...], or ? for more options: y
Changes rolled back in working tree
$ darcs whatsnew
hunk ./story.txt 2
-happy happy joy joy

rollback does not create any new patches, it just applies the inverses of the changes you have selected to your working tree, it’s up to you to record a new patch from them.