<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Initial Commit</title>
    <description>The latest articles on DEV Community by Initial Commit (@initialcommit).</description>
    <link>https://dev.to/initialcommit</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F277961%2F2cf8764e-4232-42fb-b9f2-3b15bbe66860.jpg</url>
      <title>DEV Community: Initial Commit</title>
      <link>https://dev.to/initialcommit</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/initialcommit"/>
    <language>en</language>
    <item>
      <title>A Technical Guide To Version Control System (VCS) Internals</title>
      <dc:creator>Initial Commit</dc:creator>
      <pubDate>Sun, 01 Dec 2019 17:04:59 +0000</pubDate>
      <link>https://dev.to/initialcommit/a-technical-guide-to-version-control-system-vcs-internals-4h46</link>
      <guid>https://dev.to/initialcommit/a-technical-guide-to-version-control-system-vcs-internals-4h46</guid>
      <description>&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this article, we'll provide a technical comparison of some of the most historically significant Version Control Systems (or VCS). We will discuss the following six VCS (we plan to add others in the future):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;First Generation&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SCCS (Source Code Control System)&lt;/li&gt;
&lt;li&gt;RCS (Revision Control System)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Second Generation&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CVS (Concurrent Versions System)&lt;/li&gt;
&lt;li&gt;SVN (Apache Subversion)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Third Generation&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Git&lt;/li&gt;
&lt;li&gt;Mercurial&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first generation VCS were intended to track changes for individual files and checked-out files could only be edited locally by one user at a time. They were built on the assumption that all users would log into the same shared Unix host with their own accounts. The second generation VCS introduced networking which led to centralized repositories that contained the 'official' versions of their projects. This was good progress, since it allowed multiple users to checkout and work with the code at the same time, but they would all be committing back to the same central repository. Furthermore, network access was required to make commits. The third generation comprises the distributed VCS. In a distributed VCS, all copies of the repository are created equal - there is no central copy of the repository. This opens the path for commits, branches, and merges to be created locally without network access and pushed to other repositories as needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  VCS Release History Timeline
&lt;/h2&gt;

&lt;p&gt;For context, here is a timeline of the creation of these VCS tools:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Figure 1: Timeline of the Creation of Version Control Systems&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;img src="https://initialcommit.com/img/blog/vcs-timeline.png" alt="Timeline of the creation of Version Control Systems" title="Timeline of the creation of Version Control Systems"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  SCCS - Source Code Control System - First Generation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Background
&lt;/h3&gt;

&lt;p&gt;SCCS is considered to be one of the first successful VCS tools created. It was developed by Marc Rochkind at Bell Labs in 1972. It is written in C and was created to solve the problems of source file revision tracking. Furthermore, it made it significantly easier to track down the source of bugs introduced into a program. SCCS is worth understanding at a basic level because it is the seed of the set of modern VCS tools that are so important to developers today.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;

&lt;p&gt;Like most modern day VCS, SCCS has a set of commands that allow developers to work with versioning of their files. These commands are used to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check in files to have their history tracked using SCCS&lt;/li&gt;
&lt;li&gt;Check out specific file revisions for review or compilation&lt;/li&gt;
&lt;li&gt;Check out specific file revisions for editing&lt;/li&gt;
&lt;li&gt;Check in new file revisions along with a comment explaining the changes&lt;/li&gt;
&lt;li&gt;Revert changes made in a checked out file&lt;/li&gt;
&lt;li&gt;Basic branching and merging of changes&lt;/li&gt;
&lt;li&gt;Provide a log of a file's revision history&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A special type of file called an &lt;code&gt;s-file&lt;/code&gt; or a &lt;code&gt;history file&lt;/code&gt; is created when a file is added for tracking with SCCS. This file is named using the original file name prefixed with a &lt;code&gt;s.&lt;/code&gt; and is stored in a subdirectory called &lt;code&gt;SCCS&lt;/code&gt;. So a file called &lt;code&gt;test.txt&lt;/code&gt; would get a history file created in the &lt;code&gt;./SCCS/&lt;/code&gt; directory with a name of &lt;code&gt;s.test.txt&lt;/code&gt;. On creation, the history file contains the initial content of the original file as well as some metadata to assist with version tracking. Checksums are stored in the history files to verify that the content has not been tampered with. The history file content is not compressed or encoded (as we will see is the case with the later generation VCS).&lt;/p&gt;

&lt;p&gt;Since the content of the original file is now stored in the history file, it can be retrieved into the working directory for review, compilation, or editing. Further changes made to the file such as line additions, modifications, and removals can be checked back into the history file, which increments its revision number.&lt;/p&gt;

&lt;p&gt;Subsequent SCCS checkins only store only the &lt;code&gt;deltas&lt;/code&gt; or changes to a file as opposed to the entire file content each time. This decreases the size of the history file. Each time a checkin is made, the delta is stored in a structure known as a &lt;code&gt;delta table&lt;/code&gt; inside the history file. As previously mentioned, the actual file content is more or less copied verbatim, with special control sequences for marking the start and end of sections of added and removed content. Since SCCS history files don't use compression, they are typically larger in size that the actual file being tracked. SCCS uses a delta method known as &lt;code&gt;interleaved deltas&lt;/code&gt;. This is beneficial since it allows constant-time checkouts regardless of how old the checked out revision is - i.e. older revisions don't take longer to checkout than newer revisions.&lt;/p&gt;

&lt;p&gt;One important thing to note is that all files are tracked and checked in separately in SCCS. There is no way to checkin changes to multiple files as a part of one atomic unit - like a commit in Git. Each tracked file has a corresponding history file which stores its revision history. In general, this means that the version numbers of different files in a project will not usually match each other. However, matching revision numbers can be achieved by editing every file in the project at once (even if not all of the files have real changes) and checking them all at one time. This will increment the revision number for all the files to keep them consistent, but note that this is NOT the same as including multiple files in a single commit like in Git. In SCCS, this makes an individual checkin in each history file, as opposed to one big commit including all the changes at once.&lt;/p&gt;

&lt;p&gt;When a file is checked out for editing in SCCS, a lock is placed on the file so it cannot be edited by anyone else. This prevents changes from being overwritten by other users, but also limits development since only one user can work with a given file at a time.&lt;/p&gt;

&lt;p&gt;SCCS has support for branches that can store sequences of changes within a specific file. Branches can be merged back in with the original versions or merged with other branched versions of the same parent.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Commands
&lt;/h3&gt;

&lt;p&gt;Below is a list of the most common SCCS commands.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sccs create &amp;lt;filename.ext&amp;gt;&lt;/code&gt;: Check in a new file to SCCS and create a new history file for it (in the &lt;code&gt;./SCCS/&lt;/code&gt; directory by default).&lt;br&gt;&lt;br&gt;
&lt;code&gt;sccs get &amp;lt;filename.ext&amp;gt;&lt;/code&gt;: Check out a file from from its corresponding history file and place it in the working directory in readonly mode.&lt;br&gt;&lt;br&gt;
&lt;code&gt;sccs edit &amp;lt;filename.ext&amp;gt;&lt;/code&gt;: Check out a file from the corresponding history file for editing. Locks the history file so no other users can modify it.&lt;br&gt;&lt;br&gt;
&lt;code&gt;sccs delta &amp;lt;filename.ext&amp;gt;&lt;/code&gt;: Check in the modifications to the specified file. Will prompt for a comment, store the changes in the history file, and remove the lock.&lt;br&gt;&lt;br&gt;
&lt;code&gt;sccs prt &amp;lt;filename.ext&amp;gt;&lt;/code&gt;: Display the revision log for a tracked file.&lt;br&gt;&lt;br&gt;
&lt;code&gt;sccs diffs &amp;lt;filename.ext&amp;gt;&lt;/code&gt;: Display the differences between the current working copy of a file and the state of the file when it was checked out. &lt;/p&gt;

&lt;p&gt;For more information on SCCS internals, see &lt;a href="http://sccs.sourceforge.net/man/sccs.me.html"&gt;Eric Allman's guide&lt;/a&gt; and this &lt;a href="https://docs.oracle.com/cd/E19504-01/802-5880/6i9k05dhp/index.html"&gt;Oracle guide on programming utilities&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sample SCCS History File
&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;pre class="highlight"&amp;gt;&amp;lt;code&amp;gt;^Ah20562                                                                                                                                                                           
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;^As 00001/00001/00002&lt;br&gt;
^Ad D 1.3 19/11/26 14:37:08 jack 3 2 &lt;br&gt;
^Ac Here is a comment.&lt;br&gt;
^Ae&lt;br&gt;
^As 00002/00000/00001&lt;br&gt;
^Ad D 1.2 19/11/26 14:36:00 jack 2 1 &lt;br&gt;
^Ac No. &lt;br&gt;
^Ae&lt;br&gt;
^As 00001/00000/00000&lt;br&gt;
^Ad D 1.1 19/11/26 14:35:27 jack 1 0 &lt;br&gt;
^Ac date and time created 19/11/26 14:35:27 by jack&lt;br&gt;
^Ae&lt;br&gt;
^Au&lt;br&gt;
^AU&lt;br&gt;
^Af e 0 &lt;br&gt;
^At&lt;br&gt;
^AT&lt;br&gt;
^AI 1&lt;br&gt;
Hi there&lt;br&gt;
^AE 1&lt;br&gt;
^AI 2&lt;br&gt;&lt;br&gt;
^AD 3&lt;br&gt;
This is a test of SCCS&lt;br&gt;
^AE 2&lt;br&gt;
^AE 3&lt;br&gt;
^AI 3&lt;br&gt;
A test of SCCS&lt;br&gt;
^AE 3&lt;/p&gt;

&lt;h2&gt;
  
  
  RCS - Revision Control System - First Generation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Background
&lt;/h3&gt;

&lt;p&gt;RCS was written in C by Walter Tichy in 1982 as an alternative to SCCS, which wasn't open source at the time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;

&lt;p&gt;RCS shares many traits with its predecessor, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Handling revisions on a file-by-file basis&lt;/li&gt;
&lt;li&gt;Changes across multiple files can't be grouped together into an atomic commit&lt;/li&gt;
&lt;li&gt;Tracked files are intended to be modified by one user at a time&lt;/li&gt;
&lt;li&gt;No network functionality&lt;/li&gt;
&lt;li&gt;Revisions for each tracked file are stored in a corresponding history file&lt;/li&gt;
&lt;li&gt;Basic branching and merging of revisions within individual files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When a file is set checked into RCS for the first time, a corresponding history file is created for it in the local &lt;code&gt;./RCS/&lt;/code&gt; directory. This file is postfixed with a &lt;code&gt;,v&lt;/code&gt; so a file named &lt;code&gt;test.txt&lt;/code&gt; would be tracked by a file called &lt;code&gt;test.txt,v&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;RCS uses a &lt;code&gt;reverse-delta&lt;/code&gt; scheme for storing file changes. When a file is checked in, a full snapshot of the file's content is stored in the history file. When the file is modified and checked in again, a delta is calculated based off of the existing history file content. The old snapshot is discarded and the new one is saved, along with the delta to get back to the older state. This is called &lt;code&gt;reverse-delta&lt;/code&gt; since to check out an older revision, RCS starts with the newest version of the file and applies consecutive deltas until the older revision is reached. This method requires allows for very quick checkouts of current revisions since the full snapshot of the current snapshot is always available. However, the older the checkout revision, the longer the checkout takes since an increasing number of deltas need to be calculated against the current snapshot.&lt;/p&gt;

&lt;p&gt;This is not the case with SCCS which takes the same amount of time to fetch any revision. In addition, no checksum is stored in RCS history files so file integrity cannot be ensured.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Commands
&lt;/h3&gt;

&lt;p&gt;Below is a list of the most common RCS commands:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ci &amp;lt;filename.ext&amp;gt;&lt;/code&gt;: Check in a new file to RCS and create a new history file for it (in the &lt;code&gt;./RCS/&lt;/code&gt; directory by default).&lt;br&gt;&lt;br&gt;
&lt;code&gt;co &amp;lt;filename.ext&amp;gt;&lt;/code&gt;: Check out a file from from its corresponding history file and place it in the working directory in readonly mode.&lt;br&gt;&lt;br&gt;
&lt;code&gt;co -l &amp;lt;filename.ext&amp;gt;&lt;/code&gt;: Check out a file from the corresponding history file for editing. Locks the history file so no other users can modify it.&lt;br&gt;&lt;br&gt;
&lt;code&gt;ci &amp;lt;filename.ext&amp;gt;&lt;/code&gt;: Check in file changes and create a new revision for it in its corresponding history file.&lt;br&gt;&lt;br&gt;
&lt;code&gt;merge &amp;lt;file-to-merge-into.ext&amp;gt; &amp;lt;parent.ext&amp;gt; &amp;lt;file-to-merge-from.ext&amp;gt;&lt;/code&gt;: Merge changes from two modified children of the same parent file.&lt;br&gt;&lt;br&gt;
&lt;code&gt;rcsdiff &amp;lt;filename.ext&amp;gt;&lt;/code&gt;: Display the differences between the current working copy of a file and the state of the file when it was checked out.&lt;br&gt;&lt;br&gt;
&lt;code&gt;rcsclean&lt;/code&gt;: Removes working files that don't have locks.&lt;/p&gt;

&lt;p&gt;For more information on RCS internals, see the &lt;a href="https://www.gnu.org/software/rcs/manual/rcs.html"&gt;GNU RCS manual&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sample RCS History File
&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;pre class="highlight"&amp;gt;&amp;lt;code&amp;gt;head    1.2;                                                                                                                                                                       
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;access;&lt;br&gt;
symbols;&lt;br&gt;
locks; strict;&lt;br&gt;
comment @# @;&lt;br&gt;&lt;br&gt;&lt;br&gt;
1.2&lt;br&gt;
date    2019.11.25.05.51.55;    author jstopak; state Exp;&lt;br&gt;
branches;&lt;br&gt;
next    1.1;&lt;br&gt;&lt;br&gt;
1.1&lt;br&gt;
date    2019.11.25.05.49.02;    author jstopak; state Exp;&lt;br&gt;
branches;&lt;br&gt;
next    ;&lt;br&gt;&lt;br&gt;&lt;br&gt;
desc&lt;br&gt;
@This is a test.&lt;br&gt;
@&lt;br&gt;&lt;br&gt;&lt;br&gt;
1.2&lt;br&gt;
log&lt;br&gt;
@Edited the file.&lt;br&gt;
@&lt;br&gt;
text&lt;br&gt;
&lt;a class="comment-mentioned-user" href="https://dev.to/hi"&gt;@hi&lt;/a&gt;
 there, you are my bud.&lt;br&gt;&lt;br&gt;
You are so cool!&lt;br&gt;&lt;br&gt;
The end.&lt;br&gt;
@&lt;br&gt;&lt;br&gt;&lt;br&gt;
1.1&lt;br&gt;
log&lt;br&gt;
@Initial revision&lt;br&gt;
@&lt;br&gt;
text&lt;br&gt;
@d1 5&lt;br&gt;
a5 1&lt;br&gt;
hi there&lt;br&gt;
@&lt;/p&gt;

&lt;h2&gt;
  
  
  CVS - Concurrent Versions System - Second Generation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Background
&lt;/h3&gt;

&lt;p&gt;CVS was created by Dick Grune in 1986 with the goal of adding a networking element to version control. It is also written in C. CVS kicked off the second generation of VCS tools which allowed geographically dispersed development teams to work on projects together.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;

&lt;p&gt;CVS is a frontend for RCS - it provides a set of commands for interacting with files in a project, but uses the RCS history file format and commands behind the scenes. For the first time in VCS history, CVS allowed multiple developers to check out and work on the same files simultaneously. It did this by using a centralized repository model. The first step is to set up a centralized repository on a remote server using CVS. Projects can then be imported into the repository. When a project is imported into CVS, each file is converted into a &lt;code&gt;,v&lt;/code&gt; history file and stored in a central directory known as a &lt;code&gt;module&lt;/code&gt;. The repository generally lives on a remote server which is accessible over a local network or the Internet.&lt;/p&gt;

&lt;p&gt;A developer checks out a copy the module which is copied to a working directory on their local machine. No files are locked in this process so there is no limit to the number of developers that can check out the module at one time. Developers can modify their checked out files and commit their changes as needed. If a developer commits a change, other developers will need to update their working copies via a (usually) automated merge process before committing their changes. Occasionally merge conflicts will need to be manually resolved before the commit can be made. CVS also provides the ability to create and merge branches.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Commands
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;export CVSROOT=&amp;lt;path/to/repository&amp;gt;&lt;/code&gt;: Sets the CVS repository root directory so it doesn't need to be specified in each command.&lt;br&gt;&lt;br&gt;
&lt;code&gt;cvs import -m 'Import module' &amp;lt;module-name&amp;gt; &amp;lt;vendor-tag&amp;gt; &amp;lt;release-tag&amp;gt;&lt;/code&gt;: Import a directory of files into a CVS module. Before running this browse into the root directory of the project you want to import.&lt;br&gt;&lt;br&gt;
&lt;code&gt;cvs checkout &amp;lt;module-name&amp;gt;&lt;/code&gt;: Copy a module to the working directory.&lt;br&gt;&lt;br&gt;
&lt;code&gt;cvs commit &amp;lt;filename.ext&amp;gt;&lt;/code&gt;: Commit a changed file back to the module in the central repository.&lt;br&gt;&lt;br&gt;
&lt;code&gt;cvs add &amp;lt;filename.txt&amp;gt;&lt;/code&gt;: Add a new file to track revisions for.&lt;br&gt;&lt;br&gt;
&lt;code&gt;cvs update&lt;/code&gt;: Update the working copy by merging in committed changes that exist in the central repository but not the working copy.&lt;br&gt;&lt;br&gt;
&lt;code&gt;cvs status&lt;/code&gt;: Show general information about the checked out working copy of a module.&lt;br&gt;&lt;br&gt;
&lt;code&gt;cvs tag &amp;lt;tag-name&amp;gt; &amp;lt;files&amp;gt;&lt;/code&gt;: Add an identifying tag to a single file or set of files.&lt;br&gt;&lt;br&gt;
&lt;code&gt;cvs tag -b &amp;lt;new-branch-name&amp;gt;&lt;/code&gt;: Create a new branch in the repository (must be checked out before working on it locally).&lt;br&gt;&lt;br&gt;
&lt;code&gt;cvs checkout -r &amp;lt;branch-name&amp;gt;&lt;/code&gt;: Checkout an existing branch to the working directory.&lt;br&gt;&lt;br&gt;
&lt;code&gt;cvs update -j &amp;lt;branch-to-merge&amp;gt;&lt;/code&gt;: Merge an existing branch into the local working copy.&lt;/p&gt;

&lt;p&gt;For more information on CVS internals, see the &lt;a href="https://www.gnu.org/software/trans-coord/manual/cvs/html_node"&gt;GNU CVS manual&lt;/a&gt; and &lt;a href="https://dickgrune.com/Programs/CVS.orig"&gt;Dick Grune's article&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sample CVS History File
&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;pre class="highlight"&amp;gt;&amp;lt;code&amp;gt;head     1.1;                                                                                                                                                                      
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;branch   1.1.1;&lt;br&gt;
access   ;&lt;br&gt;&lt;br&gt;
symbols  start:1.1.1.1 jack:1.1.1;&lt;br&gt;
locks    ; strict;&lt;br&gt;
comment  @# @;&lt;br&gt;&lt;br&gt;&lt;br&gt;
1.1&lt;br&gt;
date     2019.11.26.18.45.07;  author jstopak;  state Exp;&lt;br&gt;
branches 1.1.1.1;&lt;br&gt;
next     ;&lt;br&gt;&lt;br&gt;
commitid        zsEBhVyPc4lonoMB;&lt;br&gt;&lt;br&gt;
1.1.1.1&lt;br&gt;
date     2019.11.26.18.45.07;  author jstopak;  state Exp;&lt;br&gt;
branches ;&lt;br&gt;
next     ;&lt;br&gt;&lt;br&gt;
commitid        zsEBhVyPc4lonoMB;&lt;br&gt;&lt;br&gt;&lt;br&gt;
desc&lt;br&gt;
@@&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;
1.1&lt;br&gt;
log&lt;br&gt;
@Initial revision&lt;br&gt;
@&lt;br&gt;
text&lt;br&gt;
&lt;a class="comment-mentioned-user" href="https://dev.to/hi"&gt;@hi&lt;/a&gt;
 there&lt;br&gt;
@&lt;br&gt;&lt;br&gt;&lt;br&gt;
1.1.1.1&lt;br&gt;
log&lt;br&gt;
@Imported sources&lt;br&gt;
@&lt;br&gt;
text&lt;br&gt;
@@&lt;/p&gt;

&lt;h2&gt;
  
  
  SVN - Subversion - Second Generation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Background
&lt;/h3&gt;

&lt;p&gt;Subversion was created in 2000 by Collabnet Inc and is now maintained by the Apache Software Foundation. It is written in C and was designed to be a more robust centralized solution than CVS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;

&lt;p&gt;Like CVS, Subversion uses a centralized repository model. Remote users must have a working network connection to commit their changes to the central repository. &lt;/p&gt;

&lt;p&gt;Subversion introduced the functionality of atomic commits which ensured that a commit would either fully succeed, or be completely abandoned if an issue occurred. In CVS, if a commit operation failed midway, for example due to a network outage, the repository could be left in a corrupted and inconsistent state. Furthermore, a commit or revision in Subversion can include multiple files and directories. This is important since it allows users to track sets of related changes together as a grouped unit, instead of the past storage models that track changes separately for each file.&lt;/p&gt;

&lt;p&gt;The current storage model that Subversion uses for tracked files is called &lt;code&gt;FSFS&lt;/code&gt; or &lt;code&gt;File System atop the File System&lt;/code&gt;. This name was chosen since it creates its database structure using a file and directory structure that match the operating system filesystem it is running on. The unique feature of the Subversion filesystem is that it is designed to track not only the files and the directories it contains, but the different versions of these files and directories and they change over time. It is a filesystem with an added time dimension. In addition, folders are first class citizens in Subversion. Empty folders can be committed in Subversion, whereas in the rest (even Git) empty folders are unnoticed.&lt;/p&gt;

&lt;p&gt;When a Subversion repository is created, a (nearly) empty database of files and folders is created as a part of it. A directory called &lt;code&gt;db/revs&lt;/code&gt; is created in which all revision tracking information for the checked-in (committed) files is stored. Each commit (which can include changes to multiple files) is stored in a new file in the &lt;code&gt;revs&lt;/code&gt; directory and is named with a sequential numeric identifier starting with 1. When a file is committed for the first time, its full content is stored. Future commits of the same file will store only the changes - also called the &lt;code&gt;diffs&lt;/code&gt; or deltas - in order to conserve space. In addition, the deltas are compressed using &lt;code&gt;lz4&lt;/code&gt; or &lt;code&gt;zlib&lt;/code&gt; compression algorithms to further reduce their size.&lt;/p&gt;

&lt;p&gt;By default, this is actually only true to a point. Although storing file deltas instead of the whole file each time does save on storage space, it adds time to checkout and commit operations since all the deltas need to be strung together in order to recreate the current state of the file. For this reason, by default Subversion stores up to 1023 deltas per file before storing a new full copy of the file. This achieves a nice balance of both storage and speed.&lt;/p&gt;

&lt;p&gt;SVN does not use a conventional branching and tagging system. A normal Subversion repository layout is to have three folders in the root:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;trunk/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;branches/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tags/&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;trunk/&lt;/code&gt; folder is used for the production version of the application. The &lt;code&gt;branches/&lt;/code&gt; folder is used to store subfolders that correspond to individual branches. The &lt;code&gt;tags/&lt;/code&gt; folder is used to store tags which represent specific (usually significant) project revisions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Commands
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;svn create &amp;lt;path-to-repository&amp;gt;&lt;/code&gt;: Create a new, empty repository shell in the specified directory.&lt;br&gt;&lt;br&gt;
&lt;code&gt;svn import &amp;lt;path-to-project&amp;gt; &amp;lt;svn-url&amp;gt;&lt;/code&gt;: Import a directory of files into the specified Subversion repository path. &lt;br&gt;&lt;br&gt;
&lt;code&gt;svn checkout &amp;lt;svn-path&amp;gt; &amp;lt;path-to-checkout&amp;gt;&lt;/code&gt;: Copy a stored repository path to the desired working directory.&lt;br&gt;&lt;br&gt;
&lt;code&gt;svn commit -m 'Commit message'&lt;/code&gt;: Commit a set of changed files and folders along with a descriptive commit message.&lt;br&gt;&lt;br&gt;
&lt;code&gt;svn add &amp;lt;filename.txt&amp;gt;&lt;/code&gt;: Add a new file to track revisions for.&lt;br&gt;&lt;br&gt;
&lt;code&gt;svn update&lt;/code&gt;: Update the working copy by merging in committed changes that exist in the central repository but not the working copy.&lt;br&gt;&lt;br&gt;
&lt;code&gt;svn status&lt;/code&gt;: Show a list of tracked files that have been changed in the working directory (if any).&lt;br&gt;&lt;br&gt;
&lt;code&gt;svn info&lt;/code&gt;: Show a list of general details about the checked-out copy.&lt;br&gt;&lt;br&gt;
&lt;code&gt;svn copy &amp;lt;branch-to-copy&amp;gt; &amp;lt;new-branch-path-and-name&amp;gt;&lt;/code&gt;: Create a new branch by copying an existing one.&lt;br&gt;&lt;br&gt;
&lt;code&gt;svn switch &amp;lt;existing-branch&amp;gt;&lt;/code&gt;: Switch the working directory to an existing branch. This will checkout the specified branch.&lt;br&gt;&lt;br&gt;
&lt;code&gt;svn merge &amp;lt;existing-branch&amp;gt;&lt;/code&gt;: Merge the specified branch into the current branch checked out in the working directory. Note this needs to be committed afterwards.&lt;br&gt;&lt;br&gt;
&lt;code&gt;svn log&lt;/code&gt;: Show the commit history and associated descriptive messages for the active branch.&lt;/p&gt;

&lt;p&gt;For more information on SVN internals, see the &lt;a href="http://svnbook.red-bean.com/"&gt;Version Control with Subversion book&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sample SVN Revision File
&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;pre class="highlight"&amp;gt;&amp;lt;code&amp;gt;DELTA                                                                                                                                                                              
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;SVN^B^@^@   ^B&lt;br&gt;&lt;br&gt;
^A&amp;lt;89&amp;gt;  hi there&lt;br&gt;
ENDREP&lt;br&gt;
id: 2-1.0.r1/4&lt;br&gt;
type: file&lt;br&gt;
count: 0&lt;br&gt;
text: 1 3 21 9 12f6bb1941df66b8f138a446d4e8670c 279d9035886d4c0427549863c4c2101e4a63e041 0-0/_4&lt;br&gt;
cpath: /trunk/hi.txt&lt;br&gt;
copyroot: 0 / &lt;br&gt;&lt;br&gt;
DELTA&lt;br&gt;
SVN^B^@^@$^B%^A¤$K 6&lt;br&gt;
hi.txt&lt;br&gt;
V 15&lt;br&gt;
file 2-1.0.r1/4&lt;br&gt;
END&lt;br&gt;
ENDREP&lt;br&gt;
id: 0-1.0.r1/6&lt;br&gt;
type: dir &lt;br&gt;
count: 0&lt;br&gt;
text: 1 5 48 36 d84cb1c29105ee7739f3e834178e6345 - - &lt;br&gt;
cpath: /trunk&lt;br&gt;
copyroot: 0 / &lt;br&gt;&lt;br&gt;
DELTA&lt;br&gt;
SVN^B^@^@'^B#^A¢'K 5&lt;br&gt;
trunk&lt;br&gt;
V 14&lt;br&gt;
dir 0-1.0.r1/6&lt;br&gt;
END&lt;br&gt;
ENDREP&lt;br&gt;
id: 0.0.r1/2&lt;br&gt;
type: dir &lt;br&gt;
pred: 0.0.r0/2&lt;br&gt;
count: 1&lt;br&gt;
text: 1 7 46 34 1d30e888ec9e633100992b752c2ff4c2 - - &lt;br&gt;
cpath: /&lt;br&gt;
copyroot: 0 / &lt;br&gt;&lt;br&gt;
_0.0.t0-0 add-dir false false false /trunk&lt;br&gt;&lt;br&gt;
_2.0.t0-0 add-file true false false /trunk/hi.txt&lt;br&gt;&lt;br&gt;&lt;br&gt;
L2P-INDEX&lt;br&gt;
^A&amp;lt;80&amp;gt;@^A^A^A^M^H^@ä^H÷^Aé^FDÎ^Bzè^AP2L-INDEX&lt;br&gt;
^A&amp;lt;91&amp;gt;^E&amp;lt;80&amp;gt;&amp;lt;80&amp;gt;@^A?^@'2^@&amp;lt;8d&amp;gt;»Ý&amp;lt;90&amp;gt;^C§^A^X^@õ ½½^N=&lt;br&gt;
^@ü&amp;lt;8d&amp;gt;Ôã^Ft^V^@&amp;lt;92&amp;gt;&amp;lt;9a&amp;gt;&amp;lt;89&amp;gt;Ã^E;&lt;br&gt;
^@&amp;lt;8a&amp;gt;®åw|I^@&amp;lt;88&amp;gt;&amp;lt;83&amp;gt;Î&amp;lt;93&amp;gt;^L`^M^@ù­&amp;lt;92&amp;gt;À^Eïú?^[^@^@657 6aad60ec758d121d5181ea4b81a9f5f4 688 75f59082c8b5ab687ae87708432ca406I&lt;/p&gt;

&lt;h2&gt;
  
  
  Git - Third Generation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Background
&lt;/h3&gt;

&lt;p&gt;Git was created in 2005 by Linus Torvalds (also the creator of Linux) and is written primarily in C combined with some shell scripts. It is a great VCS due to its features, flexibility, and speed. Linus Torvalds originally wrote it for the Linux codebase and it has grown to become the most popular VCS in use today.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;

&lt;p&gt;Git is a distributed VCS. This means that no copy of the repository needs to be designated as the centralized copy - all copies are created equal. This is in stark contrast to the second generation VCS which rely on a centralized copy for users to checkin and checkout from. What this means is that developers can share changes with each other directly before merging their changes into an official branch.&lt;/p&gt;

&lt;p&gt;Furthermore, developers can commit their changes to their local copy of the repository without any other repositories knowing about it. This means that commits can be made without any network or Internet connection. Developers can work locally offline until they are ready to share their work with others. At that point, the changes can be pushed to other repositories for review, testing, or deployment.&lt;/p&gt;

&lt;p&gt;When a file is added for tracking with Git, it is compressed using the &lt;code&gt;zlib&lt;/code&gt; compression algorithm. The result is hashed using a SHA-1 hash function. This yields a unique hash value that corresponds specifically to the content in that file. Git stores this in an &lt;code&gt;object database&lt;/code&gt; which is located in the hidden &lt;code&gt;.git/objects&lt;/code&gt; folder. The name of the file is the generated hash value, and the file contains the compressed content. These files are called &lt;code&gt;blobs&lt;/code&gt; and are created each time a new file (or changed version of an existing file) are added to the repository.&lt;/p&gt;

&lt;p&gt;Git implements a &lt;code&gt;staging index&lt;/code&gt; which acts as an intermediate area for changes that are getting ready to be committed. As new changes are staged for commit, their compressed contents are referenced in a special index file - which takes the form of a &lt;code&gt;tree&lt;/code&gt; object. A &lt;code&gt;tree&lt;/code&gt; is a Git object that connects blob objects to their real file names, file permissions and links to other trees, and in this way represents the state of a particular set of files and directories. Once all related changes are staged for commit, the index tree can be committed to the repository, which creates a &lt;code&gt;commit&lt;/code&gt; object in the Git object database. A commit references the head tree for a particular revision as well as the commit author, email address, date, and a descriptive commit message. Each commit also stores a reference to its parent commit(s) and so over time a history of project development is established.&lt;/p&gt;

&lt;p&gt;As mentioned, all Git objects - blobs, trees, and commits - are compressed, hashed, and stored in the object database based on their hash value. These are called &lt;code&gt;loose objects&lt;/code&gt;. At this point no diffs have been utilized to save space which makes Git very fast since the full content of each file revision is accessible as a loose object. However, certain operations such as pushing commits to a remote repository, storing too many objects, or manually running Git's garbage collection command can cause Git to repackage the objects into &lt;code&gt;pack files&lt;/code&gt;. In the packing process, reverse diffs are taken and compressed to eliminate redundant content and reduce size. This process results in &lt;code&gt;.pack&lt;/code&gt; files containing the object content, each with a corresponding &lt;code&gt;.idx&lt;/code&gt; (or index) file containing a reference of the packed objects and their locations in the pack file.&lt;/p&gt;

&lt;p&gt;These pack files are transferred over the network when branches are pushed to or pulled from remote repositories. When pulling or fetching branches, the pack files are unpacked to create the loose objects in the object repository.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Commands
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;git init&lt;/code&gt;: Initialize the current directory as a Git repository (creates the hidden &lt;code&gt;.git&lt;/code&gt; folder and its contents).&lt;br&gt;&lt;br&gt;
&lt;code&gt;git clone &amp;lt;git-url&amp;gt;&lt;/code&gt;: Download a copy of the Git repository at the specified URL.&lt;br&gt;&lt;br&gt;
&lt;code&gt;git add &amp;lt;filename.ext&amp;gt;&lt;/code&gt;: Add an untracked file or changed file to the staging area (creates corresponding entries in the object database).&lt;br&gt;&lt;br&gt;
&lt;code&gt;git commit -m 'Commit message'&lt;/code&gt;: Commit a set of changed files and folders along with a descriptive commit message.&lt;br&gt;&lt;br&gt;
&lt;code&gt;git status&lt;/code&gt;: Show information related to the state of the working directory, current branch, untracked files, modified files, etc.&lt;br&gt;&lt;br&gt;
&lt;code&gt;git branch &amp;lt;new-branch&amp;gt;&lt;/code&gt;: Create a new branch based on the current checked-out branch.&lt;br&gt;&lt;br&gt;
&lt;code&gt;git checkout &amp;lt;branch&amp;gt;&lt;/code&gt;: Checkout the specified branch into the working directory.&lt;br&gt;&lt;br&gt;
&lt;code&gt;git merge &amp;lt;branch&amp;gt;&lt;/code&gt;: Merge the specified branch into the current branch checked out in the working directory.&lt;br&gt;&lt;br&gt;
&lt;code&gt;git pull&lt;/code&gt;: Update the working copy by merging in committed changes that exist in the remote repository but not the working copy.&lt;br&gt;&lt;br&gt;
&lt;code&gt;git push&lt;/code&gt;: Pack loose objects for local active branch commits into pack files and transfer to remote repository.&lt;br&gt;&lt;br&gt;
&lt;code&gt;git log&lt;/code&gt;: Show the commit history and associated descriptive messages for the active branch.&lt;br&gt;&lt;br&gt;
&lt;code&gt;git stash&lt;/code&gt;: Save all uncommitted changes in the working directory to a cache so that they can be retrieved later.&lt;/p&gt;

&lt;p&gt;For more information on Git internals, see the &lt;a href="https://book.git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain"&gt;Pro Git book chapter on Git's internals&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Sample Git Blob, Tree, Commit Files
&lt;/h3&gt;

&lt;p&gt;A blob file with hash value &lt;code&gt;37d4e6c5c48ba0d245164c4e10d5f41140cab980&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;hi there&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;A tree object with hash value &lt;code&gt;b769f35b07fbe0076dcfc36fd80c121d747ccc04&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;100644 blob 37d4e6c5c48ba0d245164c4e10d5f41140cab980   hi.txt&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;A commit object with hash value &lt;code&gt;dc512627287a61f6111705151f4e53f204fbda9b&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;pre class="highlight"&amp;gt;&amp;lt;code&amp;gt;tree b769f35b07fbe0076dcfc36fd80c121d747ccc04
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;author Jacob Stopak  1574915303 -0800&lt;br&gt;
committer Jacob Stopak  1574915303 -0800&lt;br&gt;&lt;br&gt;
Initial commit&lt;/p&gt;

&lt;h2&gt;
  
  
  Mercurial - Third Generation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Background
&lt;/h3&gt;

&lt;p&gt;Mercurial was created in 2005 by Matt Mackall and it is written in Python. It was also started with the goal of hosting the codebase for Linux, but Git was chosen instead. It is the second most popular distributed VCS after Git, but is used far less often.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;

&lt;p&gt;Like Git, Mercurial is a distributed version control system that allows any number of developers to work with their own copy of a project independently from others. Mercurial leverages many of the same technologies as Git, such as compression and SHA-1 hashing, but does so in different ways.&lt;/p&gt;

&lt;p&gt;When a new file is committed for tracking in Mercurial, a corresponding &lt;code&gt;revlog&lt;/code&gt; file is created for it in the hidden directory &lt;code&gt;.hg/store/data/&lt;/code&gt;. You can think of a &lt;code&gt;revlog&lt;/code&gt; (or revision log) file as a modernized version of the &lt;code&gt;history files&lt;/code&gt; used by the older VCS like CVS, RCS, and SCCS. Unlike Git, which creates a new &lt;code&gt;blob&lt;/code&gt; for every version of every staged file, Mercurial simply creates a new entry in the revlog for that file. To conserve space, each new entry only contains the delta (changes) from the previous version. Once a threshold number of deltas is reached, a full snapshot of the file is stored again. This reduces the lookup time when applying many deltas to reconstruct a particular file revision.&lt;/p&gt;

&lt;p&gt;These file revlogs are named to match the files that they track, but are postfixed with &lt;code&gt;.i&lt;/code&gt; and &lt;code&gt;.d&lt;/code&gt; extensions. The &lt;code&gt;.d&lt;/code&gt; files contained the compressed delta content. The &lt;code&gt;.i&lt;/code&gt; files are used as indexes to quickly track down different revisions inside the &lt;code&gt;.d&lt;/code&gt; files. For small files with low numbers of revisions, both the indexes and content are stored in &lt;code&gt;.i&lt;/code&gt; files. Revlog file entries are compressed for performance and hashed for identification. The hash values are referred to as &lt;code&gt;nodeids&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Whenever a new commit is made, Mercurial tracks the all file revisions in that commit in something called the &lt;code&gt;manifest&lt;/code&gt;. The manifest is also a revlog file - it stores entries that correspond to particular states of the repository. However, instead of storing individual file content like the file revlogs, the manifest stores a list of filenames and nodeids that specify which file revision entries exist in each revision of the project. These manifest entries are also compressed and hashed. The hash values are again referred to as &lt;code&gt;nodeids&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Lastly, Mercurial uses one more type of revlog called a &lt;code&gt;changelog&lt;/code&gt;. The changelog contains a list of entries that associate each commit with the following information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Manifest nodeid: Identifies the full set of file revisions that exist at a particular time.&lt;/li&gt;
&lt;li&gt;Parent commit nodeid(s): This allows Mercurial to establish a timeline or branch of project history. One or two parent ID's are stored depending on the type of commit (normal vs merge).&lt;/li&gt;
&lt;li&gt;Commit author&lt;/li&gt;
&lt;li&gt;Commit date&lt;/li&gt;
&lt;li&gt;Commit message&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each changelog entry also generates a hash known as its &lt;code&gt;nodeid&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Commands
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;hg init&lt;/code&gt;: Initialize the current directory as a Mercurial repository (creates the hidden &lt;code&gt;.hg&lt;/code&gt; folder and its contents).&lt;br&gt;&lt;br&gt;
&lt;code&gt;hg clone &amp;lt;hg-url&amp;gt;&lt;/code&gt;: Download a copy of the Mercurial repository at the specified URL.&lt;br&gt;&lt;br&gt;
&lt;code&gt;hg add &amp;lt;filename.ext&amp;gt;&lt;/code&gt;: Add a new file for revision tracking.&lt;br&gt;&lt;br&gt;
&lt;code&gt;hg commit -m 'Commit message'&lt;/code&gt;: Commit a set of changed files and folders along with a descriptive commit message.&lt;br&gt;&lt;br&gt;
&lt;code&gt;hg status&lt;/code&gt;: Show information related to the state of the working directory, untracked files, modified files, etc.&lt;br&gt;&lt;br&gt;
&lt;code&gt;hg update &amp;lt;revision&amp;gt;&lt;/code&gt;: Checkout the specified branch into the working directory.&lt;br&gt;&lt;br&gt;
&lt;code&gt;hg merge &amp;lt;branch&amp;gt;&lt;/code&gt;: Merge the specified branch into the current branch checked out in the working directory.&lt;br&gt;&lt;br&gt;
&lt;code&gt;hg pull&lt;/code&gt;: Download new revisions from remote repository but don't merge them into the working directory.&lt;br&gt;&lt;br&gt;
&lt;code&gt;hg push&lt;/code&gt;: Transfer new revisions to remote repository.&lt;br&gt;&lt;br&gt;
&lt;code&gt;hg log&lt;/code&gt;: Show the commit history and associated descriptive messages for the active branch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sample Mercurial Files
&lt;/h3&gt;

&lt;p&gt;Manifest revlog entry:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;pre class="highlight"&amp;gt;&amp;lt;code&amp;gt;hey.txt208b6e0998e8099b16ad0e43f036ec745d58ec04
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;hi.txt74568dc1a5b9047c8041edd99dd6f566e78d3a42&lt;/p&gt;

&lt;p&gt;Changelog revlog entry:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;pre class="highlight"&amp;gt;&amp;lt;code&amp;gt;b8ee947ce6f25b84c22fbefecab99ea918fc0969
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Jacob Stopak &lt;br&gt;
1575082451 28800&lt;br&gt;
hey.txt&lt;br&gt;&lt;br&gt;
Add hey.txt&lt;/p&gt;

&lt;p&gt;For more information on Mercurial internals, check out the following links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://hgbook.red-bean.com/read/behind-the-scenes.html"&gt;Bryan O'Sullivan's Hg Book&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mercurial-scm.org/wiki/Revlog"&gt;Mercurial Wiki (Revlog)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mercurial-scm.org/wiki/ChangeSet"&gt;Mercurial Wiki (ChangeSet)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mercurial-scm.org/wiki/Manifest"&gt;Mercurial Wiki (Manifest)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mercurial-scm.org/wiki/Revision"&gt;Mercurial Wiki (Revision)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mercurial-scm.org/wiki/Nodeid"&gt;Mercurial Wiki (Nodeid)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, we provided a technical comparison of some historically relevant version control systems. If you have any questions or comments, feel free to reach out to &lt;a href="mailto:jacob@initialcommit.io"&gt;jacob@initialcommit.io&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A special thanks to Reddit user &lt;a href="https://teknikaldomain.me/"&gt;u/Teknikal_Domain&lt;/a&gt;, who provided expert details and insight that greatly contributed to the writing of this article.&lt;/p&gt;

&lt;p&gt;You can find our original post &lt;a href="https://initialcommit.com/blog/Technical-Guide-VCS-Internals"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>vcs</category>
      <category>versioncontrol</category>
      <category>git</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Overview of Git's Original Makefile</title>
      <dc:creator>Initial Commit</dc:creator>
      <pubDate>Sat, 23 Nov 2019 08:47:06 +0000</pubDate>
      <link>https://dev.to/initialcommit/overview-of-git-s-original-makefile-1p09</link>
      <guid>https://dev.to/initialcommit/overview-of-git-s-original-makefile-1p09</guid>
      <description>&lt;h2&gt;
  
  
  Turning Source Code into a Program
&lt;/h2&gt;

&lt;p&gt;Before getting straight into Makefiles, lets briefly cover how source code gets turned into an actual program that can run on a computer. Source code consists of a set of files and folders that contain code. This source code usually needs to be converted into a form that the computer can understand. This process is called &lt;strong&gt;&lt;em&gt;compilation&lt;/em&gt;&lt;/strong&gt; or &lt;strong&gt;&lt;em&gt;compiling&lt;/em&gt;&lt;/strong&gt;. A program that performs this conversion is called a &lt;strong&gt;&lt;em&gt;compiler&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Sometimes the compiler needs to be given certain pieces of information so it can properly do its job. This information may include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The names and locations of the source code (input) files to compile&lt;/li&gt;
&lt;li&gt;The set of compiled (output) programs to create&lt;/li&gt;
&lt;li&gt;The names and locations to put the compiled (output) programs&lt;/li&gt;
&lt;li&gt;Whether or not to apply any special options in the compilation process&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The process of choosing a compiler, identifying the set of source code files to be included, performing preperation steps, and compiling the code into its final form is called &lt;strong&gt;&lt;em&gt;building&lt;/em&gt;&lt;/strong&gt;, or the &lt;strong&gt;&lt;em&gt;build process&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is &lt;strong&gt;&lt;em&gt;Make&lt;/em&gt;&lt;/strong&gt;?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Make&lt;/em&gt;&lt;/strong&gt; is a &lt;strong&gt;&lt;em&gt;build automation tool&lt;/em&gt;&lt;/strong&gt;. It would be very tedious for a developer to manually run all of the build steps in sequence each time they want to build their program. Build automation tools like Make allow developers to describe the build steps and execute them all at once.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a &lt;strong&gt;&lt;em&gt;Makefile&lt;/em&gt;&lt;/strong&gt;?
&lt;/h2&gt;

&lt;p&gt;Makefiles are text files that developers use to describe the build process for their programs. The &lt;code&gt;make&lt;/code&gt; command can then be used to conveniently run the instructions in the Makefile.&lt;/p&gt;

&lt;h2&gt;
  
  
  Baby Git Makefile
&lt;/h2&gt;

&lt;p&gt;Below is the original Makefile for Git. It is used to invoke the gcc C compiler to build binary executable&lt;br&gt;
files for each of the original 7 git commands:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;init-db&lt;/li&gt;
&lt;li&gt;update-cache&lt;/li&gt;
&lt;li&gt;cat-file&lt;/li&gt;
&lt;li&gt;show-diff&lt;/li&gt;
&lt;li&gt;write-tree&lt;/li&gt;
&lt;li&gt;read-tree&lt;/li&gt;
&lt;li&gt;commit-tree&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This Makefile can be invoked in 3 variations (referred to as 3 &lt;strong&gt;&lt;em&gt;targets&lt;/em&gt;&lt;/strong&gt;), by running the 3 following commands from the command line inside the same directory as the Makefile:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;make clean&lt;/em&gt;&lt;/strong&gt;: This removes all previously built executables and build files from the working directory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;make backup&lt;/em&gt;&lt;/strong&gt;: This first runs &lt;code&gt;make clean&lt;/code&gt; and then backs up the current directory into a tar archive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;make&lt;/em&gt;&lt;/strong&gt;: This builds the codebase and creates the 7 git executables.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Enough talk - here is the code from Git's first Makefile:&lt;/p&gt;

&lt;pre class="highlight"&gt;
&lt;code&gt;CFLAGS=-g # The `-g` compiler flag tells gcc to add debug symbols to the executable for use with a debugger.
CC=gcc # Use the `gcc` C compiler.&lt;br&gt;
# Specify the names of all executables to make.
PROG=update-cache show-diff init-db write-tree read-tree commit-tree cat-file
all: $(PROG)&lt;br&gt;
install: $(PROG)
    install $(PROG) $(HOME)/bin/&lt;br&gt;
# Include the following dependencies in the build.
LIBS= -lssl&lt;br&gt;
# Specify which compiled output (.o files) to use for each executable.
init-db: init-db.o&lt;br&gt;
update-cache: update-cache.o read-cache.o
    $(CC) $(CFLAGS) -o update-cache update-cache.o read-cache.o $(LIBS)&lt;br&gt;
show-diff: show-diff.o read-cache.o
    $(CC) $(CFLAGS) -o show-diff show-diff.o read-cache.o $(LIBS)&lt;br&gt;
write-tree: write-tree.o read-cache.o
    $(CC) $(CFLAGS) -o write-tree write-tree.o read-cache.o $(LIBS)&lt;br&gt;
read-tree: read-tree.o read-cache.o
    $(CC) $(CFLAGS) -o read-tree read-tree.o read-cache.o $(LIBS)&lt;br&gt;
commit-tree: commit-tree.o read-cache.o
    $(CC) $(CFLAGS) -o commit-tree commit-tree.o read-cache.o $(LIBS)&lt;br&gt;
cat-file: cat-file.o read-cache.o
    $(CC) $(CFLAGS) -o cat-file cat-file.o read-cache.o $(LIBS)&lt;br&gt;
# Specify which C header files to include in compilation/linking.
read-cache.o: cache.h
show-diff.o: cache.h&lt;br&gt;
# Define the steps to run during the `make clean` command.
clean:
    rm -f *.o $(PROG) temp_git_file_* # Remove these files from the current directory.&lt;br&gt;
# Define the steps to run during the `make backup` command.
backup: clean
    cd .. ; tar czvf babygit.tar.gz baby-git # Backup the current directory into a tar archive.&lt;/code&gt;
&lt;/pre&gt;

&lt;h2&gt;
  
  
  Build Variables
&lt;/h2&gt;

&lt;p&gt;Build variables are variables than can be defined in the Makefile to hold specific values. In the Makefile above, words such as &lt;code&gt;CFLAGS&lt;/code&gt; and &lt;code&gt;CC&lt;/code&gt; are not special in any way. They are just variable names used to store the values that come after the equals sign. Variable names like &lt;code&gt;$(CFLAGS)&lt;/code&gt; can be used later in the Makefile to substitute in the variable values where needed. This is convenient since we can use a variable name in multiple places, while only updating it in one place if the value changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Specifying the Compiler
&lt;/h3&gt;

&lt;p&gt;Git is written in C, so this Makefile is tailored to a C build process.&lt;/p&gt;

&lt;p&gt;The first line &lt;code&gt;CFLAGS=-g&lt;/code&gt; specifies the compiler flags - special compiler options - to use during compilation. In this case, the &lt;code&gt;-g&lt;/code&gt; flag tells the compiler to output debug information to the console.&lt;/p&gt;

&lt;p&gt;The second line &lt;code&gt;CC=gcc&lt;/code&gt; identifies the actual compiler to use. &lt;a href="https://en.wikipedia.org/wiki/GNU_Compiler_Collection"&gt;GCC&lt;/a&gt; is the GNU Compiler Collection. It supports compilation of code in several programming languages including C, C++, Java, and more.&lt;/p&gt;

&lt;h3&gt;
  
  
  Specifying the Executables
&lt;/h3&gt;

&lt;p&gt;The third line defines a build variable called &lt;code&gt;PROG&lt;/code&gt; which contains the names of the executables we'll be creating.&lt;/p&gt;

&lt;h3&gt;
  
  
  Linking External Libraries
&lt;/h3&gt;

&lt;p&gt;We'll quickly skip ahead to the line which defines the &lt;code&gt;LIBS&lt;/code&gt; variable. This stores the external libraries that we want to link into the build process. In this case, we link in the SSL library which allows Git to access cryptographic functions like hashing.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;&lt;em&gt;Make&lt;/em&gt;&lt;/strong&gt; Targets and Commands
&lt;/h2&gt;

&lt;p&gt;Throughout the Makefile, there are multiple lines that start with a keyword followed by a colon such as &lt;code&gt;all:&lt;/code&gt;, &lt;code&gt;install:&lt;/code&gt;, &lt;code&gt;init-db:&lt;/code&gt;, etc. Each of these is called a &lt;strong&gt;&lt;em&gt;target&lt;/em&gt;&lt;/strong&gt;. Each target essentially maps to a command that you can specify when running Make, in the form &lt;code&gt;make target&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, if you open a terminal window and browse to this Makefile's directory, you could run the &lt;code&gt;make all&lt;/code&gt; command to run Make on the &lt;code&gt;all&lt;/code&gt; target. Similarly you could run &lt;code&gt;make install&lt;/code&gt; to run Make on the &lt;code&gt;install&lt;/code&gt; target. If no target is specified, the &lt;code&gt;all&lt;/code&gt; target will be used by default.&lt;/p&gt;

&lt;p&gt;When Make runs a target, it executes the instructions associated with that target in the Makefile.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;strong&gt;&lt;em&gt;All&lt;/em&gt;&lt;/strong&gt; Target
&lt;/h3&gt;

&lt;p&gt;Back to the Makefile, the &lt;code&gt;all: $(PROG)&lt;/code&gt; line states that, when Make is run without specifying a target, all targets listed in $(PROG) will be executed. Since &lt;code&gt;$(PROG)&lt;/code&gt; lists all 7 of the Baby Git executables, each of them will be executed.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;strong&gt;&lt;em&gt;Install&lt;/em&gt;&lt;/strong&gt; Target
&lt;/h3&gt;

&lt;p&gt;The next target in the Makefile is &lt;code&gt;install&lt;/code&gt;. It is run at the command line using &lt;code&gt;make install&lt;/code&gt;. This starts the same way as the &lt;code&gt;all&lt;/code&gt; target, by specifying the executables to compile using &lt;code&gt;$(PROG)&lt;/code&gt;. But then it uses the &lt;code&gt;install&lt;/code&gt; command to move those built executables into the users home directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Baby Git Program Targets
&lt;/h3&gt;

&lt;p&gt;Now for the targets corresponding to the executable names:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;init-db:&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;update-cache:&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;show-diff:&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;write-tree:&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;read-tree:&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;commit-tree:&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cat-file:&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each one of these targets specifies which compiled C object (.o) files we want in each of our executables. Below that each one specifies the compiler command to run based no the build variables specified earlier in the file.&lt;/p&gt;

&lt;p&gt;The first executable &lt;strong&gt;&lt;em&gt;init-db&lt;/em&gt;&lt;/strong&gt; is very simple since it only includes 1 source file: &lt;code&gt;init-db: init-db.o&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The other executables (we'll take update-cache as an example) link together multiple C object (.o) files:&lt;/p&gt;

&lt;pre class="highlight"&gt;
&lt;code&gt;update-cache: update-cache.o read-cache.o
     $(CC) $(CFLAGS) -o update-cache update-cache.o read-cache.o $(LIBS)&lt;/code&gt;
&lt;/pre&gt;

&lt;p&gt;The second line above gets converted to the following after variable substitution:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;gcc -g -o update-cache update-cache.o read-cache.o -lssl&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Linking Header Files
&lt;/h2&gt;

&lt;p&gt;After the program targets, there are two lines that specify the C header (.h) files to link to each object (.o) file. The only header file in the Baby Git codebase is &lt;code&gt;cache.h&lt;/code&gt; which gets linked to &lt;code&gt;read-cache.o&lt;/code&gt; and &lt;code&gt;show-diff.o&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;strong&gt;&lt;em&gt;clean&lt;/em&gt;&lt;/strong&gt; Target
&lt;/h2&gt;

&lt;p&gt;This target is invoked using &lt;code&gt;make clean&lt;/code&gt; and simply deletes all compiled code and executables from the working directory. It leaves the source files alone so that the program can be built again.&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;strong&gt;&lt;em&gt;backup&lt;/em&gt;&lt;/strong&gt; Target
&lt;/h2&gt;

&lt;p&gt;This target is invoked using &lt;code&gt;make backup&lt;/code&gt;. First it invokes the &lt;code&gt;clean&lt;/code&gt; target. Then it backs up the source code files in the working directory as a tar archive in the parent directory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article we described how Git's first Makefile works line by line. We hope it helped you understand how Makefiles work and how they are implemented in practice.&lt;/p&gt;

&lt;p&gt;Note: The original posting for this article can be found on the &lt;a href="https://initialcommit.com/blog/Learn-Git-Makefile"&gt;Initial Commit Blog&lt;/a&gt;&lt;/p&gt;

</description>
      <category>git</category>
      <category>c</category>
      <category>initialcommit</category>
      <category>babygit</category>
    </item>
  </channel>
</rss>
