 So my name is Rodrigo and I will talk a little about how Git can help you work a little less. Anyone here uses Git every day? Okay, so I'm talking to the right people. Happy Star Wars Day. If you want to talk to me later, you can send me an email or talk to me on Twitter. So Git can help you mainly in five ways to work less by what I'm showing you today. Git can help you identify if the code you are committing follows all the company standards. Identify where a commit came from. I had this problem a lot of times in QA when you find a bug and you don't remember which branch that file was changed last time. You can make sure at least the files changed are being tested before you push any code to your CI system. You can start the CI system build using Git and I will show you two different approaches to deploying a system using only Git. Of course, this is for simpler systems that don't need a lot of bunch of automation, but it solves a lot of problems when you are starting or building a system from scratch. Do you do any of these daily, you need to write a good commit message or check if the code you are writing follows all the standards of the company, the formatting and you are not using anything that's deprecated and things like that. You need to compile assets every time you deploy something or install NPM modules, run migrations. I think everyone that works with Rails do all of that and you don't need to anymore. My goal is to automate all that tasks at least at some point. So the way I work when I am committing something, I use Git to check the standards, all the formatting and deprecated methods and there are tools to do that, it runs that every time. I add information to the commit message, when I push code, I run tests, then I start the CI build using Git and when I pull code, I install any new gems or NPM modules. And for deployment, there are some situations where you don't need Capistrano or any fancy tool to automate the deployment, just Git will solve everything you need. And I will show you how Heroku works too. Anyone here uses Heroku? So, putting Git to work is mainly learning to use the Git hooks. Git has a lot of workflow hooks, that's how Heroku works, that's how GitHub do almost all their magic. It's just learning to use the tools that are already there and they are already available to you on a daily basis. So, why did I start to do this, to learn this? Once upon a time I had a problem with a co-worker that decided he didn't need to follow the company formatting code formats and used all the methods that we told them not to use and my boss told me I needed to talk to him and fix things. I tried that, my boss tried that and Git solved the problem for me. Yeah, I will show you how to fight your evoker worker. So, I just added Git pre-commit hook, calling rubo code to check every file that was changed and if rubo code doesn't like it, it's not committed, just like that. I think this is too small to read or it's okay. So, the only important part in this code is the red one. The rest is just how you find which files were changed in this commit and this is a really simple bash script. You can write these Git hooks using anything that you can hashbang in this script. Sometimes I use bash or sometimes I use ruby. I never use Perl because I'm afraid of it. Yeah, I know how to write Perl. The problem is that you don't update a Perl code, you just write again, it's impossible to evolve the code. So, this was the magic Git did for me. It prevents anything that rubo code doesn't like to be committed. Of course, you also need that dot rubo code to configure it and tell what's your company's standards and what verifications you need, what you don't, but that's the trick. Of course, you need to install it on every machine. The Git hooks are not committed to the repository. They are specific to each repository and every machine has a different repository. I will show you how to fix that later. Excuse me. There was another time that I was working on a bug in the QA environment and we were working on six or 10 different features and that file was changed with a lot of features and that bug was specific to one of that features and I didn't remember which branch was that. So, to prevent that from happening again, I decided that every commit needed to have the branch name in the beginning and I didn't want to forget to do that. So, I just edited the format commit message Git hook on my repository and used it a little sad to add the branch name to the start of every commit message and it never happened again. So, usually these hooks help me not forget what I want to do and does anyone have the problem with someone working on the company that feels like life is too short to run your test before committing anything before pushing code, yeah. That was the same co-worker. Yeah, no, it was not just one. It happened in different companies but... And now I will change the screen to... Okay, I need to move it and the... Yeah, that's the one. I wanted to make sure at least the files changed in that push were being tested for every commit. Every time someone was pushing something to the repository so why just the changed files, why not all the tests because the CI server would run all the tests anyway and this is faster than running everything. Sometimes you have very lengthy tests that needs running and the CI server is there for it so you could run the test just for the changed files. The idea here is to identify the branch name that is being pushed. Then I get only the changed files getting the depth of that branch with the original one from the main repository. From that files, this is a sample script. It's not the live one. We are using RSpec and I have a lot of code from auto-tests in the live script but this was easier to explain during the presentation. I just find everything that's inside app and change for tests and add test.rb at the end. If it's already in the test directory, just use the name if it's in any other directory. Just ignore that. Then I check if any of these tests doesn't exist if it's not the push is aborted because there is a missing test. Otherwise, if there is something changed in the config directory, you need to run all the tests before pushing. I do a git stash to prevent any uncommitted change to make tests pass and then it's missing in the server and nothing works there. Then just run Rails test passing the file names and that's all. If the test exists with non-zero results, I abort the push. That's the same logic but it helps fix a lot of broken builds in the CI server that we are using. It's not just for that evocal worker but of course it's fine that way but it helped me a lot because running only the changed files test is a lot faster when you have a really big application. Do you remember that you need to install the git hooks on every machine? So writing that really cool git hooks on my machine would not solve my problem with my evocal worker. I needed to do some magic to make it run on every machine. And it's really easy. I tried to write a Ruby gem to install it automatically. It seemed possible because installing a gem doesn't have an after-install hook. The best you can do is just play... I'm installed message to do that but showing a text message would not solve my problem. I needed something that would install the hooks automatically. And I discovered that when you install an NPM module, it runs a post-install script. I started writing one, then I decided oh, someone probably did that already and I found shared git hooks. It's a small NPM module that after you install it runs the hooks from the hooks directory in your application. It assumes that you have a .git directory and in the same folder you have a hooks directory with the code you need to run. So you just put your hooks there and that's a folder you can commit to the repository and you can just hash bank the script or add .rb.pl or any extension that is executable for your environment. And it will just... After the first install of this module all the hooks will be installed and will be executed from that directory. So this... Mainly installing this solved my problem. Okay, but sometimes it's too much automation because that gem... You need to make sure that gem is not installed on the server because you don't need your development hooks running on a production server that can cause a lot of problems sometimes. Depending on what you do and how do you do. So just be careful. Install that only for the dev environment. Never automate a hook install only install for the server because some of them can prevent you from being able to update the code on the server and that would be really bad. Have you ever discovered that you needed an extra gem or NPM module or anything like that when you decided to finish your work during a flight or something like that? That happened to me three days ago. I... When flying here, I decided I was not taking the day out of work. I was working in the airport and during the flight and I updated my code before flying. I tried to execute the application and it was impossible. I didn't have internet, I didn't have a new NPM module that one of my coworkers added to the application. In that case, I just commented it out and it was not a big change. It was just to define a color for a bubble in the application. So it worked out, but it might create problems if you need to work offline one day. One of the cool things of having the entire repository in your machine is that you can work offline. But if you don't have all the dependencies, you don't have that. So you can just add a Git post merge in your repository and post merge will be executed every time you do a Git pull or you merge any branches into your branch and it will run after it so you can't abort what's done. It's just to automate tasks after it happened. So after I forgot that, I added this code to my repository and it will never be a problem to me again. Probably it will happen again in another application where I forgot to add this hook, but nothing is perfect. Who uses continuous integration here? Okay, I thought I would get more hands, the ones that didn't raise your hands, you need to start doing it. Do you know how most of the continuous integration servers work to check if your code is changed and start a new build? It's almost like it. Every time I'm explaining this, I remember the Shrek 2 start scene where the donkey is... Are we there yet? Are we there yet? And sometimes you want to punch the people that are doing that. Probably the server with your repository feels the same about the server with your continuous integration server because that's how it works most of the time. It has a pulling system that do from time to time. Do we have changes? Do we have changes? And you can use Git to change that. That's how some of the continuous integration systems integrated with GitHub, for example, already do what I'm saying. They just wait for GitHub to warn them there is changes in the code. The solution is simple. You just add a post-receive hook on your main repository that will call the continuous integration server in some way. Usually they have a URL that you can send a post or a get and it will start your build. I like to use TeamCity because it's well integrated with IntelliJ IDEA that I use for a lot of things. Or with RubyMind that apparently no one wants. I like the tools. They do a lot of this Git automation for you without GitHub. You wouldn't need this if you were using RubyMind. If you are using Jenkins, for example, this will start your build. You can do that from the command line or from the Git post merge hook on your main server. To do that you need to go to the user configuration on Jenkins, create an API token, and then go to the build configuration you want to start and copy the build configuration API token. You need to pass both tokens in the URL. If you are using Travis, you are probably using GitHub too and you don't need this code because this is what GitHub already do to start the Travis builds once you integrate Travis with your GitHub repository. If you are using Travis without GitHub, you can use these codes to start the builds and it will work just fine. For TeamCity, you need to put your password here in plain text so don't share this script with anyone. It's ugly, I like the Jenkins approach with API tokens, but you can't share that too, so that's not a big problem. And Bamboo, anyone here uses Bamboo? No, it's a CI server from Atlassian, really good and it has a lot of cool features like support for containers. You just add a .file in your HOOTS directory and it will start your containers with the version of all the tools you want. And it's free to use for, I think, half an hour a month. If you build this fast, you can use it for free for the entire month. If your build is slow, you'll probably need to pay. Okay, all these things I've talked about now have in some way already broke, deployed for me, a test broken, a test that was not executed, got to production and something was not tested. And everything here was... let's improve things prior to deployment. But now let's do... let's talk really about deployment. My idea here is to show you how Heroku was implemented and how you can build your own Heroku. That's... the goal is to add a Git remote to your repository and deploy the application with the code Git push production master or any other branch you need. And it's just easier than it looks. You'll just create in the server that you are building a Git Bear repository. A Git Bear repository is simply a Git repository where you don't check out your code. It's a .Git repository. It's just that. But usually with a better name because it's strange to reference something with slash.Git. So you just remove the slash and you are done. Then you edit the post-receive hook to look like this one. The post-receive hook will be executed after you push something to that repository. And it doesn't receive any common line parameter so you need to read the standard input to find out which branch is being pushed. The first time I did this I used only the master branch so I didn't need this loop. And it's not really a loop because most of the time it's pushing only one branch. But you use these codes to find out which branch you just received. And any echo or any text that you put print here will appear in the console of who is pushing the code. So it's a good way to show the stats for things. Then I will run bash in logging mode to make sure that all the RVM code is loaded because I use in this server RVM to make sure I'm using the correct Ruby version. Go to the deployed app directory. A fetch just to copy from the bare directory to the application directory. Then you check out the branch to make sure you are in the correct branch and do a git pull. And all the steps you need to do here yarn install, bundle install, assets compile depending on the application run, any other scripts you need to probably restart the server with or something like that. Of course the access to this bare repository needs to be very well secured because anyone that has access to that can deploy anything to your project. But since the idea is to reproduce Heroku anyone that can access your Heroku account can deploy anything to your server. So that's the same idea. And with this you just created the same environment that you have with Heroku except for handling extra processes that you can add later to this script or any other information, any other tools you need. And this is a version of that script where you can't read anything because the font is too small. In another server I had a very simpler approach. It was an internal application where we don't have any automation and it was already there when I got to the company. And we had a lot of problems of deploying and forgetting to compile assets or deploying and not running one code, one step or another. And I decided I needed to automate and deploy to that server. That was my first week in the company. But changing that to a really automated deploy would take a lot of time. So this is a quick hack that can save you a lot of time and when you get to somewhere that don't have time to automate things, at least not now and you need to avoid making mistakes during deployments to some application. So we just add a post-marriage hook. The same I did to make sure I had all the gems and NPM models installed. I did exactly the same thing to the server if I slightly bigger script, of course. This is a sample that I wrote in PowerPoint. It's not the one in the server because it happened five years ago and I hadn't listed about Yarn at that time but it's just to show the idea. You can do just Git pull and let these hook do all the repetitive tasks for you. This script has one problem. Sometimes you don't need to compile assets and sometimes you don't need to run a migration and migrate is fast even if you don't need it. But sometimes compiling assets depending on what you are using in the application if you are using the Webpacker with asset pipeline and depending on the amount of NPM modules you have can take a long time and it will do that all the time you do a Git pull on that repository. You probably shouldn't be doing like that so it's a quick hack. That's the problem with it. Your deploys can take a lot of time but it's better than forgetting it and the last line saved my life sometimes because more than once we deployed to that server with new assets and refresh the screen and nothing changed or client access the server two days later and why this bug is not fixed, it was fixed already we just forgot to reload the servers, the assets because in production Rails will not check the assets all the time it will just use the cached version. If you are using Git to do deployment I'm talking a lot about Capstrano because I like it and I use it a lot and Capstrano has some cool features like being able to revert your deploy to any previous version and when using this Heroku approach I was missing that feature and I found out that there is a Git deploy gem not a gem, it's just a command line utility like any other Git command that is a big lie, it will not deploy anything the name is to deceive you and it's right in the readme they use this name to deceive you the idea is to enable you to revert to any previous version so to use this gem before deploying let's say your production deployed branch is master you go to the master branch and you run Git deploy start it will create another branch and you'll merge everything you want to deploy every feature branch to that branch it created then you'll Git deploy sync it will merge the... it will finish the merge and push to the server then you can do the real deploy whatever way you want using the Heroku approach I showed or any other way then you do a Git deploy finish it will start the deployed version with deployed time everything in the Git deploy story and then you can Git deploy list and it will list what version is currently deployed what versions were deployed before when each deploy happened and you can revert your report story to any of those dates and push to the server and that's... it's just for control I never really needed that but it's a good information to have when and what was deployed every day every single deployment and I think I'm a little early on this but any questions? so... and that's all thank you for your attention