tag! You’re it!

We now have all the tools the we need to craft our patches and their dependencies into a shape that we find satisfying. We know how to record patches, pull and push work between other repositories, state dependencies between patches, amend them or just throw them away. But how do we indicate that we have reached a point in our development where we have confidence in our work and say: “Yes! We have finally reached one of our goals!”

As your project progresses you might pass a milestone every now and then. Once you have decided that your current repository state meets all the conditions you would like it to meet for such a milestone to occur it is useful to be able to refer to that repository state by something like a version number (e.g ‘1.0’) or a code name. In darcs we do this by creating a tag. You can call your tag any way you like but it’s a good idea to stick to a certain naming scheme once you start applying tags to your repository.

So let’s take a look at darcs tag which allows you to create a tag.

To illustrate how tags work let’s build ourselves are relatively simple example repository and tag it for fun and profit.

$ touch A B
$ darcs add A
Adding 'A'
$ darcs record -m A -a
Finished recording patch 'A'
$ darcs record -m B -a -l
Finished recording patch 'B'
$ darcs log
patch 4dd3f2b240fcae41674f6742213c0ac953981aa7
Author: raichoo@example.com
Date:   Wed Jul 11 19:15:28 CEST 2018
  * B

patch 773190b27402bae8af4895db5810010650652185
Author: raichoo@example.com
Date:   Wed Jul 11 19:14:46 CEST 2018
  * A

If we look at the dependency graph for this repository we will see that it is remarkably unspectacular. We just have two patches and they do not depend on each other in any way.

So if we were to capture the current state of this repository we need to ensure that we pull in those two patches. To do this let’s create a tag we call it 1.0 so we can take a closer look at what darcs is going to do.

$ darcs tag -m 1.0
Finished tagging patch 'TAG 1.0'
$ darcs log -v --last 1
patch 46094731f678f0741907b99b3bedeaff5febd27d
Author: raichoo@example.com
Date:   Wed Jul 11 19:18:29 CEST 2018
  tagged 1.0
    depend patch 4dd3f2b240fcae41674f6742213c0ac953981aa7
    * B
    depend patch 773190b27402bae8af4895db5810010650652185
    * A

As you can see tags are very much like patches. They have an author, a creation date as well as a hash, but instead of recording any changes they only depend on patches. This one obviously depends on the two patches we have previously recorded to capture the repositories state.

If we don’t want to depend on all the patches then, just like record, we can instruct tag to prompt us for dependencies by adding the --ask-deps flag to our command. So in case we just want to depend on patch A for our tag we can simply do this.

$ darcs tag -m 1.0 --ask-deps
patch 773190b27402bae8af4895db5810010650652185
Author: raichoo@example.com
Date:   Wed Jul 11 19:14:46 CEST 2018
  * A
Shall I depend on this patch? (1/2)  [ynW...], or ? for more options: y
patch 4dd3f2b240fcae41674f6742213c0ac953981aa7
Author: raichoo@example.com
Date:   Wed Jul 11 19:15:28 CEST 2018
  * B
Shall I depend on this patch? (2/2)  [ynW...], or ? for more options: n
Do you want to Depend on these patches? [Yglqk...], or ? for more options: y
Finished tagging patch 'TAG 1.0'

To list all the tags in a repository you can issue darcs show tags and it will give a list of all the recorded tags.

This is especially useful if we decide to tag our repository but already recorded some patches that we don’t want to have in that version.

Pulling tags

Now if we wanted to pull in all the changes the correspond to our tag 1.0 from another repository we can specify that tag by using the -t flag that pull offers. This is where tags become quite helpful if we just care about a specific version on the project. Maybe we want to retrieve a stable version of a piece of software without pulling in the patches that or not yet part of a stable release.

Here we are in repository that only contains patch B and we want to pull in all the dependencies of our tag 1.0. This is how we would go about that.

$ darcs log
patch 4dd3f2b240fcae41674f6742213c0ac953981aa7
Author: raichoo@example.com
Date:   Wed Jul 11 19:15:28 CEST 2018
  * B
$ darcs pull -t 1.0 ../repo
Pulling from "/tmp/darcs/repo"...
patch 773190b27402bae8af4895db5810010650652185
Author: raichoo@example.com
Date:   Wed Jul 11 19:14:46 CEST 2018
  * A
Shall I pull this patch? (1/2)  [ynW...], or ? for more options: y
patch 46094731f678f0741907b99b3bedeaff5febd27d
Author: raichoo@example.com
Date:   Wed Jul 11 19:18:29 CEST 2018
  tagged 1.0
Shall I pull this patch? (2/2)  [ynW...], or ? for more options: y
Do you want to Pull these patches? [Yglqk...], or ? for more options: y
Finished pulling.
$ darcs log
patch 46094731f678f0741907b99b3bedeaff5febd27d
Author: raichoo@example.com
Date:   Wed Jul 11 19:18:29 CEST 2018
  tagged 1.0

patch 773190b27402bae8af4895db5810010650652185
Author: raichoo@example.com
Date:   Wed Jul 11 19:14:46 CEST 2018
  * A

patch 4dd3f2b240fcae41674f6742213c0ac953981aa7
Author: raichoo@example.com
Date:   Wed Jul 11 19:15:28 CEST 2018
  * B

If there are any patches in that other repository that are not a dependency of 1.0 we would not be prompted for those.

Actually the -t flag is supported by quite a lot of darcs commands. If you took a look at all of the available options for all of the darcs commands you might have realized that darcs is trying very hard to give you a consistent user experience. If a command understands the notion of a tag those will always be references with the -t flag or its longhand --tags. This flag takes a regular expression so you can even reference multiple tags at once if you happen to fancy that in a particular situation.

It should not be much of a surprise that push supports the -t flag as well, so if we were to push our changes in the above example we would do it like this.

$ darcs push -t 1.0 ../anotherrepo
patch 773190b27402bae8af4895db5810010650652185
Author: raichoo@example.com
Date:   Wed Jul 11 19:14:46 CEST 2018
  * A
Shall I push this patch? (1/2)  [ynW...], or ? for more options: y
patch 46094731f678f0741907b99b3bedeaff5febd27d
Author: raichoo@example.com
Date:   Wed Jul 11 19:18:29 CEST 2018
  tagged 1.0
Shall I push this patch? (2/2)  [ynW...], or ? for more options: y
Do you want to Push these patches? [Yglqk...], or ? for more options: y
Finished applying.
Push successful.

Ah, nice and consistent. Everything is just as we expected.

A tale of dirty tags

When using darcs show dependencies things might become a little surprising because this command only generates a graph by walking backwards through our repository’s history until it encounters the first tag. So if we were to look at our repository right after we have tagged a version which depends on all the loose ends in our patch dependency graph things might get a little anti-climactic. We might end up with a “graph” that looks like this.

This is actually how it is supposed to look because darcs show dependencies only looks at past patches until it finds a tag. But things might get a bit confusing if we hand craft our tag dependencies. This is how our dependency graph would look like after our darcs tag -t 1.0 --ask-deps example, where we only let the tag 1.0 depend on patch A and not B.

Now that’s quite weird. Even though we have tagged our repository we still can see past tag 1.0. Wasn’t darcs show dependencies supposed to stop when it encountered the first tag? This is because our history currently looks like this.

$ darcs log -v
patch d457a1cbaa6ad18761849fc7a90589dc3cdeb108
Author: raichoo@example.com
Date:   Wed Jul 11 22:07:27 CEST 2018
  tagged 1.0
    depend patch 773190b27402bae8af4895db5810010650652185
    * A

patch 4dd3f2b240fcae41674f6742213c0ac953981aa7
Author: raichoo@example.com
Date:   Wed Jul 11 19:15:28 CEST 2018
  * B
    addfile ./B

patch 773190b27402bae8af4895db5810010650652185
Author: raichoo@example.com
Date:   Wed Jul 11 19:14:46 CEST 2018
  * A
    addfile ./A

So there is a patch, namely B that is not part a dependency of 1.0 but it’s still in our repository and history-wise it’s after our tag. darcs is trying very hard to make a useful graph out of this situation and this is the best it can come up with. This is what’s called a dirty tag, and they can impact the performance of commands where repositories need to be compared such like pull and push. Thankfully we can get rid of these dirty tags quite easily by moving all the patches that are not a dependency of our tag to the top of our history. This is what darcs optimize reorder does. Take a look.

$ darcs optimize reorder
Done reordering!
$ darcs log
patch 4dd3f2b240fcae41674f6742213c0ac953981aa7
Author: raichoo@example.com
Date:   Wed Jul 11 19:15:28 CEST 2018
  * B

patch d457a1cbaa6ad18761849fc7a90589dc3cdeb108
Author: raichoo@example.com
Date:   Wed Jul 11 22:07:27 CEST 2018
  tagged 1.0

patch 773190b27402bae8af4895db5810010650652185
Author: raichoo@example.com
Date:   Wed Jul 11 19:14:46 CEST 2018
  * A

Ah that’s better now darcs can make a bit more sense of our history and create a nice crisp dependency graph that looks just like we expect it.

B now comes before 1.0 in our history, in fact there is nothing hiding past the tag that is not a dependency 1.0. So darcs can stop generating the graph right after encountering our tag, it’s not dirty anymore. Notice that darcs optimize reorder does not change the identity of a patch. This is once again a result of darcs not really caring about the order in which patches get applied to your repository.

Cloning tags

Tags are particularly useful when cloning a repository. If you ever want to check out a specific version of a repository you can specify a tag with -t just like with any other command and get a copy of the project from that version. Let’s say that out of curiosity we want to take a look at version 1.0.0 of darcs. Since I have a copy of the darcs repository on my computer I can do it like this.

$ darcs clone -t 1.0.0 --lazy darcs-screened darcs-old
Going to specified version...
Unapplying 10084 patches
Finished cloning.

This work flow can be used to branch off from a specific version and work from there. Some development models feature multiple branches. Maybe you have a release branch that contains all the patches you ship to your audience and a development branch where you try out new things. Once your development branch has stabilized you can tag a version and pull that into your stable branch. darcs unlike other version control systems does not have a notion of branches, we simple maintain multiple working trees. If you are worried that this might take up an unreasonable amount of disk space don’t worry too much. darcs is able to share information between these copies so cloning a local repository is pretty fast and does not take twice as much disk space as you might expect.