~jan0sch/darcs-book
Showing details for patch a2ae80284727abf3d058a5159be6915914522dac.
diff -rN -u old-darcs-book/en/07-dependencies-and-good-patches.md new-darcs-book/en/07-dependencies-and-good-patches.md --- old-darcs-book/en/07-dependencies-and-good-patches.md 1970-01-01 00:00:00.000000000 +0000 +++ new-darcs-book/en/07-dependencies-and-good-patches.md 2024-11-23 20:35:48.682781430 +0000 @@ -0,0 +1,220 @@ +Dependencies and good patches +============================= + +I think this is a good place to take a little breath and start talking about +patches and how to actually create a good history. This can be a tricky task to +accomplish but it's worth it in the long run. Think of your set of patches as +little building blocks from which you build a whole project, it'll help you +later when you might want to track down a problem. A cleanly crafted set of +patches can be extremely helpful here. Maybe a patch has introduced a bug if the +patch is self-contained you can simply `rollback` that single patch and you can +start thinking about a better way to solve the issue than this patch did. Or you +can just pick some patches that you are really interested in without pulling in +other ones that might currently just interfere with your work. + +In this chapter we will take a look at some more details about patches and some +thought about how to create good patches. + +Dependencies in `darcs` +----------------------- + +First we should take a step back and take a look at how `darcs` looks at our +patches again. Whenever we take a look at our changes with `darcs log` +everything is presented to us in a linear fashion, but that's not the only way +we can think of organizing our patches. We now have heard numerous times that a +"repository's state is defined by a set a changes". We have also heard what it +means when to patches `A` and `B` commute, namely that it does not matter in +which order we apply them. Until now we didn't really exploit these properties +of `darcs` that much. So let's talk a little bit about dependencies so we can +get the most out of recording and crafting our patches. + +To illustrate how patches can depend on each other in `darcs` let's create a +very simple repository with two files called `A` and `B`. First we are going to +`add` these two files and then we are going to change their contents. + +``` +$ touch A B +$ darcs add A +Adding 'A' +$ darcs record -m 'add A' -a +Finished recording patch 'add A' +$ darcs add B +Adding 'B' +$ darcs record -m 'add B' -a +Finished recording patch 'add B' +$ echo A >> A +$ darcs record -m 'change A' -a A +Recording changes in: "A" +Finished recording patch 'change A' +$ echo B >> B +$ darcs record -m 'change B' -a B +Recording changes in: "B" +Finished recording patch 'change B' +patch 376b1bc0febb10802797a5afe7d55e35e42ac89f +Author: raichoo@example.com +Date: Mon Jul 9 19:04:01 CEST 2018 + * change B + +patch 1f9b4b1566ce3410c70ad5231ff21abb0dfed04b +Author: raichoo@example.com +Date: Mon Jul 9 19:02:49 CEST 2018 + * change A + +patch 0d87b94c8d03fea3a2b613c43032df8da8cbff93 +Author: raichoo@example.com +Date: Mon Jul 9 19:02:02 CEST 2018 + * add B + +patch 0b2f173ea79d311c34d8e321b6a8d86582d18ff4 +Author: raichoo@example.com +Date: Mon Jul 9 19:01:03 CEST 2018 + * add A +``` + +Nothing too surprising has happened here. We have added some files and then we +have changed them. Everything looks nice and linear. But let's take a look at +how these patches depend on each other. + +`darcs show dependencies` will give us some `graphviz` output that we can pipe +into the `dot` command to generate a visual representation of all the patch +dependencies in our repository. The command to do this looks like this. + +``` +darcs show dependencies | dot -Tpng -o dependencies-1.png +``` + +For our little example repository `darcs` and `dot` will generate a `png` file +that looks like this. + +![](../img/dependencies-1.png) + +Huh, now that looks radically different. Let's talk about what this output +actually means. We see that `change B` depends on `add B` and `change A` depends +on `add A`. That's not really surprising. You can only really change a file +after you have added it. Makes sense doesn't it. But how does `darcs` figure out +what patches depend on each other? It's quite simple. Remember when we talked +about **commuting patches**. To patches `A` and `B` commute if we can apply them +to our repository in any order and end up with the same result. Now that's +clearly not the case for our patches above. I can't change a file that isn't +there, therefore I have to `add` it before changing it. These to patches do not +commute, and this is what we call a **dependency**. You need to satisfy all the +dependencies of a patch before you can apply it. + +In our dependency graph you can also see that all our changes concerning the +files `A` and `B` are totally independent from each other. So I could pull only +the changes concerning `B` from the repository while ignoring the changes +regarding `A` altogether. This is an incredibly powerful mechanism that +**snapshot based** version control systems do not have. Now you can pull in a +set of patches and ignore all those that don't depend on the change you are +currently interested in. Other version control systems like `git` for example +call this **cherry picking**, but compared to `darcs` they are suffering from +some short comings. In those version control system you re-record the patch when +you **cherry pick** it. That means that its whole identity changes, one way in +which this manifests is that it will get a different hash. So even though it's +the exact same change the patches are now different. This can become quite +annoying when working in a distributed setting, with `darcs` this is a complete +non-issue. + +Let's play some more with this. We now want to change file `A` but let's pretend +that we are referencing something that is in file `B` (maybe a function, or a +paragraph). + +``` +$ echo use B >> A +$ darcs record -m 'use B' -a A +``` + +![](../img/dependencies-2.png) + +Darn, that's not really what we wanted. Now we have a change in file `A` that +depends on file `B` being present, but `darcs` has no understanding of the +semantics of a file's content. This is problematic because if someone decided to +pull in the `use B` patch without pulling in all our `B` patches the state of +our repository would not make sense. You can't use anything in `B` if it isn't +there, makes sense doesn't it? But fear not, we can instruct `record` to prompt +us for dependencies, so we can inform `darcs` about semantic relationships +between patches. So let's try again! + +``` +$ darcs record --ask-deps -m 'use B' -a A +Recording changes in: "A" +hunk ./A 2 ++use B +Shall I record this change? (1/1) [ynW...], or ? for more options: y +Do you want to Record these changes? [Yglqk...], or ? for more options: y +patch 376b1bc0febb10802797a5afe7d55e35e42ac89f +Author: raichoo@example.com +Date: Mon Jul 9 19:04:01 CEST 2018 + * change B +Shall I depend on this patch? (1/2) [ynW...], or ? for more options: y +Will not ask whether to depend on 1 already decided patch. +Do you want to Depend on these patches? [Yglqk...], or ? for more options: y +Finished recording patch 'use B' +``` + +The `--ask-deps` flag instructs `darcs` to prompt us for dependencies and we +tell it that we want our new patch to depend on the patch `change B`. Now the +dependency graph looks like this. + +![](../img/dependencies-3.png) + +This gives us unprecedented control over our patches. We now can enrich them +with semantic information and our collaborators can leverage that information to +mix and match patches to their liking. Want to `pull` in one feature but not the +other one because it's still too experimental for you, or maybe clashes with +some feature you are working on? You can do that now, and all of that while +maintaining the identity of patches. This is one of the true powers of `darcs`. + +A thought on patches +-------------------- + +I want to talk a little bit about "good practices" regarding patches here. If +you are just starting out with version control you might find it hard to figure +out what goes into a patch, in the beginning you might start out just randomly +recording patches with everything new you have and move along. I'm not +going to lie, even for experienced developers, crafting good patches can be +somewhat of a challenge. + +The most important thing is to try to make patches that make sense. That sounds +deceptively easy but this can be a bit tricky. Each patch should constitute unit +of work, so if you were to apply it and it's dependencies, the resulting working +tree should also make sense. + +So what does it mean for a set of changes in our repository to make sense? In +some cases this question is easy to answer in others it's sadly not that simple. +When it comes to a software project, I usually try to make patches and their +dependency not break the project. So no matter which patches I `pull` in, the +project should always compile and work as expected. If your project is not code +this might become a little harder, like when you are writing a text. If you want +to change something throughout your project it makes sense to turn that single +change into one patch, here we might think about "making sense" in another way. +Like in an earlier example we talked about writing a novel and then renaming the +protagonist. A patch that would only perform the renaming on a couple of pages +would not be very useful, a better patch would do that throughout the existing +parts of the novel. This is a very useful approach because if you change your +mind, it gets a lot easier to `rollback` all of the changes you have decided +against. + +Writing good patches is takes a lot of experience and practice but it's a +valuable skill to train. `darcs` is a VCS that rewards good patches by allowing +you to *cherry pick** in a way no other VCS can, so striving for good patches is +something that you want to keep in mind, especially if you are working with +others on a team. Your fellow cooperators will be thankful. + +Spontaneous branches +-------------------- + +One way where this becomes really quite powerful is something that we call +**spontaneous branches**. If you look at a repository where you are working on a +lot of things at the same time you might see a lot of "loose end" in your +dependency graph. Take a look at this. + +![](../img/branches.png) + +So here you can see a repository where were are tracking the development of 3 +different features `A`, `B` and `C`. Since `darcs` knows about dependencies we +can work on each of these features separately without interfering the others. I +someone else chooses to work on feature `A` and we are working on feature `B` we +can do that in a single repository without getting in each others way. Not many +version control systems can do that without changing the identity of the patches +involved which makes working in distributed teams a lot harder. Binary files old-darcs-book/img/branches.png and new-darcs-book/img/branches.png differ diff -rN -u old-darcs-book/Makefile new-darcs-book/Makefile --- old-darcs-book/Makefile 2024-11-23 20:35:48.682781430 +0000 +++ new-darcs-book/Makefile 2024-11-23 20:35:48.682781430 +0000 @@ -19,14 +19,17 @@ ${PANDOC} -V prev:chapter04 -V next:chapter06 en/05-a-little-help-from-my-friends.md -o dist/chapter05.html dist/chapter06.html: dist - ${PANDOC} -V prev:chapter05 en/06-conflict-management.md -o dist/chapter06.html + ${PANDOC} -V prev:chapter05 -V next:chapter07 en/06-conflict-management.md -o dist/chapter06.html + +dist/chapter07.html: dist + ${PANDOC} -V prev:chapter06 -V next:chapter08 en/07-dependencies-and-good-patches.md -o dist/chapter07.html dist/chapter08.html: dist - ${PANDOC} -V next:chapter09 en/08-rewriting-history.md -o dist/chapter08.html + ${PANDOC} -V prev:chapter07 -V next:chapter09 en/08-rewriting-history.md -o dist/chapter08.html dist/chapter09.html: dist ${PANDOC} -V prev:chapter08 en/09-tag-youre-it.md -o dist/chapter09.html -all: dist/chapter01.html dist/chapter02.html dist/chapter03.html dist/chapter04.html dist/chapter05.html dist/chapter06.html dist/chapter08.html dist/chapter09.html +all: dist/chapter01.html dist/chapter02.html dist/chapter03.html dist/chapter04.html dist/chapter05.html dist/chapter06.html dist/chapter07.html dist/chapter08.html dist/chapter09.html clean: rm -r dist