~jan0sch/darcs-book

Showing details for patch 632fffcd7aeeb40b56bd4c7a2074f725deb3c971.
2018-07-10 (Tue), 6:22 PM - - 632fffcd7aeeb40b56bd4c7a2074f725deb3c971

add chapter 7

Summary of changes
4 files added
  • en/07-rewriting-history.md
  • img/dependencies-1.png
  • img/dependencies-2.png
  • img/dependencies-3.png
1 files modified with 6 lines added and 3 lines removed
  • Makefile with 6 added and 3 removed lines
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