~jan0sch/darcs-book
~jan0sch/darcs-book/en/05-a-little-help-from-my-friends.md
~jan0sch/darcs-book/en/05-a-little-help-from-my-friends.md
title: A little help from my friends next: chapter06 prev: chapter04 toclink: yes ---
In chapter 1 we have learned about darcs
being a distributed version
control system, but until now we basically just worked with one local instance
of our project. No other parties were involved. But whenever we are working on
something big it's a good thing when people participate. In this chapter I am
going to introduce you how to work together with others.
Until now we only used repositories that were freshly created by ourselves. But sometimes we want to start participating on a project that has already started, so initializing something new is not what we want. This is where cloning comes in. With cloning we can take a repository and make our own copy from it.
Let's say you want to clone
the source of this book, which is hosted on darcs
hub. To clone
this repository you
simply issue darcs clone https://hub.darcs.net/raichoo/darcs-book
and
darcs
will start copying the repository into a directory called darcs-book
..
$ darcs clone https://hub.darcs.net/raichoo/darcs-book
Copying patches, to get lazy repository hit ctrl-C...
Finished cloning.
Huh, that's an interesting messageā¦ I can hit CTRL-C
to get a lazy repository.
What does that mean? Well, quite simple. Repositories can get REALLY big and
therefore it takes a lot of time to clone
them, but what if you only wanted
the newest changes and pull in everything else on demand? No need to pull in the
entire history of a project all at once. A lazy repository does just that, and
this reduces cloning time drastically. Cloning the entire history is only useful
if you might not be able to access the Internet for some time and you really
need to have access to the entire evolution of the project. So if you happen to
get stuck on a particularly long clone
, just hit CTRL-C
and you are good to
go, most of the time you will be interested in the current state of the
repository anyways. Of course you can instruct darcs
to do a lazy clone right
away by add the --lazy
flag.
$ darcs clone --lazy https://hub.darcs.net/raichoo/darcs-book
Finished cloning.
It's a simple as that.
clone
locally.clone
is useful for more than just copying data from a remote location.
Sometime you might just want to have another copy of your project to record a
entirely different set of patches in. This becomes especially interesting once
we are able to modify the history of our project, but more on that in a later
chapter.
In the section before we saw that the clone
command takes a location from
where you want to clone
. This does not have to be a remote server, it can also
be a directory. So let's say I decided to work on the second edition of this
book and I wanted to do that inside of a separate repository and pull patches
from there in the future.
$ ls
darcs-book
$ darcs clone darcs-book darcs-book-2nd-edition
Copying patches, to get lazy repository hit ctrl-C...
Finished cloning.
$ ls
darcs-book darcs-book-2nd-edition
So, clone
can take 2 arguments, one being the source repository and another
one being the destination directory. So a source does not necessarily need to be
a remote location, it can be a directory as well.
Great, now we can have multiple copies of a repository and they can either be
remote or local. We are slowly stepping up our game! Now, let's start to
exchange patches between those different copies. For this purpose darcs
offers
the push
and pull
commands. We are going to take a look at push
first. To
do this in a somewhat realistic example let's setup simple scenario first. I'm
going to do this locally but all of the upcoming examples also work with remote
sources.
$ darcs init new-project
$ darcs clone new-project new-project-work
Copying patches, to get lazy repository hit ctrl-C...
Finished cloning.
$ cd new-project-work
$ touch some-file.txt
$ darcs add some-file.txt
Adding 'some-file.txt'
$ darcs record -a -m 'added some file'
Finished recording patch 'added some file'
$ darcs log
patch cfaa89a2b431c0642687d9bfa0bbb721015cc775
Author: raichoo@example.com
Date: Fri Jun 29 13:02:03 CEST 2018
* added some file
Here we have a repository called new-project
and a copy of it which we call
new-project-work
, here we are going to do some actual work and once we are
done we are going to push that to our project repository for publishing or
whatever we choose to do with it.
In our new-project-work
repository we have recorded a patch that is not
present in our new-project
repository which we consider as our main
repository, everything in here is meant to be published to a larger audience. At
some point we have decided that our new patch is ready to go and we want to
publish it to the main repository.
Currently we are in the working tree of our new-project-work
repository and we
want to push to the new-project
repository, this is how we would do that.
$ darcs push ../new-project
Pushing to "/tmp/darcs/new-project"...
patch cfaa89a2b431c0642687d9bfa0bbb721015cc775
Author: raichoo@example.com
Date: Fri Jun 29 13:02:03 CEST 2018
* added some file
Shall I push this patch? (1/1) [ynW...], or ? for more options: y
Do you want to Push these patches? [Yglqk...], or ? for more options: y
Finished applying.
Push successful.
darcs
first figures out which patches are not present in the destination
repository and prompts us for each one of them if we really want to push that
patch. Once we are done it asks us if we really want to push these patches and
after confirming all our selected patches are being transferred to the
destination repository.
Let's take a quick look at the patches that are now inside our new-project
repository, remember that we have just created it and there were no patches in
there to begin with.
$ cd ../new-project
$ darcs log
patch cfaa89a2b431c0642687d9bfa0bbb721015cc775
Author: raichoo@example.com
Date: Fri Jun 29 13:02:03 CEST 2018
* added some file
Nice, as you can see our patch has been transferred from new-project-work
to
the new-project
repository. If you take a look at the working tree you will
also find that all the changes contained in our transferred patches have been
applied. Piece of cake!
Keep in mind that the destination does not need to be just another folder on our own computer, it can as well be a remote destination.
But what if the patches we are interested in are on a remote machine to which we
cannot simple log in and issue a push
. Well, for that we have pull
. Let's
pretend that we didn't push the patch to new-project
like we just did. This
time we are going to pull
it in from new-project-work
to new-project
rather then the other way around. So now we are in the working tree of
new-project
.
$ darcs pull ../new-project-work
HINT: if you want to change the default remote repository to
/tmp/darcs/new-project-work,
quit now and issue the same command with the --set-default flag.
patch cfaa89a2b431c0642687d9bfa0bbb721015cc775
Author: raichoo@example.com
Date: Fri Jun 29 13:02:03 CEST 2018
* added some file
Shall I pull this patch? (1/1) [ynW...], or ? for more options: y
Do you want to Pull these patches? [Yglqk...], or ? for more options: y
Finished pulling.
$ darcs log
patch cfaa89a2b431c0642687d9bfa0bbb721015cc775
Author: raichoo@example.com
Date: Fri Jun 29 13:02:03 CEST 2018
* added some file
So now rather than pushing to another location we can pull
our patches in
from, let's say a website like darcshub.
Wait a minute though, there is something in the output that we didn't talk about
yet. darcs
emits a HINT
message which tells us something about a default
remote repository. What does that mean? A default remote repository allows is
to omit the destination when pushing and pulling. To check if you have one set
you can issue darcs show repo
.
$ darcs show repo
Format: hashed, darcs-2
Root: /tmp/darcs/new-project
PristineType: HashedPristine
Cache: thisrepo:/tmp/darcs/new-project, cache:/home/raichoo/.cache/darcs
PatchIndex: enabled, but not yet created
Num Patches: 1
Weak Hash: cfaa89a2b431c0642687d9bfa0bbb721015cc775
This gives us some information about our repository, but I can't spot a default
repository here. Let's use the --set-default
flag just like darcs
told us to
in the hint.
$ darcs pull --set-default ../new-project-work
No remote patches to pull in!
darcs show repo
Format: hashed, darcs-2
Root: /tmp/darcs/new-project
PristineType: HashedPristine
Cache: thisrepo:/tmp/darcs/new-project, cache:/home/raichoo/.cache/darcs
PatchIndex: enabled, but not yet created
Default Remote: /tmp/darcs/new-project-work
Num Patches: 1
Weak Hash: cfaa89a2b431c0642687d9bfa0bbb721015cc775
Here we go! Now we do not have to explicitly state the remote repository we are working with when we just want to talk to the default remote repository.
$ darcs pull
Pulling from "/tmp/darcs/new-project-work"...
No remote patches to pull in!
$ darcs push
Pushing to "/tmp/darcs/new-project-work"...
No recorded local patches to push!
Of course we can still explicitly specify other repositories if we want to
communicate with a different repository, we can also always set a different
default remote repository just by using the --set-default
flag on a push
or
pull
. This saves us from memorizing all the remote repositories we are working
with and thus makes life a little easier for us.
There is something else that is interesting in the darcs show repo
output.
Namely the weak hash. What in tarnation does that mean and why is it useful?
Basically it's useful to communicate if your repository has the same state as
someone else's. Let me explain. When we first got to know darcs
we've learned
that a repository's state is defined by a set of changes, and therefore the
order in which one has acquired these changes does not matter. So if I were to
work on a project with my friend gimbar and they would pull in patches in a
different order than I, how would we know that our repositories are actually in
the same state? Well, as you might have guessed, that's what the weak hash
is for. In chapter 3 we have learned that every patch can be identified by a
hash, the weak hash is generated from the hashes of all the patches in a
repository in a way that does not care about their order. So if two repositories
are in the same state, meaning they have the same set of changes, and each patch
has a hash that is supposed to be unique to that hash, they are bound to have
the same weak hash. Take a look.
$ darcs log
patch 1ae0f2d1bd00c9d72ac21eef7a26736ed76c27c8
Author: raichoo@example.com
Date: Thu Jul 5 21:36:46 CEST 2018
* A
patch 6f9774a3038e1226d0df9518b163cab517b29f27
Author: raichoo@example.com
Date: Thu Jul 5 21:37:03 CEST 2018
* B
$ darcs show repo
Format: hashed, darcs-2
Root: /tmp/darcs/X
PristineType: HashedPristine
Cache: thisrepo:/tmp/darcs/X, cache:/home/raichoo/.cache/darcs
PatchIndex: enabled, but not yet created
Num Patches: 2
Weak Hash: 75778672be8edbf1fa1d8bf7cb45b9dbc0deb8ef
$ darcs log
patch 6f9774a3038e1226d0df9518b163cab517b29f27
Author: raichoo@example.com
Date: Thu Jul 5 21:37:03 CEST 2018
* B
patch 1ae0f2d1bd00c9d72ac21eef7a26736ed76c27c8
Author: raichoo@example.com
Date: Thu Jul 5 21:36:46 CEST 2018
* A
$ darcs show repo
Format: hashed, darcs-2
Root: /tmp/darcs/Y
PristineType: HashedPristine
Cache: thisrepo:/tmp/darcs/Y, cache:/home/raichoo/.cache/darcs
PatchIndex: enabled, but not yet created
Default Remote: /tmp/darcs/X
Num Patches: 2
Weak Hash: 75778672be8edbf1fa1d8bf7cb45b9dbc0deb8ef
Even though these two example repositories have patch A
and B
applied in a
different order, they do have the same weak hash meaning they are in the
same state.
Sometimes we don't actually want to push
or pull
but rather just want to see
what would happen if we were to do either of these operations. One of these
situations might be that we want to know what changes we have that do not exist
in the remote repository that we want to push
to, or the set changes we would
pull
in from another repository. Both pull
and push
offer a --dry-run
flag to suppress the effects of the actual operation. When we issue a command
using the --dry-run
flag it will only report the actions it would do without
actually performing them.
$ darcs pull --dry-run raichoo@hub.darcs.net:darcs-fish
Would pull from "raichoo@hub.darcs.net:darcs-fish"...
Would pull the following changes:
patch 0dd46bd7a710d66136d7293b667984bdaffb1509
Author: raichoo@example.com
Date: Mon Jun 18 12:31:32 CEST 2018
* display move
Making no changes: this is a dry run.
You can see that there is one change in the remote repository that I do not have
in my local copy yet. I can now decide if I really want to pull
this change or
not.
Instead of using --dry-run
you can of course always say no
to all of the
changes when the interactive prompt asks you if you would like to pull them in.
Whether you prefer this or --dry-run
is totally up to you.
As a side note, the --dry-run
flag is supported by other commands as well, it
is a common way to tell an operation that it should only show me what its
intentions are rather than actually performing an action. You can check the help
section of the individual commands to find out of they support this flag.
Once you start working with multiple people it becomes useful to know who had recorded what patches and how that affected a current file. Imagine you are working on an important and someone has written a patch you don't fully understand, maybe it's not a sufficiently documented change or you are just having a bad day and need the person who wrote that to help you understand what is going on.
Here we have a simple file but it presents us with an issue, who wrote which
line? Thankfully annotate
can be of assistance here.
$ cat text.txt
I wrote this!
I wrote this!
$ darcs annotate text.txt
1: patch abcb03dd0b39a08c6424700eac117f72fb465ea5
Author: raichoo@example.com
Date: Fri Jun 29 14:09:20 CEST 2018
* adding important information
2: patch 3f8ee5063a2697aeec8856246f7069ae8c9aafa5
Author: tauli@example.com
Date: Fri Jun 29 14:09:57 CEST 2018
* some more information
1: raichoo@example.com #1 | I wrote this!
2: tauli@example.com #2 | I wrote this!
The contents of the file does not help us a lot when we want to figure out who
contributed which line to the file. But annotate
presents us with a list of
involved changes and who recorded them. This can be immensely useful when trying
to find bugs or just figure out the right person to talk to about a particular
piece of code. Quite a lot of power you got there, remember to use it
responsibly. Fun fact: other version control systems tend to call this command
blame
, you can guess what some people are primarily using it for. Don't be
that person.