~jan0sch/darcs-book
Showing details for patch 632fffcd7aeeb40b56bd4c7a2074f725deb3c971.
diff -rN -u old-darcs-book/en/07-rewriting-history.md new-darcs-book/en/07-rewriting-history.md --- old-darcs-book/en/07-rewriting-history.md 1970-01-01 00:00:00.000000000 +0000 +++ new-darcs-book/en/07-rewriting-history.md 2024-11-23 20:21:27.973309964 +0000 @@ -0,0 +1,485 @@ +Rewriting History +================= + +Before we start talking about rewriting our repository history, 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. + +Dependencies in `darcs` +----------------------- + +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`. + +Amending patches +---------------- + +When you start using version control you will quickly encounter situations where +you have recorded a patch and realize that you have made a mistake. For example +you have recorded a patch with a typo or you have forgotten to state a +dependency in a patch. That's really super annoying. What you could do now is +`record` a new patch correcting that error but that would make our history more +and more confusing as time progresses and this kind patches start to accumulate. +This is where `darcs amend` comes in handy, it let's you change a patch the you +have already recorded without creating a new one. + +As an example we are going to pretend that we accidentally didn't state the +dependency of our `use B` patch in the above section correctly, so our +repository once again looks like this. + +![](../img/dependencies-2.png) + +So let's use `amend` to right that wrong. + +``` +$ darcs amend --ask-deps -p 'use B' +patch 610c31ea41237cd407464ff41720d04bce214ef2 +Author: raichoo@example.com +Date: Mon Jul 9 20:05:30 CEST 2018 + * use B +Shall I amend this patch? [yNjk...], 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 amending patch: +patch 9890bbfa50839674d45c416395bdb7e3bcd0ac00 +Author: raichoo@example.com +Date: Mon Jul 9 20:07:22 CEST 2018 + * use B +``` + +We have used the `-p` flag to state a pattern for the patch we want to `amend` +and instructed `darcs` to prompt us for dependencies. We don't need to specify a +pattern but sometimes if we know exactly what patch we want to `amend` it can +certainly speed up the process. After selecting the patch we want to take care +of, `darcs` will prompt us for changes just like it would to when recording a +change. Our repository now looks like we want it to. + +![](../img/dependencies-3.png) + +`amend` works very much like `record` but rather than recording a new patch it +prompts you for an existing patch that you intend to improve first and then +proceeds just like we are used to when recording patches. We can add more +changes to our patch, change hunks, messages, author etcetera. Keep in mind that +you should not rewrite patches that have already been pushed to a public +repository since this action is **local only**, pushed patches will remain in +your remote repository even if you amend them locally. If you want to change the +state of a remote repository your best option is to `record` a new patch and +`push` it there. + +You also cannot `amend` patches that are a dependency of another patch. That +would be like pulling a rug away from under their feet. There are more powerful +tools that let you do even that, but that's something for a later chapter. + +Another example that is a bit more common deals with typos. Typos are probably +the most annoying thing when you deal with recording patches. They show up in +parts of your projects as well as patch names. Heck, they are pretty much +everywhere, just look at this patch gone horribly wrong. + +``` +$ darcs log -v +patch a7f5a2efe162787b3e7f6ceb215f53fa300f6590 +Author: raichoo@example.com +Date: Tue Jul 10 19:41:56 CEST 2018 + * initial rceord + addfile ./Main.hs + hunk ./Main.hs 1 + +main = "Hello Wrold!" +``` + +Oh boy, looks like we weren't quite awake yet when we recorded that patch. We +misspelled "World" as well as "record". That's quite embarrassing, surely we +don't want to `push` that! Thankfully we can still `amend` that patch before its +publication. + +``` +$ sed -i '' 's/Wrold/World/' Main.hs +patch a7f5a2efe162787b3e7f6ceb215f53fa300f6590 +Author: raichoo@example.com +Date: Tue Jul 10 19:41:56 CEST 2018 + * initial rceord +Shall I amend this patch? [yNjk...], or ? for more options: y +hunk ./Main.hs 1 +-main = "Hello Wrold!" ++main = "Hello World!" +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 +Finished amending patch: +patch 1e00a2684025c2ee9e1cbbb809d71d8167482458 +Author: raichoo@example.com +Date: Tue Jul 10 19:45:57 CEST 2018 + * initial record +``` + +Patch quality is certainly an important thing to take care of, so be sure to +double check before you publish something important. + +Unrecording patches +------------------- + +Sometimes we want to get rid of patches without getting rid of the work we have +done. Maybe we want to fold a bunch of patches into one, or maybe we want to +organize our patches a little differently. Whatever the case, sometimes some +patches need to be removed from our local repository and `unrecord` is how we +can do that. + +Let's say we are currently working on a new feature in our project and our +history currently looks something like this. + +We started out with a Haskell program just printing out "Hello!" and then we got +the feature request asking us to add two more messages to the output. First we +added some code that additionally prints out "World!". At that point wanted to +capture our progress, so we decided to `record` a patch and call it `WIP`. Then +we proceeded to add the other message requested in the feature and record that +as well. + +``` +$ cat Main.hs +main = do + putStrLn "Hello!" + putStrLn "World!" + putStrLn "Everyone!" +$ darcs log -v +patch 4f43a522ae0162dcef8dab6aab0d354ede209767 +Author: raichoo@example.com +Date: Sun Jul 8 14:51:56 CEST 2018 + * WIP + hunk ./Main.hs 4 + + putStrLn "Everyone!" + +patch b7cf79bc1e3454f7dfdee86a480e72f312b43a14 +Author: raichoo@example.com +Date: Sun Jul 8 14:51:42 CEST 2018 + * WIP + hunk ./Main.hs 3 + + putStrLn "World!" + +patch faf56a95edb01004d10f3bd4b72ad8d2b5ad2044 +Author: raichoo@example.com +Date: Sun Jul 8 14:51:10 CEST 2018 + * initial record + addfile ./Main.hs + hunk ./Main.hs 1 + +main = do + + putStrLn "Hello!" +``` + +That's not a very useful history and really not fit for publishing since it's +showing our work in progress rather than a finished patch. It certainly served +its purpose, but it really needs to be cleaned up before we show it to the rest +of the world. We have recorded the state of our working tree whenever we felt +confident and then moved onward to the next step. We want to squash the two +`WIP` patches into a single patch. The first thing we do is that we `unrecord` +them. Since we have named all our "work in progress" patches `WIP` we can +specify a pattern for `unrecord` using the `-p` flag so `darcs` will only ask us +if it should `unrecord` patches that have a name matching this pattern. + +``` +$ darcs unrecord -p WIP +patch 4f43a522ae0162dcef8dab6aab0d354ede209767 +Author: raichoo@example.com +Date: Sun Jul 8 14:51:56 CEST 2018 + * WIP +Shall I unrecord this patch? (1/2) [ynW...], or ? for more options: y +patch b7cf79bc1e3454f7dfdee86a480e72f312b43a14 +Author: raichoo@example.com +Date: Sun Jul 8 14:51:42 CEST 2018 + * WIP +Shall I unrecord this patch? (2/2) [ynW...], or ? for more options: y +Do you want to Unrecord these patches? [Yglqk...], or ? for more options: y +Finished unrecording. +$ darcs log +patch faf56a95edb01004d10f3bd4b72ad8d2b5ad2044 +Author: raichoo@example.com +Date: Sun Jul 8 14:51:10 CEST 2018 + * initial record +``` + +Okay, good. We are now back with only one patch in our repository. We have +decided that this is the only thing that we want to keep and re-record our work +on top of that. Since `unrecord` does not change our working tree still contains +our work. + +``` +$ cat Main.hs +main = do + putStrLn "Hello!" + putStrLn "World!" + putStrLn "Everyone!" +``` + +Now all the modifications that we have done to our project since the `initial +record` are now unrecorded again and `darcs whatsnew` will report them as such. + +``` +$ darcs whatsnew +hunk ./Main.hs 3 ++ putStrLn "World!" ++ putStrLn "Everyone!" +``` + +So let's create a new patch single patch out of these changes and call it `add +cool new feature`. + +``` +$ darcs record -a -m 'add cool new feature' +Finished recording patch 'add cool new feature' +$ darcs log -v +patch 07729b85848c949e03ae856005a8c90bf42c785a +Author: raichoo@example.com +Date: Sun Jul 8 15:11:42 CEST 2018 + * add cool new feature + hunk ./Main.hs 3 + + putStrLn "World!" + + putStrLn "Everyone!" + +patch faf56a95edb01004d10f3bd4b72ad8d2b5ad2044 +Author: raichoo@example.com +Date: Sun Jul 8 14:51:10 CEST 2018 + * initial record + addfile ./Main.hs + hunk ./Main.hs 1 + +main = do + + putStrLn "Hello!" +``` + +That's better. We are now happy with our new patch. Again, keep in mind that you +should not do this with patches you have already published. Just like `amend` +this operation is **local only**. + +OB-LIT-E-RATE! +-------------- + +Sometime we want to go even further than `unrecord`. For example when a feature +we are working on turns out to be completely broken and we think that we are +better off to start from scratch. Of course we could just do an `unrecord` +followed by a `revert` to make the patches disappear from our repository and +then make the changes disappear from our working tree. If that is what you want +you can use `obliterate`. That command sounds scary for a reason. It basically +throws away work permanently. + +So here's our repository from the first section again. + +``` +$ ls +A B _darcs +$ darcs log +patch 9890bbfa50839674d45c416395bdb7e3bcd0ac00 +Author: raichoo@example.com +Date: Mon Jul 9 20:07:22 CEST 2018 + * use 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 +``` + +We now want to get rid of all of the changes involving the file `B` and we want +to get rid of them for good. + +``` +$ darcs obliterate +patch 9890bbfa50839674d45c416395bdb7e3bcd0ac00 +Author: raichoo@example.com +Date: Mon Jul 9 20:07:22 CEST 2018 + * use B +Shall I obliterate this patch? (1/5) [ynW...], or ? for more options: y +patch 376b1bc0febb10802797a5afe7d55e35e42ac89f +Author: raichoo@example.com +Date: Mon Jul 9 19:04:01 CEST 2018 + * change B +Shall I obliterate this patch? (2/5) [ynW...], or ? for more options: y +patch 1f9b4b1566ce3410c70ad5231ff21abb0dfed04b +Author: raichoo@example.com +Date: Mon Jul 9 19:02:49 CEST 2018 + * change A +Shall I obliterate this patch? (3/5) [ynW...], or ? for more options: n +patch 0d87b94c8d03fea3a2b613c43032df8da8cbff93 +Author: raichoo@example.com +Date: Mon Jul 9 19:02:02 CEST 2018 + * add B +Shall I obliterate this patch? (4/5) [ynW...], or ? for more options: y +Will not ask whether to obliterate 1 already decided patch. +Do you want to Obliterate these patches? [Yglqk...], or ? for more options: y +Finished obliterating. +$ darcs log +patch 1f9b4b1566ce3410c70ad5231ff21abb0dfed04b +Author: raichoo@example.com +Date: Mon Jul 9 19:02:49 CEST 2018 + * change A + +patch 0b2f173ea79d311c34d8e321b6a8d86582d18ff4 +Author: raichoo@example.com +Date: Mon Jul 9 19:01:03 CEST 2018 + * add A +$ ls +A _darcs +``` + +`obliterate` has done its name justice. All the patches involving `B` are gone +as well as the related files in our working tree. Notice how `darcs` has kept +all our changes regarding file `A` even though the changes to `A` and `B` where +interleaved in our first `darcs log` output. But there is no relationship +between those changes so `darcs` could get separate those two cleanly from one +another. Binary files old-darcs-book/img/dependencies-1.png and new-darcs-book/img/dependencies-1.png differ Binary files old-darcs-book/img/dependencies-2.png and new-darcs-book/img/dependencies-2.png differ Binary files old-darcs-book/img/dependencies-3.png and new-darcs-book/img/dependencies-3.png differ diff -rN -u old-darcs-book/Makefile new-darcs-book/Makefile --- old-darcs-book/Makefile 2024-11-23 20:21:27.973309964 +0000 +++ new-darcs-book/Makefile 2024-11-23 20:21:27.973309964 +0000 @@ -19,9 +19,12 @@ ${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 -all: dist/chapter01.html dist/chapter02.html dist/chapter03.html dist/chapter04.html dist/chapter05.html dist/chapter06.html +dist/chapter07.html: dist + ${PANDOC} -V prev:chapter06 en/07-rewriting-history.md -o dist/chapter07.html + +all: dist/chapter01.html dist/chapter02.html dist/chapter03.html dist/chapter04.html dist/chapter05.html dist/chapter06.html dist/chapter07.html clean: rm -r dist