<!DOCTYPE html>
<html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="author" content="Matt Makai">
    <meta name="description" content="Full Stack Python explains each layer of the web application stack, from the server up through the rendering in a user's browser.">
    <link rel="shortcut icon" href="theme/img/fsp-fav.png">
    <title>Source Control - Full Stack Python</title>
    <link href="theme/css/fsp.css" rel="stylesheet">
    <!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
    <![endif]-->
    <link href="//netdna.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.css" rel="stylesheet">
    <script type="text/javascript">
  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-19910497-7']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>  </head>

<body>
    <a href="https://github.com/makaimc/fullstackpython.github.com" class="github">
        <img style="position: absolute; top: 0; right: 0; border: 0;" src="http://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on GitHub" />
    </a>
    <div class="container">
        <div class="row">
    <div class="col-md-12">
        <div class="logo-header-section">
            <a href="/" style="text-decoration: none; border: none;"><img src="theme/img/fsp-logo.png" height="52" width="52" class="logo-image" style="padding-top: 1px;"/></a>
            <span class="logo-title"><a href="/">Full Stack Python</a></span>
        </div>
    </div>
</div>        <div class="row">
    <div class="col-md-8">
      <h1>Source control</h1>
<p>Source control, also known as <em>version control</em>, stores software code files
with a detailed history of every modification made to those files.</p>
<h2>Why is source control necessary?</h2>
<p>Version control systems allow developers to modify code without worrying 
about permanently screwing something up. Unwanted changes can be easily rolled
back to previous working versions of the code. </p>
<p>Source control also makes team software development easier. One developer 
can combine her code modifications with other developers' code through 
<a href="http://en.wikipedia.org/wiki/Diff">diff</a> views that show line-by-line 
changes then merge the appropriate code into the main code branch.</p>
<p>Version control is a necessity on all software projects regardless of 
development time, codebase size or the programming language used. Every
project should immediately begin by using a version control system such
as Git or Mercurial.</p>
<h2>Source control during deployment</h2>
<p>Pulling code during a deployment is a potential way source control systems fit
into the deployment process. </p>
<p><img src="theme/img/app-source-control.png" width="100%" class="technical-diagram" alt="App deployment uses a server to pull from the source control system."></p>
<p>Note that some developers recommend deployment pipelines package the source 
code to deploy it and never have a production environment touch a source 
control system directly. However, for small scale deployments it's often
easiest to pull from source code when you're getting started instead of 
figuring out how to wrap the Python code in a system installation package.</p>
<h2>Source control projects</h2>
<p>Numerous source control systems have been created over the past several
decades. In the past, proprietary source control software offered features
tailored to large development teams and specific project workflows. However,
open source systems are now used for version control on the largest and most
complicated software projects in existence. There's no reason why your project
should use anything other than an open source version control system in
today's Python development world. The two primary choices are:</p>
<ul>
<li>
<p><a href="http://git-scm.com/">Git</a> is a free and open source distributed version
  control system.</p>
</li>
<li>
<p><a href="http://mercurial.selenic.com/">Mercurial</a> is similar to Git, also a free
  and open source distributed version control system.</p>
</li>
</ul>
<h2>Hosted source control services</h2>
<p>Git and Mercurial can be downloaded and run on your own server. However,
it's easy and cheap to get started with a hosted version control service.
You can transition away from the service at a later time by moving your 
repositories if your needs change. A couple of recommended hosted version
control services are:</p>
<ul>
<li>
<p><a href="https://github.com/">GitHub</a> is currently the most commonly used source
  control platform for using Git.</p>
</li>
<li>
<p><a href="https://bitbucket.org/">BitBucket</a> provides free Git and Mercurial 
  repositories for open projects and private repositories for up to five
  users. Users pay for hosting private repositories with more than five users.</p>
</li>
</ul>
<h2>General source control resources</h2>
<ul>
<li>
<p><a href="http://www.kalzumeus.com/2010/12/12/staging-servers-source-control-deploy-workflows-and-other-stuff-nobody-teaches-you/">Staging Servers, Source Control &amp; Deploy Workflows, And Other Stuff Nobody Teaches You</a> 
  is a comprehensive overview by Patrick McKenzie of why you need source 
  control.</p>
</li>
<li>
<p><a href="https://blog.rainforestqa.com/2014-05-28-version-control-best-practices/">Version control best practices</a>
  is a good write up of how to work with version control systems. The post is 
  part of an ongoing deployment guide written by the folks at 
  <a href="https://www.rainforestqa.com/">Rainforest</a>.</p>
</li>
<li>
<p>This lighthearted guide to the 
  <a href="http://www.flourish.org/blog/?p=397">ten astonishments in version control history</a> 
  is a fun way to learn how systems developed over the past several decades.</p>
</li>
<li>
<p><a href="http://betterexplained.com/articles/a-visual-guide-to-version-control/">A visual guide to version control</a> 
  is a detailed article with real-life examples for why version control is
  necessary in software development.</p>
</li>
<li>
<p><a href="http://guides.beanstalkapp.com/version-control/intro-to-version-control.html">An introduction to version control</a> 
  shows the basic concepts behind version control systems.</p>
</li>
<li>
<p><a href="http://oss-watch.ac.uk/resources/versioncontrol">What Is Version Control? Why Is It Important For Due Diligence?</a> 
  explains the benefits and necessity of version control systems.</p>
</li>
<li>
<p><a href="http://git-scm.com/book/en/Getting-Started-About-Version-Control">About version control</a> 
reviews the basics of distributed version control systems.</p>
</li>
</ul>
<h2>Git resources</h2>
<ul>
<li>
<p><a href="http://git-scm.com/book">Pro Git</a> is a free open source book that walks 
  through all aspects of using the version control system.</p>
</li>
<li>
<p><a href="http://wildlyinaccurate.com/a-hackers-guide-to-git">A Hacker's Guide to Git</a>
  covers the basics as well as more advanced Git commands while explaining each
  step along the way.</p>
</li>
<li>
<p><a href="http://mrchlblng.me/2014/09/practical-git-introduction/">A practical git introduction</a>
  is exactly what the title says it is. This is a well written guide with 
  plenty of code snippets to get you up to speed with Git.</p>
</li>
<li>
<p><a href="http://gitready.com/">git ready</a> has a nice collection of blog posts based on
  beginner, intermediate and advanced Git use cases.</p>
</li>
<li>
<p><a href="http://nvie.com/posts/a-successful-git-branching-model/">git-flow</a> details
  a Git branching model for small teams.</p>
</li>
<li>
<p><a href="http://scottchacon.com/2011/08/31/github-flow.html">GitHub Flow</a> builds on
  git-flow, goes over some of the issues that arise with it and presents a
  few solutions to those problems.</p>
</li>
<li>
<p><a href="http://blog.endpoint.com/2014/05/git-workflows-that-work.html">Git Workflows That Work</a>
  is a helpful post with diagrams to show how teams can create a Git workflow
  that will help their development process.</p>
</li>
<li>
<p>"<a href="http://www.braintreepaymentsolutions.com/devblog/our-git-workflow">Our Git Workflow</a>"
  by Braintree goes over how this payments company uses Git for development
  and merging source code.</p>
</li>
</ul>
<h2>Source control learning checklist</h2>
<p><i class="fa fa-check-square-o"></i>
Pick a version control system. Git is recommended because on the web there 
are a significant number of tutorials to help both new and advanced users.</p>
<p><i class="fa fa-check-square-o"></i>
Learn basic use cases for version control such as committing changes, rolling 
back to earlier file versions and searching for when lines of code were 
modified during development history.</p>
<p><i class="fa fa-check-square-o"></i>
Ensure your source code is backed up in a central repository. A central
repository is critical not only if your local development version is corrupted
but also for the deployment process.</p>
<p><i class="fa fa-check-square-o"></i>
Integrate source control into your deployment process in three ways. First,
pull the project source code from version control during deployments. Second, 
kick off deployments when code is modified by using webhooks or polling on 
the repository. Third, ensure you can roll back to a previous version if a 
code deployment goes wrong.</p>
<h3>Now that your source code is versioned, what's next?</h3>
                  <div class="row">
    <div class="col-md-4">
        <div class="well select-next">
            <a href="/deployment.html" class="btn btn-success btn-full"><i class="fa fa-share fa-2x"></i></a>
            <p class="under-btn">
                How do I deploy the code I've created for my web app?
            </p>
        </div>
    </div>
    <div class="col-md-4">
        <div class="well select-next">
            <a href="/web-analytics.html" class="btn btn-success btn-full"><i class="fa fa-dashboard fa-2x"></i></a>
            </a>
            <p class="under-btn">
                I want to learn more about the users of my application.
            </p>
        </div>
    </div>
    <div class="col-md-4">
        <div class="well select-next">
            <a href="/api-integration.html" class="btn btn-success btn-full"><i class="fa fa-link fa-2x"></i></a>
            <p class="under-btn">
                How do I integrate external APIs into my web application?
            </p>
        </div>
    </div>
    </div>            <style type="text/css">
    #mc_embed_signup{background:#fff; clear:left; font:12px "Helvetica Neue",Arial,sans-serif; }
    /* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
       We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
</style>
<hr/>
<div id="mc_embed_signup">
<form action="http://mattmakai.us2.list-manage.com/subscribe/post?u=b7e774f0c4f05dcebbfee183d&amp;id=b22335388d" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
    <h4>Interested in a complete Full Stack Python book with detailed tutorials and example code? Sign up here and you'll get an alert email if a book is created. No other emails will be sent other than sign up confirmation.</h4>
    <div class="row">
        <div class="col-md-9">
            <label for="mce-EMAIL">Email Address</label>
            <input type="email" value="" name="EMAIL" class="required email form-control" id="mce-EMAIL">
        </div>
        <div class="col-md-3">
        <input type="submit" value="Subscribe" name="subscribe" id="mc-embedded-subscribe" class="btn btn-success" style="margin-top: 20px;">
    </div>
    <div id="mce-responses" class="clear">
        <div class="response" id="mce-error-response" style="display:none"></div>
        <div class="response" id="mce-success-response" style="display:none"></div>
    </div>    <!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups-->
    <div style="position: absolute; left: -5000px;"><input type="text" name="b_b7e774f0c4f05dcebbfee183d_b22335388d" value=""></div>
</div>
</form>
</div>
<script type="text/javascript">
var fnames = new Array();var ftypes = new Array();fnames[0]='EMAIL';ftypes[0]='email';fnames[1]='FNAME';ftypes[1]='text';fnames[2]='LNAME';ftypes[2]='text';
try {
    var jqueryLoaded=jQuery;
    jqueryLoaded=true;
} catch(err) {
    var jqueryLoaded=false;
}
var head= document.getElementsByTagName('head')[0];
if (!jqueryLoaded) {
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = '//ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js';
    head.appendChild(script);
    if (script.readyState && script.onload!==null){
        script.onreadystatechange= function () {
              if (this.readyState == 'complete') mce_preload_check();
        }    
    }
}

var err_style = '';
try{
    err_style = mc_custom_error_style;
} catch(e){
    err_style = '#mc_embed_signup input.mce_inline_error{border-color:#6B0505;} #mc_embed_signup div.mce_inline_error{margin: 0 0 1em 0; padding: 5px 10px; background-color:#6B0505; font-weight: bold; z-index: 1; color:#fff;}';
}
var head= document.getElementsByTagName('head')[0];
var style= document.createElement('style');
style.type= 'text/css';
if (style.styleSheet) {
  style.styleSheet.cssText = err_style;
} else {
  style.appendChild(document.createTextNode(err_style));
}
head.appendChild(style);
setTimeout('mce_preload_check();', 250);

var mce_preload_checks = 0;
function mce_preload_check(){
    if (mce_preload_checks>40) return;
    mce_preload_checks++;
    try {
        var jqueryLoaded=jQuery;
    } catch(err) {
        setTimeout('mce_preload_check();', 250);
        return;
    }
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = 'http://downloads.mailchimp.com/js/jquery.form-n-validate.js';
    head.appendChild(script);
    try {
        var validatorLoaded=jQuery("#fake-form").validate({});
    } catch(err) {
        setTimeout('mce_preload_check();', 250);
        return;
    }
    mce_init_form();
}
function mce_init_form(){
    jQuery(document).ready( function($) {
      var options = { errorClass: 'mce_inline_error', errorElement: 'div', onkeyup: function(){}, onfocusout:function(){}, onblur:function(){}  };
      var mce_validator = $("#mc-embedded-subscribe-form").validate(options);
      $("#mc-embedded-subscribe-form").unbind('submit');//remove the validator so we can get into beforeSubmit on the ajaxform, which then calls the validator
      options = { url: 'http://mattmakai.us2.list-manage.com/subscribe/post-json?u=b7e774f0c4f05dcebbfee183d&id=b22335388d&c=?', type: 'GET', dataType: 'json', contentType: "application/json; charset=utf-8",
                    beforeSubmit: function(){
                        $('#mce_tmp_error_msg').remove();
                        $('.datefield','#mc_embed_signup').each(
                            function(){
                                var txt = 'filled';
                                var fields = new Array();
                                var i = 0;
                                $(':text', this).each(
                                    function(){
                                        fields[i] = this;
                                        i++;
                                    });
                                $(':hidden', this).each(
                                    function(){
                                        var bday = false;
                                        if (fields.length == 2){
                                            bday = true;
                                            fields[2] = {'value':1970};//trick birthdays into having years
                                        }
                                        if ( fields[0].value=='MM' && fields[1].value=='DD' && (fields[2].value=='YYYY' || (bday && fields[2].value==1970) ) ){
                                            this.value = '';
                                        } else if ( fields[0].value=='' && fields[1].value=='' && (fields[2].value=='' || (bday && fields[2].value==1970) ) ){
                                            this.value = '';
                                        } else {
                                            if (/\[day\]/.test(fields[0].name)){
                                                this.value = fields[1].value+'/'+fields[0].value+'/'+fields[2].value;                                           
                                            } else {
                                                this.value = fields[0].value+'/'+fields[1].value+'/'+fields[2].value;
                                            }
                                        }
                                    });
                            });
                        $('.phonefield-us','#mc_embed_signup').each(
                            function(){
                                var fields = new Array();
                                var i = 0;
                                $(':text', this).each(
                                    function(){
                                        fields[i] = this;
                                        i++;
                                    });
                                $(':hidden', this).each(
                                    function(){
                                        if ( fields[0].value.length != 3 || fields[1].value.length!=3 || fields[2].value.length!=4 ){
                                            this.value = '';
                                        } else {
                                            this.value = 'filled';
                                        }
                                    });
                            });
                        return mce_validator.form();
                    }, 
                    success: mce_success_cb
                };
      $('#mc-embedded-subscribe-form').ajaxForm(options);
      
      
    });
}
function mce_success_cb(resp){
    $('#mce-success-response').hide();
    $('#mce-error-response').hide();
    if (resp.result=="success"){
        $('#mce-'+resp.result+'-response').show();
        $('#mce-'+resp.result+'-response').html(resp.msg);
        $('#mc-embedded-subscribe-form').each(function(){
            this.reset();
        });
    } else {
        var index = -1;
        var msg;
        try {
            var parts = resp.msg.split(' - ',2);
            if (parts[1]==undefined){
                msg = resp.msg;
            } else {
                i = parseInt(parts[0]);
                if (i.toString() == parts[0]){
                    index = parts[0];
                    msg = parts[1];
                } else {
                    index = -1;
                    msg = resp.msg;
                }
            }
        } catch(e){
            index = -1;
            msg = resp.msg;
        }
        try{
            if (index== -1){
                $('#mce-'+resp.result+'-response').show();
                $('#mce-'+resp.result+'-response').html(msg);            
            } else {
                err_id = 'mce_tmp_error_msg';
                html = '<div id="'+err_id+'" style="'+err_style+'"> '+msg+'</div>';
                
                var input_id = '#mc_embed_signup';
                var f = $(input_id);
                if (ftypes[index]=='address'){
                    input_id = '#mce-'+fnames[index]+'-addr1';
                    f = $(input_id).parent().parent().get(0);
                } else if (ftypes[index]=='date'){
                    input_id = '#mce-'+fnames[index]+'-month';
                    f = $(input_id).parent().parent().get(0);
                } else {
                    input_id = '#mce-'+fnames[index];
                    f = $().parent(input_id).get(0);
                }
                if (f){
                    $(f).append(html);
                    $(input_id).focus();
                } else {
                    $('#mce-'+resp.result+'-response').show();
                    $('#mce-'+resp.result+'-response').html(msg);
                }
            }
        } catch(e){
            $('#mce-'+resp.result+'-response').show();
            $('#mce-'+resp.result+'-response').html(msg);
        }
    }
}

</script>
<!--End mc_embed_signup-->     </div>
    <div class="col-md-offset-1 col-md-3" id="sidebar">
  <div class="panel panel-success">
      <div class="panel-heading"><h3 class="panel-head">Source Control</h3></div>
      <div class="panel-body">
          <a href="/">Full Stack Python</a> is an open book that explains
          each Python web application stack layer and provides the
          best web resources for those topics.
          <hr/>
                    There's a work-in-progress 
          <a href="/full-stack-python-map.pdf">subjects map (.pdf)</a> 
          that visually lays out each chapter in addition to the table of
          contents found below.
                    <hr/>
          Need more detailed tutorials and walkthroughs than what is
          presented here? 
          <a href="/email.html">Sign up for an email alert when that content is created.</a>
          <hr/>
          <a href="http://twitter.com/mattmakai">Matt Makai</a> built
          this site with assistance from community pull requests. On GitHub 
          you can <a href="https://github.com/makaimc">follow Matt</a>
          to see the daily changes.
      </div>
  </div>
    <div class="panel panel-success">
      <div class="panel-heading">
        <h3 class="panel-head">Table of Contents</h3>
      </div>
      <div class="list-group">
                        <a href="/introduction.html" class="list-group-item smaller-item ">Introduction</a>
                        <a href="/web-frameworks.html" class="list-group-item smaller-item ">Web Frameworks</a>
                        <a href="/django.html" class="list-group-item smaller-item ">Django</a>
                        <a href="/flask.html" class="list-group-item smaller-item ">Flask</a>
                        <a href="/bottle.html" class="list-group-item smaller-item ">Bottle</a>
                        <a href="/morepath.html" class="list-group-item smaller-item ">Morepath</a>
                        <a href="/other-web-frameworks.html" class="list-group-item smaller-item ">Other Web Frameworks</a>
                        <a href="/deployment.html" class="list-group-item smaller-item ">Deployment</a>
                        <a href="/servers.html" class="list-group-item smaller-item ">Servers</a>
                        <a href="/platform-as-a-service.html" class="list-group-item smaller-item ">Platform-as-a-service</a>
                        <a href="/operating-systems.html" class="list-group-item smaller-item ">Operating Systems</a>
                        <a href="/web-servers.html" class="list-group-item smaller-item ">Web Servers</a>
                        <a href="/wsgi-servers.html" class="list-group-item smaller-item ">WSGI Servers</a>
                        <a href="/source-control.html" class="list-group-item smaller-item active">Source Control</a>
                        <a href="/application-dependencies.html" class="list-group-item smaller-item ">Application Dependencies</a>
                        <a href="/databases.html" class="list-group-item smaller-item ">Databases</a>
                        <a href="/no-sql-datastore.html" class="list-group-item smaller-item ">NoSQL Data Stores</a>
                        <a href="/web-design.html" class="list-group-item smaller-item ">Web Design</a>
                        <a href="/cascading-style-sheets.html" class="list-group-item smaller-item ">Cascading Style Sheets</a>
                        <a href="/javascript.html" class="list-group-item smaller-item ">JavaScript</a>
                        <a href="/continuous-integration.html" class="list-group-item smaller-item ">Continuous Integration</a>
                        <a href="/code-metrics.html" class="list-group-item smaller-item ">Code Metrics</a>
                        <a href="/configuration-management.html" class="list-group-item smaller-item ">Configuration Management</a>
                        <a href="/static-content.html" class="list-group-item smaller-item ">Static Content</a>
                        <a href="/caching.html" class="list-group-item smaller-item ">Caching</a>
                        <a href="/task-queues.html" class="list-group-item smaller-item ">Task Queues</a>
                        <a href="/application-programming-interfaces.html" class="list-group-item smaller-item ">Application Programming Interfaces</a>
                        <a href="/api-integration.html" class="list-group-item smaller-item ">API Integration</a>
                        <a href="/api-creation.html" class="list-group-item smaller-item ">API Creation</a>
                        <a href="/logging.html" class="list-group-item smaller-item ">Logging</a>
                        <a href="/monitoring.html" class="list-group-item smaller-item ">Monitoring</a>
                        <a href="/web-analytics.html" class="list-group-item smaller-item ">Web Analytics</a>
                        <a href="/web-application-security.html" class="list-group-item smaller-item ">Web Application Security</a>
                        <a href="/best-python-resources.html" class="list-group-item smaller-item ">Best Python Resources</a>
                        <a href="/development-environments.html" class="list-group-item smaller-item ">Development Environments</a>
                        <a href="/about-author.html" class="list-group-item smaller-item ">About the Author</a>
                        <a href="/change-log.html" class="list-group-item smaller-item ">Change Log</a>
                        <a href="/future-directions.html" class="list-group-item smaller-item ">Future Directions</a>
                        <a href="/what-full-stack-means.html" class="list-group-item smaller-item ">What "Full Stack" Means</a>
                        <a href="/why-use-python.html" class="list-group-item smaller-item ">Why Use Python?</a>
                        <a href="/websockets.html" class="list-group-item smaller-item ">WebSockets</a>
                </div>
  </div>
  </div></div>
        <hr/>
        <div class="footer pull-right">
            <a href="http://www.mattmakai.com/" class="underline">Matt Makai</a>
            2014
        </div>
    </div>
    <script type="text/javascript">
setTimeout(function(){var a=document.createElement("script");
var b=document.getElementsByTagName("script")[0];
a.src=document.location.protocol+"//dnn506yrbagrg.cloudfront.net/pages/scripts/0016/5846.js?"+Math.floor(new Date().getTime()/3600000);
a.async=true;a.type="text/javascript";b.parentNode.insertBefore(a,b)}, 1);
</script>    <div style="display: none;">
        <img src="https://www.linkedin.com/profile/view?authToken=zRgB&authType=name&id=3952407" />
    </div>
</body>
</html>