FossilBook

Multiple users
Login

Multiple users

Introduction

In the previous chapter I went through using Fossil with just one user (me). In this chapter we will get into using it with multiple users. Thanks to Fossil's distributed design once the set up is done using it is not much different than the single user case with Fossil managing automatically the multiple user details.

Setup

In the previous chapter the Fossil repository was a file on our system and we did commits to it and pulled copies of the source from it. Fossil is a distributed source control system. What this means is that there is a remote server repository in a place that all users can access. Each user has their own "cloned" copy of the repository and Fossil will automatically synchronize the users repository with the remote repository. From a each user's perspective you have your local repository and work with it using the same commands shown in chapter [Single user]. It's just that now Fossil will keep your local repository in sync with the remote repository. This remote repository acts as a server.

Remote server

I have the FossilBook.fossil repository and now have to put it in place so multiple users can access it. There are two ways, the first is using fossil's built in webserver to host the file and the second is using the operating systems supported web server (if present) and a cgi type access.

Self hosted

A self-hosted server is quite simply the easiest way to do it. The downside is that you are responsible for keeping the machine available and the webserver up. That is, don't turn the machine off when you quit for the day or some other user is going to be upset. All I have to do is this:

::: Shell $ fossil server FossilBook.fossil & :::

This is on a UNIX system, the "&" at then end of the command line runs the fossil webserver in the background. If I know this machine has an IP address of 192.168.1.200 then from any other machine in the network I can type into my browser:

http://192.168.1.200:8081

and I can access the Fossil web server.

As you can see this is simple and works on any system that runs Fossil. As long as you carefully make sure it's always running and available for others this can be a very easy way to make the repository remotely available.

The problems with this method are:

  1. If you have multiple repositories you have to use the server not the ui command, have all your repositories in the same directory, and have them all use the extension .fossil.

  2. If the machine goes offline (i.e. for OS update) or other reason it might not automatically restart the Fossil servers.

  3. Backup of the repositories might not be done.

This method does work, and if you only have one repository and a diligent owner of the remote machine, it will work and work well.

Server hosted

If you have a server type machine available (i.e., a Linux or UNIX box) that is running Apache or a Windows machine running IIS you can let it be the webserver for your repository. This has a number of advantages: this machine will be up all the time, it will probably be automatically backed up, and it can easily support multiple Fossil repositories.

I am not going into how to set up the webserver or how to enable CGI (Common Gateway Interface). See the following sites:

If you are not in control of the webserver you will need the help of the server admin to enable CGI and to copy your CGI scripts to the correct location.

CGI Script for hosted server

If we assume an Apache server and, in my case, the cgi directory path is /Library/Webserver/CGI-Executables, then we have to write a script of the form:

#! <Fossil executable location> repository: <Fossil repository location>

and put it into the cgi script directory. I have put my Fossil executable into /usr/local/bin and I am putting my Fossil shared repository into /Users/Shared/FOSSIL. My script then becomes:

>  #!/usr/local/bin/fossil # Put the book repository on the web repository: /Users/Shared/FOSSIL/Fossilbook.fossil

After making the script I then copy it to the CGI directory and allow anyone to execute it.

sudo cp Book.cgi /Library/Webserver/CGI-Executables/Book.cgi

Local server

Actually, you can also use Fossil as a "local server". What this means is that the Fossil repository can just be located in any folder on your machine and then clone from there. It must not be a remote machine. People using this just need to have read/write access to that file path where the repository is located. So, assume you have put your repository into /var/repos/myRepo.fossil. Then, all users with read/write access can just do:

::: Shell $ fossil clone /var/repos/myRepo.fossil ~/myClone.fossil $ mkdir ~/src $ cd ~/src $ fossil open ~/myClone.fossil :::

When you then work on the files and commit your code later, it will be automatically synchronized (using the default behaviour of autosync on) to the repository in /var/repos/myRepo.fossil. The drawback of this method is that you do not have good control over what each individual user can do. If you need that, user fossil server instead.

Test the setup

If all is in place then I should be able to access the webserver and get to this:

Web access to Fossil CGI hosted site - placeholder

User accounts

Serving a repository, either self hosting or the more complicated CGI method gets you to the same place as shown in Figure [fig:Web-access-to]. Now I have to set up user accounts for the other contributors to this book. Remember Fossil has automatically created an Anonymous user (see Figure [fig:User-Configuration]) thus others can access the site in a limited way, that is they can download the book but cannot commit changes. In this case I want to create a new account (Marilyn) that can make changes and commit changes as she is my editor.

To accomplish all this first I have to login by going to the log in page and entering my ID (jim) and my password. Now since I'm super-user I then go back to the User-Configuration page, Figure [fig:User-Configuration] and add a new user:

   New Editor user - placeholdere

Since she is going to be an editor, this will be similar to a developer if we were doing code, so I picked the Developer privilege level. This way she can get the repository, check-in, check-out, and write and update tickets. I also added the attachments since she might need that to put on an image or other comment on actions she is doing. I also gave her a password so her access can be secured.

I could add other users at this point but don't need any others for this project, but you can see how easily this can be done. When you assign the user privileges just read carefully and don't give them any more than you think they need. If they have problems, you can easily modify their account in the future.

Multiple user operation

With the server set up and the user established the next thing to do is clone the repository. This means to make a copy of the webserver repository on my local machine. Once that is done this local repository uses the same commands and is very much like single the user use discussed in section [Single user]. Fossil will synchronize your local repository with the one on the server.

Cloning

To clone a Fossil repository you have to know four things:

  1. It's web address, for our repository. It is https://fossil-scm.org/FossilBook

  2. Your account name, in my case it's jim

  3. Your password (which I'm keeping to myself thank you...)

  4. The local name of the repository, in this case I'm calling it FossilBook.fossil

You then go to where you want to keep the repository (in my case the FOSSIL directory) and use the clone command:

::: Shell $ fossil clone https://jim:@fossil-scm.org/FossilBook FossilBook.fossil :::

At this point I can go through the steps outlined in section [Single user] to set my user password and then open the Fossil repository on a working directory.

Now that I've moved everything to the new cloned repository I do a check-in the end of the day which looks like this:

::: Shell $ fossil commit -m "Moved to clone repository" :::

As you see the files were committed locally and then the local repository was automatically synchronized with the repository on the server.

Keeping the code in sync

After doing all the setup described above I now have a distributed source control system. My co-worker, Marilyn has also cloned the repository and begun work. She is editing the book correcting my clumsy phrasing and fixing spelling mistakes. She is working independently and on the same files I use. We must use Fossil to prevent us from both modifying the same files but in different ways. Remember Fossil has no file locking, there is nothing to prevent her from editing and changing a file while I work on it.

This is where we both must follow procedures to prevent this sort of problem. Even though she edits files I cannot see the changes till they are committed. Two different versions of the same file won't be a problem till I try to commit with my version and her version is in the current leaf.

There are two problems:

  1. Before I do any work I must be sure I have the current versions of all the files.

  2. When I commit I must make sure what I am committing has only my changes and is not stepping on changes she has done.

The first is pretty obvious. You make sure you have the latest version before you do anything. We do that with the fossil update command. In figure [fig:Cloned-repository-checkin] I had done my latest check-in. Before starting any more work I should ensure that Marilyn hasn't checked in something else. I could check the timeline but instead I'll do an update to my repository and source files. When I do the update I specify it should be updated from the trunk. This ensures I get it from the latest and greatest ... and not some branch.

::: Shell $ fossil update trunk :::

Ah ha! Marilyn has been at work and updated the book source and pdf. If I check the timeline from the webserver I see she has even documented it:

Now I know I have the current state of the world and I can proceed to add in new sections.

::: GoodToKnow In the default configuration, Fossil operates in 'auto-sync' mode (configurable with the fossil settings command). This means that Fossil makes sure changes by others are synced from the Fossil server when the fossil update command is used. When doing a commit, Fossil will automatically push your changes back to the server you cloned from or most recently synced with. When doing an update, Fossil will first go to that same server and pull the recent changes to your local repository, then merge them into your local source tree. :::

Complications

The second problem described in section [Keeping the code in sync] is much harder. In this case I have diligently done my fossil update and started working. In the mean time Marilyn has also done her update and also started working. Now she is done and checks in her changes. I obviously don't know this since I am happily working on my changes. What happens next ...

::: Shell $ fossil commit -m "Commit that might fork" :::

Ah ha, that very thing has happened and Fossil warned me that my copy of the file differs from the master copy. If I had provided the option –force to the commit then the repository would generate a fork and Marilyn's future commits would be to her fork and my commits would be to mine. That would not be what we want since I want her to edit my copy of the book.

The next step would be to do as Fossil says and do an update. At this point you have to be careful since blindly updating the changed files could overwrite the stuff I've just done. So we do a trial update by using the -n and -v options to say "do a dry run" and show me the results_

::: Shell $ fossil update -n -v :::

That's a little more than I wanted as you can see almost everything is UNCHANGED but it shows that my file needs a MERGE and fossilbook.pdf needs an UPDATE. This is what I should expect, Marilyn has done edits to the ... file and so have I. So we have to merge the changes. But she has also updated the fossilbook.pdf which I have not. Before we go on if you are running on Linux or UNIX you can simplify this dry run by doing:

::: Shell $ fossil update -n -v | grep -v UNCHANGED :::

By using the pipe and grep I can eliminate all those extra UNCHANGED lines.

Fixing the update file

First we fix the easy file, the fossilbook.pdf I can just update by itself so it matches the current repository. It doesn't need to be merged, so I just replace it. Before I do that I have to look at the repository time line

Placeholder for Timeline figure

I see that the current Leaf is ...[d44769cc23]... and it is tagged as trunk. I want to update the fossilbook.pdf from there. So I say:

::: Shell $ fossil update trunk fossilbook.pdf :::

and it's done.

Fixing the merge file

We can use the tools built into Fossil. In this case noticing that commit will cause a fork, Jim will use the -force option to cause the fork and will handle the merge later.

::: Shell > fossil commit -m "adding some changes of jim" :::

Now the timeline looks like:

Placeholder for Timeline figure

To remove this fork (i.e. get the changes Marilyn did into the trunk) we use the Fossil merge command. We can use the merge because ...fossilbook.lyx... is a text file and the merge markers are designed to work with text files. If it was a binary file we might have to use an external file or copy and paste between the two file versions using the handler program for the file.

::: Shell > fossil merge a91582b699 :::

Looking at the file (fossilbook.lyx) in a text editor (not LyX) we find:

> \>>>>>>> BEGIN MERGE CONFLICT

Placeholder for now

After the commit the timeline shows how the merge brought the fork back into the main trunk. Marilyn will then have to update to this new trunk. (See Section [sub:Updating-by-others])

More on merge conflicts

Sometimes, you may get notified about a merge conflict when updating (fossil update) your locally changed code due to changes others have done and already commited. That means Fossil cannot resolve this by itslf. Fossil cannot figure out how to combine your own and the other person's changes. It simply can't know which is the right code. Apart from the possibility of doing a fossil undo and re-investigate the situation manually, you can also look at the merged file and resolve the conflicts there. This is how a merge conflict looks like (the example is some Tcl code):

<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<< (line 83)
	if {$myvar eq "one"} {::do::something $myvar}

||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||| (line 83)
	
======= MERGED IN content follows =============================== (line 67)
	if {$myvar eq "one"} {::do::something $myvar; puts "Hello"}
>>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

What does this all mean? The merge conflict is shown as three parts: It always starts with a line of <<<<<, has a line with |||| somewhere in between and ends with another line of >>>>>. The first part is the local copy. This is your own edits to the file. Then you see the common ancestor. That is how the file looked before both persons started editing this particular location in the file. At the end is the merged in content. That is what the other person did to the file. So, you have your own edits, the clean prior version and the other person's edits. Now, you just need to decide which of the three versions is correct. It might be that your edit is correct and the other person did it wrongly or had no right to actually change this part. Then, just delete the second and thrid part and remove the lines that Fossil inserted to mark the conflict. If your version didn't get it right, just remove the first and second part. However, it can well be that both participants have got it right, just in different places. Then you have to manually figure out which parts of your own version should stay and you will manually merge the code from both versions.

Sharing other changes than code

Sharable content

When multiple users are working on the code, they may also want to use their local clone of the repository for tickets, the wiki and other stuff. So, while the local code changes are synchronized with the server using the fossil commands update and commit (or pull and push if you do it manually), other parts of the repository are not synchronized. If you want to see the current set of tickets or the wiki in your local copy of the repository as well, you need to synchronize those with the command fossil sync.

This command will synchronize all sharable content:

This is particularly useful if you cannot work on the remote server for a reason. You can start your local server with fossil ui, make changes to e.g. wiki pages and the sync the changes back to the remote server with fossil sync.

Synchronize the Fossil configuration

When cloning the remote repository, you also get the current configuration of the repository. This includes e.g. the skin and the ticket setup. When these settings change on the server, they will not automatically be synchronized with your local clone of the repository. So you may end up in a situation where you create a new ticket locally that does not reflect the structure of the tickets on the server because the server configuration has changed! So, if some important configuration changes on the server, you can (and should) pull those changes into your local clone. This is done using the fossil configuration command (see the section on the configuration command for all details). It can be used to change the configuration of the following areas:

So, to pull a changed ticket configuration into the local clone, you issue the following command:

::: Shell > fossil configuration pull ticket :::

Using the configuration command, you can also import and export configurations via text files and even do a kind of merge operation. This makes it possible to edit more complex configurations in an editor of your choice (e.g. when you want to have some syntax highlighing). You can also push your local changes back to the server but that will require administeation priviliges on the remote server. Last but not least, you may want to do a 'real' sync, synchronizing configuration changes in the local repository with the remote repository. When you use the keyword 'all' for the area, all of the above areas will be synchronized:

::: Shell > fossil configuration sync all :::