Version Control Systems: Fossil Part II

  • Tutorial
We continue the conversation about Fossil.

In the first part, we introduced the use of Fossil in single-user mode at one workstation. The next step is to transfer the repository to another computer - from work to home, or to a laptop, which we take with us on a trip. The easiest option is to simply copy the repository, since this is just one file, to a new workstation. You can do this, but the simplest solution is not always the best, there is a chance that there will be small problems.

Single-user mode of work at several workplaces.
The fact is that not only the version history is stored in the repository, but also some service information, in particular, the administrator name and password. The administrator name is automatically generated when creating the repository, usually this is the name of the user under which you are logged into the OS - and it may well turn out that this name on the computer where you are copying the repository is different from the one with which the repository was created. In this case, commit will fail, and you will have to add the required user using fossil ui , or add the --user parameter to fossil commit each time . A cleaner way is to clone an existing repository with fossil clone. As in the first part of the article, we will proceed from the assumption that we have Windows, that all our repositories are stored in a separate directory c: \ fossil, that we are working on a Castle project, the sources of which we want to be placed on another computer in c: \ projects \ castle \ source \. In addition, suppose we transfer the repository to a flash drive mounted as drive F. So, we clone:

fossil clone f:\castle.fossil c:\fossil\castle.fossil

And open for future use:

cd \projects\castle
fossil open c:\fossil\castle.fossil
In this case, the files included in the repository are unpacked into the current directory.

Before moving on, we need to understand the autosync parameter . If it is turned on (" on ", or 1), then when executing the fossil update command, an attempt will be made to first get the update from the remote repository ( pull ), and when fossil commit is executed , first pull and update , and immediately after commit , push (transfer) changes to the remote repository), and the address of the remote repository will be specified in the last executed clone , push ,pull , sync , remote-url . In our case, it will be f: \ castle.fossil, i.e., with each commit, Fossil will first try to contact the file on the flash drive, and if it is not inserted, then commit will not be executed - this is hardly what we want to. The included autosync is good if our remote repository is located on a server on the local network, i.e. almost always available. In the case when the remote repository is actually a file on a flash drive, with which we transfer the accumulated changes from one place to another, this may not be very convenient. Therefore, before you start working with the repository, disable autosync :

fossil settings autosync off

Now you can continue working on the project at a new workplace, saving changes to the local repository using commit as necessary . To transfer changes to other workstations, we use push (transferring changes from the local to the remote repository), pull (receiving changes from the remote to the local repository). You can use sync - this command does pull and push . Thus, our workflow is something like this:

Rewritten updates from a flash drive:
fossil pull f:\castle.fossil
fossil update
The update command modifies the working files according to the contents of the local repository. At the same time, the changes that we made in the working files after the last commit (in fact, in single-user mode do not need to!) Will not be lost - Fossil will try to merge (merge).
We worked on the project, saved the changes ( commit ) to the local repository and sent them to the remote:
fossil push f:\castle.fossil
We come to another workplace - and again: pull , update , work ..., commit , push .

You can, in principle, instead of push, simply physically copy the repository file to a flash drive - in the case of this single-user mode of operation, this is acceptable, but using push is a more “clean” option. What definitely should not be done is to physically copy the repository to the local one when this local one is open - in this case there may be a mismatch between the local repository and the service repository that was created as a result of its opening, which can lead to loss of information about the changes and, accordingly to unpleasant pads.

It’s more convenient, of course, not to carry the repository on a flash drive or other portable physical medium, but to keep it on the server. You can use a third-party service such as dropbox, or you can, if possible, place the repository on a server that is accessible to you for administration. We will consider this option further, especially since we will need it for organizing multi-user work (you can also use the services of sites that provide hosting options for Fossil repositories, for example, or Sourceforge , but I I will not stop here on this).

Installing the repository on the server.
Actually, the installation is performed in the same way as we did with the flash drive - we copy our local repository to the flash drive or to an accessible place on the server and make fossil clone . The question is how to provide access to this newly created remote repository, which URL to use in Fossil commands.
There are three options for connecting to a remote repository:

  • The easiest when the repository is in a shared directory,
  • Via ssh connection
  • Using an http server.

The first option, indeed, is the simplest; to implement it, you don’t need to do anything at all, except to clone the repository into the desired directory. Accessing it is no different from the flash drive option, just use the path to the directory how it is mounted on your computer. But this method limits you to the limits of your local network. There is another drawback: since in this case we are not working in client-server mode, but as with data on a file server, in the event of a failure (turning off the power to your computer, for example, or something with communication) while writing to a remote repository file there may be problems.

To use the ssh connection, you must have an ssh server, respectively, and the fossil executable file must be copied to this server. In this case, the repository URL in the Fossil command will look like this:

If an absolute path is used, then another slash must be placed before path . If the fossil executable is located in a directory unknown to the system (that is, unavailable by SET PATH), then add? Fossil = path_to_fossil / fossil to the URL.
Suppose we hosted our castle.fossil repository on a Linux server in / usr / local / fossil, and login on that server is alex. Then the push command , for example, may look like this (our server is
fossil push ssh://alex@ 
Once again, I note that in this case, the login to the server is used as the login, and not the repository username.

Now about the third option - the use of http - server. The simplest thing is to execute the fossil server command on the server - as a result, the http server will be launched there, the same as the fossil ui command we already know , the only difference is that now access to it is possible not only from local, but also from any other computer on the network, and now with web access we will have to log in to get full access to the repository. The URL in this case will look like this:

Let me remind you that the default port is 8080, it can be changed with the --port option of the fossil server command .
If the server already has an http server supporting CGI, you can use the Fossil executable as a CGI program (this is exactly how the official Fossil website works, according to the documentation). To do this, you need to put such a simple script in the CGI - directory on the server (usually a cgi-bin):

repository: /usr/local/fossil/castle.fossil

We assume here that the fossil executable is located in / usr / bin. Do not forget, of course, to set the necessary rights to the files of the repository, script and corresponding directories. If we named the castle script file, then the URL might look like this:

here userid is the repository username. And the push command will look like this:

 fossil push http://alex@

If the http server does not support CGI, you can configure the Fossil call through SCGI. You can raise a http service using inetd, xinetd or stunnel. You can read more about this in the Fossil documentation , here I describe only what I tried with my own hands.
The option of using http, in addition to the convenience of using it from any computer connected to the server via a local network or via the Internet, is also good because it provides a web service, we get, in fact, a project web server. Of course, the first thing that needs to be done is to configure access rights - in particular, for anonymous - all those who are not registered as a user in the repository.

If we continue to use the repository exclusively, then the workflow remains the same as when using the flash drive as the medium for the remote repository (only the URL changes): pull , update , work ..., commit , push . Although, if we use a resource permanently connected to the same address as a remote repository, we can reconsider the relation to the autosync parameter and set it to " on ". In this case, the duty cycle is reduced to update , work ..., commit - pull and pushwill be performed automatically. Do not forget to check which address of the remote repository will be used (usually the last one used in the clone , pull , push or sync commands ). This can be done with the fossil remote-url command . The same command can be used to set the desired URL by passing it as a parameter: fossil remote-url URL .

And one more important remark concerning both single-user and multi-user modes. Watch for the correct time setting on computers! When trying to commitwhen the current version in the local repository has a later date / time than the ones currently installed on the computer, the operation will not be completed and an appropriate message will be displayed. If the time on your computer is correct and you still need to make this commit , execute it with the --allow-older option . But it is better, of course, not to bring to such a situation.

Multiuser mode of operation.
The remote repository on the server is already installed. We create a local repository by cloning from a remote location (which URL to use in the previous section), add this user to the remote one, prescribe his rights and go ahead. The duty cycle is about the same as in single-user mode, only now pull andupdate must be done before each commit (if autosync is disabled, if enabled it is done automatically), since the remote repository could have been changed by another user since the previous pull .

Here a new, previously unknown situation may arise. You updated your work files ( pull , update ) and started editing them. Meanwhile, your colleague also edited something and sent it to the server ( commit , push ). You have finished your work and want to send the changes to the server. The following options are possible here:

1) Autosyncis on or off, but you do pull , update before commit , as expected. Update will try to merge (merge) and if it goes fine, then ... everything is fine. If the merge fails (for example, the changes were in the same line of the same file), then updatewill give a corresponding message, you will have 3 new files for each “unfailed” with extensions ending in -baseline, -merge and -original, and in the “unfused” files new lines will appear in each controversial place, starting with "<<< <<<< BEGIN MERGE CONFLICT: ... "and ending with" >>>>>>> END MERGE CONFLICT ... ", there will be both the previous version (COMMON ANCESTOR content) and your version (local copy content), and the version of your colleague (MERGED IN content). You will have to make the necessary changes yourself by editing the file, and then commit .

2) Autosync is turned off and you forgot to do pull , update before commit. Everything will pass without additional messages, without excesses, but at the same time, as a result of commit , a fork will be created in the repository - in fact, a new project branch. As the documentation says, in Fossil fork , this is an unwanted, unintended branch . The bad thing is that neither you nor your colleague can even notice this if you do not look at Timeline - there the bifurcation will immediately catch your eye. To correct this situation, you need to combine the formed branches with the fossil merge team . If the merge fails, then, as in the previous case, it will need to be done independently and made commit .
This second situation can arise not only as a result of forgetfulness, but also if you work offline for some time and are forced to save changes to the local commit repository without synchronizing it with the server. In this case, keep in mind that you can get a fork and check Timeline after sending the changes to the server. And one more thing : if you have Autosync enabled, but for some reason you want to get fork instead of combining your changes with those of other developers, you can run commit with the --allow-fork option .

I will not talk here about why the project needs to be forked, why and in what cases to use it, I will just tell you briefly how it is implemented in Fossil. Suppose we want to create a new branch ver_2_0:

 fossil branch new ver_2_0 trunk
trunk is the branch from which we branch, trunk is the name of the main "trunk" of any project. If we now execute the fossil branch list command , then we will see that we now have 2 branches - trunk and ver_2_0, and the trunk branch is marked with the “*” sign - this means that it is the current one. Creating a new branch does not change the status of working files - we are still in the old trunk branch, this can also be checked with the fossil status command . To go to the new branch, do

 fossil checkout ver_2_0
or fossil co ver_2_0 , it's the same thing. The checkout command replaces the working files with those in the local repository and sets the specified branch (if one is specified) as the current one. Now all of our subsequent changes will relate to the ver_2_0 branch. If we need to make the changes in the trunk branch that we worked out in ver_2_0, go to trunk and merge:

fossil co trunk
fossil merge ver_2_0

When combining, conflicts can arise - I talked about how to deal with them above.

There are also so-called personal branches, they remain in the local repository and are not transferred to the server, such branches are formed if the --private parameter is added to the branch command .

Well, that’s all that I planned to tell. Of course, not all issues were covered here, not all the teams and not all parameters (I think, even a smaller part) of the teams that were discussed. But there is documentation for this. There is still an interesting topic that was worth mentioning - the possibility of creating my own scripts in the built-in Tcl - similar to the TH language, but I myself still did not understand this.

In the end, I would like to answer the question that was most often asked in the comments to the first part of the article: why Fossil is better than Git or Mercurial.
I’m not trying to persuade anyone to switch to Fossil with another VCS, moreover, I consider it unproductive to change the VCS that you use to another if everything suits you and there are no serious reasons for migration. The version control system is just a tool and it should not be in the forefront in your work. Another thing, if you only select VCS for yourself - in this case it is worth considering Fossil as a completely worthy option that provides all the necessary features.
Is it better or worse? This is largely a matter of personal preference. I like the minimalism of Fossil. I like that to install that client, that the server you just need to copy one file, that there is no need to raise a separate service for the server, that I can carry on the flash drive two small executable files (for Windows and for Linux) and several files - repositories - and this enough to use it anywhere. It seems to me convenient its web - interface and it seems important that it can be used locally. I like that bug-tracking and wiki are built into the system, their data is stored in the same repository and tightly integrated with the rest of the repository, that you can work with them offline, you do not need to use third-party web services and worry about your data in if these services are closed or their policies change.

Also popular now: