Transcription
Git is the most popular version control system in the industry, arguably the second most important skill for any developer after a programming language. Git is used in any team, in every project, in any company you could possibly end up in in the modern world. That is precisely why it is critically important for a beginner developer to know how to use Git, at least at a basic level. But it has one problem: if you've never seen it before, starting to use it will likely be quite difficult. Its main interface is the console. God help us, and there are countless commands. Moreover, when you use them, you can't always clearly see with your own eyes what happened afterwards. And sometimes you get really cringe in your own projects. Therefore, today I will explain in very simple terms all the basic concepts of this incredibly powerful tool. Hello, ladies and gentlemen, my name is Vlad. Welcome to my channel, where we talk about IT careers and life in general. In this video, I will explain to you in super simple language why you need Git at all, and also teach you how to use all its basic commands. So that you will never forget why one is needed and why another is needed. Knowing all this, dear friends, you will definitely be able to cope with any Git-related task from the real world, except perhaps only the one where you pushed a config to prod and were then fired. But Git will also be able to track the history of these events. Of course, you will ask me, dear friends, Vlad, why should I bother with this boring Git? What's the profit from it? I will answer you: remember that your ex recently left you? Well, she left because you didn't use Git properly. Because she knew that when you have Git, you can track changes to any files on your computer. And when you work in a team on the same project, that is, you change the same files, it would be very important for you to always know who changed what and when, to quickly find the culprit. Essentially, what is coding? Coding is when you take some text file and write some text in it, that's all. It doesn't even matter what this code does, what matters is that it's just text, in fact. Essentially, what does it mean to be able to program? It's the ability to press buttons in the correct order, right? So, imagine that you have developed a revolutionary application, for example, to call your buddies for a showdown behind the stadium. Everyone is delighted with it, in short. But you've also come up with some new brilliant feature for it. For example, you've added promo codes for buying Baltika 9 for your showdowns. And this is an extremely important functionality for all your users, fundamental, which required changing a huge number of existing files in your system. You took all these files, collected them into some single executable file, for example, a .exe or .jar, and put it on some server with which your direct users of your magnificent application interact. Now, after this action, they finally have access to this new feature that you added there. But it suddenly turns out that after you added all the changes to production, there's a bug in your code that users quickly find, and it greatly hinders them, and the new feature doesn't work because of it. And, for example, the old functionality also breaks. Users are furious, obviously. And you need to urgently somehow return everything back as it was, and so that users work with a stable version, and you can dig into your new functionality for a longer time and find this problem to solve it. But how to do this if you just have physical code files? You'll have to open them and try to remove this new code that is potentially broken, and not just remove it, but also back it up somewhere so that you can return to it later and try to fix this bug. But what if there are thousands of lines and a bunch of changed files? It's very difficult. It will take you a lot of time to reassemble these pieces later. You'll just get tired of it. And users, they don't wait, they don't care. They just start shouting, "Nothing works for me! Bring it back as it was! I don't want to see you!" And instead of helping them very quickly, you're busy moving text from one file to another. This is one of those problems that Git solves. Initially, when developing your application, you can take all its files and put them under Git control. And from that moment on, Git will track all changes within these files, on which lines they occurred, what changed, to what, when, who did it, and much more. As a result, if you have a problem like this, but Git tracks your files, you can simply come and say, "Excuse me, Mr. Git, can you please take all my files and return everything as it was before I broke everything myself, and when my application prospered and users were happy?" And he will simply take and return it like that. But moreover, he will also save the unstable version within himself. He won't just delete it, he won't lose it. It will also continue to be stored there, and you can switch to it separately. That is, you simply ask Git to roll everything back, it rolls it back instantly for you. You reassemble these files again, put them into a new .jar file, for example, and upload them to prod. Now, users have the stable version they were working with before. Everything is fine with them, they continue to feel good. And you, meanwhile, with your team, ask Git to give you that broken version and sweat over it to find that very bug that destroyed everything. But these are not even all the possibilities of Git. This is just one of them, but which should already show you how important and cool a thing it is in development. But right now, we will talk about all the main other capabilities of this wonderful tool. In general, Git is just a special program that you install on your computer. You can download it completely for free, without registration, SMS, from the official website. No viruses or banners will appear on your computer after that, don't worry. Then, just install it like any other program. The main interface for working with Git is the console. So, open any terminal on any operating system you have and start configuring Git for work. We need to set the username under which we will make all changes to the files that Git tracks, so that it can remember who exactly changed these files on our computer. Well, that's us. Such settings are set using the command `git config`. We type this in the console and then specify the `--global` parameter to say that these settings will apply to any file that we give under Git control. And then we specify the name of the setting we want to update. To update the username, you need to write `user.name`, and then in double quotes, specify the specific value that we want to write there. For example, in my case, it will be Vlad Mishustin, and that's why I write exactly that. In exactly the same way, we specify the email for the user, but now instead of `user.name`, we write `user.email`, and in quotes, we specify the desired email. Obviously, now Git has remembered these settings and will apply them to any files that you change. You will be known by this name in the change history of a particular file. Now, you should also create an account on the github.com portal. Do not confuse Git and GitHub. Git is a special program that tracks changes in all files on your computer, while GitHub is a special web application that allows you to upload all your file changes from your computer to the cloud and store them there so that other people can also access them. Why else would you store these files in the cloud? Because imagine a situation: you have written a huge amount of code on your computer in files that are stored on your computer, and then you catch that very malicious banner. It appears on your entire screen with all the necessary things, and it says you need to wipe your hard drive to remove it. This means that you will lose all the work you have done. So, Git allows you to take all your code and upload it to GitHub, where it will be stored not on your computer where everything can go to waste, but in the cloud on many different computers with many copies, and so on. That is, nothing will happen to it there for sure, and you can always access it from any computer at all. But moreover, this means that your team, for example, can also access it. That is, in this way, you share your files, your developments, your projects with people. The key is the repository. Essentially, a repository is just a folder with files that Git tracks on your computer. And in this regard, there can be as many repositories on your computer as you want. That is, one folder, for example, with your project, Git tracks it - this is one repository. Another folder with your diploma, which doesn't exist, is the second repository, and so on. All internal folders and files of the repository are also automatically under Git's supervision and control. Thus, any change to any file in your repository is automatically remembered and tracked by Git. Now, a repository can be local and remote. A local repository is simply that same folder with files that is stored on your computer, on your computer specifically, which Git tracks. Whereas a remote repository is this very local one that you had. You took it and, using Git, uploaded it, for example, to GitHub, and now it is stored there. This is a remote repository. That is, it is created based on a local one. It is essentially a copy of your local repository, but which is now stored not on your computer, but in the cloud somewhere, that is, remotely. And this means that your local repository and the remote repository created based on it are linked to each other, and Git provides this connection for you. Now, how to turn your usual directory into a Git repository? To do this, you need to first go to the folder you want to make a repository in the terminal. The `cd` command allows you to do this, after which you need to specify the path to that very folder where you want to be. By executing it, you immediately go to the specified directory. Being here, you can now execute the `git init` command, which informs Git that this directory needs to be turned into a repository, that is, in fact, to track all files and folders that are here. From this moment on, Git knows everything. Now, how to create a remote repository? First, go to your profile on GitHub, and there create an empty repository. To do this, just click the "New" button, enter the name, choose the desired access parameters, and save. In general, now you have an empty remote repository on GitHub, but it doesn't know anything about your local one yet. So, this connection needs to be established somehow. To do this, in your local repository, you need to execute the command `git remote add origin` and specify the URL of your repository. We will take the repository URL from GitHub, where we just created everything necessary. In general, this is the command we just wrote, it says that you need to take the local repository in which you are executing this command and add a remote to it that is available on GitHub at this URL. After executing this command, your local and remote repositories become linked, but nothing is copied anywhere yet, obviously. Now, it's time for changes in the files in your local repository. When you are ready, you can tell Git to publish them all to the remote copy. But note that Git will not do anything on its own. It will publish only when you explicitly tell it to. We will talk later about how to do this, so don't worry. If you suddenly made some hard cringe locally so that everyone will see it right now, no, until you publish it yourself, public opinion about you will remain good. But this is obviously temporary. And now, how can other people, participants in your team, for example, download the code that you will upload to your new remote repository in the future? Essentially, they can take your local repository and, based on it, create a local repository on their computers. That is, note that essentially it is just a new copy of your remote repository on another computer. But this is precisely another, second copy. That is, you have your copy of the local repository on your computer, and another participant in your team has another copy, that is, another local repository. But both of them are linked to the same remote repository. That is, it is common for them. To create a local repository on your computer that completely copies a remote one, you first need to go to the folder where you want to download the copy of the remote repository in the console. You can use the same `cd` command for this, for example. And then, run the `git clone` command, and after it, specify the URL of the remote repository. We take the URL of the remote repository from GitHub, of course. That is, this is precisely the URL of the repository that we want to download to our computer. We run it, wait a bit for everything to download, and boom, you have a new folder on your computer with all the files that are in that remote repository. This folder is immediately your local repository. That is, Git is already tracking all changes here, and this local repository is already automatically linked to the remote one. You don't need to do anything else explicitly for this. But again, it's important to understand that when you change something here in this new local repository, these changes will by no means be automatically reflected in the remote one. Only when you explicitly tell it again, "Please, Git, upload them to GitHub," will it do so. Until then, you are simply changing your local copy. Only you, the owner of this local copy, see these changes. Now let's talk directly about making changes to files in your local repository. I have a simple text file `README.md` open here, which is located in a local repository linked to a remote one on GitHub. Right now, this file is empty, and let's assume I want to make some changes to it. To do this, I just need to work with this file. At this stage, I am not specifically tied to Git, so I will just add a couple of lines here for example. As you remember, dear friends, Git tracks all changes to files in the repository, so let's make sure that this is indeed the case. Git knows that we have changed this file. To understand the state in which Git currently sees our files within the repository, you can execute the `git status` command. This command will output information about all unfinished files in the Git repository to the console, i.e., those whose version we have changed but have not yet saved these changes within Git. As you can see, dear friends, Git shows us that right now it sees one changed file, but which has the state "uncommitted." This means that Git knows that this file is changed, but if you were to delete everything from it right now, for example, you wouldn't be able to return to the point where all this text was still in place. That is, we have not yet saved this version of the file within Git so that we can return to it later if necessary. Saving a specific version of a file within Git is called a commit. That is, if I want to be able to quickly jump to this version of the file in the future, I must commit such a state of it to Git. And it's quite simple to do, because in the process of making changes to the repository, you can change many files. So, before making a commit, you must first tell Git which of these changes you want to save as a separate version, i.e., a commit within Git. To select the necessary files from all the changed files and prepare them for a future commit, use the `git add` command. After this command, you need to specify the names of the files or folders that you want to prepare for saving. To prepare all files at once, you can simply write a dot, which indicates the directory in which you are right now, i.e., it selects all files from the current directory. Now, after we have executed `git add`, if we execute the `git status` command again, we will see that Git now knows that the changes in our file are ready to be saved, and are not just gathering dust in obscurity. The place where Git currently stores information about which files are ready for commit is called the Git index or staging area. Only those files that are in the index will go into the next commit. When you have added changes to the index and are now ready to save them in Git history, you need to execute the `git commit` command. It also has parameters, after which, in quotes, you can specify a message describing the version of files that you are saving. This is convenient so that you can later understand what exactly is contained in this version. When you execute `git commit`, a new checkpoint will be created within Git, which is called a commit. Essentially, this means that it has remembered the state that you committed. You can return to this state if you need it someday. You can make many commits one after another, thus saving different versions of your files. Git stores the entire commit history, so you can then return, as it were, back in time to any of these commits, completely, if you know its number. Let's change our `README.md` file a bit more to repeat the exercise and create another commit in Git with another version of this file. Let's add some text. Now, execute the `git add` command to place the changed files into the index and tell Git that these are the ones we want to commit in the future. And now, after they have been added to the index, we can make a commit with the `git commit` command. And here, it commits only those files that are in the index, obviously. And since we now have several commits, it would be great to see what they look like. You can do this using the `git log` command. This command will display information about all the commits you have made so far on the screen in chronological order. As you can see, dear friends, there is the specific commit number, as well as the message we specified, which allows us to much better understand which version of our files is in this commit. And it is precisely this number, or as it is also called, the commit hash, that allows us to, as it were, return in time to this version that we saved at this point. Let's look. Right now, we are looking at the very latest version of our file that we just updated. But what if I quickly want to return to the previous one? To do this, I can simply execute the `git checkout` command and specify the commit hash to which I want to return. As you can see, dear friends, we have returned exactly to the version of our file that we saved the first time. You will tell me that this is not very impressive, Vlad, and we could have just pressed Ctrl+Z. But imagine that you have 50 such files, and you also want to return to some version that existed a couple of weeks ago. Then Git is simply indispensable. All these commits are now in your local repository. This means that if you are working with a team on some common project, then other participants still do not see the changes that you have made to these files, not the versions that you have saved. Since your local repository is linked to the remote one on GitHub, you can use Git to take all your commits that you have made and from the local repository to the remote one, so that other participants in your team can download these commits to themselves from this remote repository. To upload the made commits to the remote repository, it is enough to be inside your local repository in the terminal and execute the `git push` command. After this command, you need to specify the name of the remote repository to which you want to upload all this. Any local Git knows its remote repository by the codename `origin` so as not to write the URL every time. So, we write `origin`. Also, after the name of the remote repository, you need to specify the name of the branch of changes into which you are uploading the commits. We will talk about branches a little later. For now, you can write `master`. This is our main and only branch of changes for now. It always exists. We press Enter and see how it starts sending our commits and files to the GitHub servers, to our remote repository. Now you can go to GitHub, to our repository, and see our file there in its current state. Here you can see the last commit. But in fact, GitHub also stores all the history, it is also available. Now, imagine that there is another developer in your team who wants to pull those changes that you made to the `README.md` file from the common remote repository. Let's assume he cloned the entire project before you pushed your commits. Therefore, on his computer, the state of this file is still old. Here, on my computer, I have created a second folder with another local repository, which is linked to the same remote repository as the first one. In general, as you can see, the state of `README.md` here is still the old, the very first one we had initially. Now, for another participant in your team to download your commits from the remote repository, you need to execute the `git pull` command from the directory of their local repository. After which, you also need to specify the name of the remote repository, which is `origin` for us, and also the name of the branch from which we are downloading commits, which is `master` for us. We run it, it quickly downloads all the missing files for us, and voila, we see the latest version of changes here. Although before, we were looking at old files. As if someone updated them in the repo, and now we have received them. But we received not just the latest version, we received all the commits, all the history. If you now execute the `git log` command, we will see all those commits that we made earlier in another local repository. And therefore, now from this new local repository, I can move between them in exactly the same way as the author in the original, using `git checkout`. Very convenient. Now let's talk about another fundamental concept in Git: branches. Essentially, a branch in Git is just a sequence of commits that has a specific name, that's all. Therefore, in any local or remote repository that you create, there is always at least one branch, because commits, they have to start somewhere. This branch is usually called `master` or `main`, i.e., the main and only branch. But you can create as many of your own branches as you want. Why would you create them at all? Imagine a situation where you, as a developer, are working on some project and are creating a huge new feature. It's long, you have to change many files. You change them constantly, make new commits so as not to lose changes iteratively. And they are not finished. What if you broke something there? Then other people who download this remote repository with common changes will also have their files possibly unstable. The application you are working on together will break for them too, because you have a bug in an unfinished feature. Therefore, it is very convenient to conduct such development of a completely separate feature in isolation from your stable commits, so that other people can also work with this repository completely independently of you. This is precisely what branches allow you to do. When you create a branch in Git, you, as it were, "fork" it from some existing sequence of commits into a completely new, separate, isolated one with a specific name. And that's precisely why it's called branches. That is, if you create many of them from each other, you will visually get a structure that strongly resembles a tree, and each sequence of commits there is separate - this is precisely a branch of such a tree. Let's now see how exactly to work with branches in Git and what they allow you to do at all. Firstly, in our local repository, we can first see which branches we have right now. To do this, execute the `git branch` command. This command will show us a list of all branches currently available in our local repository. And right now, we have only one branch here: `master`. That very single, main branch that always exists in any repository. The asterisk marks the branch we are currently on. We are on `master`. To create a new branch from the `master` branch, it is enough to execute the `git branch` command and after it, pass the name of the new branch that we want to create. The name can be absolutely anything, but I recommend naming branches according to the changes that will be contained in them. Now, if we get the list of branches again, we will see that we now have two of them, but we are still on the `master` branch because we haven't switched to the new one, we just created it. To switch to the new branch, you need to execute the `git checkout` command, the same one, and after it, pass not a commit, but the name of the branch to which we want to switch. And now, if we look at the list of branches again, it will show us that we have indeed switched. When we create a new branch, by default, it is created based on the last commit of the branch we were on at the moment of creation. Thus, right now, the files of the `master` branch and our new branch are absolutely identical, because the new one was generally created based on `master`. But now, if we, being on the new branch, change our file and, following the old scheme, make a commit of our changes, then this commit will be made precisely in this branch of changes, and not in `master`. What does this give you? Now, if I want to switch to a stable version of changes in `master`, I just need to return to the `master` branch, and all my files will automatically correspond to the last commit precisely in `master`. We make a `git checkout` and, in general, we see that `README.md` is again in its initial state from where we came. And now, if we want to return to the second branch again and continue the unfinished work, we just do a `checkout` to it and find our file in the state where we left it. Thus, different developers can work in their own different separate branches without interfering with each other. If someone needs a stable version, they simply take `master`, and all work is done in separate branches, which can then end up in `master` when they are completed. Also, note that right now our new branch is local, meaning it exists in our local repository, but it's not yet in the remote one. So other developers won't be able to see it yet. To publish your new branch, you just need to execute the `git push` command again while in the local branch you want to publish, but in the last parameter, specify not the `master` branch, but the name of the branch that you want to give to the new remote branch on GitHub, into which you will now upload your local one. It is usually called the same as it is named locally, so that the same appears on GitHub. We run it. At this moment, commits from your local branch are published to the remote repository, just like before. But now other team members can also see your branch and switch between it and `master`, just like you, if they do a `git pull`. In general, now imagine this situation: you were working on this big feature in a separate branch, making commits for a very long time, and finally brought this feature to perfection. You consider it completely stable, and therefore you want to transfer all your changes from the development branch to the main `master` branch so that everyone can access them. That is, you want to quickly transfer all the file changes from your working branch to your main branch and merge them there with all other changes from other branches that other developers are also merging into `master`. And such a procedure in Git is called merging branches. And there are two mechanisms for performing what you want to do. The first mechanism is `merge`. `Merge` is precisely the merging. We still have a branch with our commits, and we want to transfer its state to the `master` branch. To do this, we first need to do a `checkout` to the branch into which we will do the merge, and then execute the `git merge` command with the name of the branch from which we will perform the merge. At this moment, Git takes all changes from the passed branch and adds them all to the `master` branch in the form of just one new commit. But it takes absolutely everything that was in the branch we are merging. It's easy to verify this. In general, it's enough to execute the `git log` command from `master` now and see that first there are a couple of our old commits, and here appears a new one where it is written that a `merge` has occurred, in general. Also, if we, being on the `master` branch, look at the state of our `README.md` file, we will see that it exactly matches what we saw in our second branch before. That is, all these changes have now gone into `master` and exist in the form of one new commit here. It is important to note here again that all this happens in your local repository. If you want to publish the result of the merge, you need to do a `push` of `master` to the remote repository. Now, but there is also a second mechanism for transferring changes from one branch to another. Let's go back to our second branch and make a couple of new changes to the `README.md` file in it, and then make a couple more additional commits. Let's look at the log now and make sure that there are indeed such new commits that we just made. Here they are with the corresponding messages. Now, let's assume that we again want to pull these changes into the `master` branch. But remember that in fact, it creates just one new commit in `master` that contains all the changes from the second branch that we merged. But what if I want to preserve the history of changes and transfer all commits from the second branch to `master`, and not just make some single new commit? For this, I can use the `git rebase` command instead of the `git merge` command. The procedure there is the same as with `merge`. We switch to the branch where we will do the rebase, and then run this command, specifying from which branch we will transfer commits to ours. Now, being in the `master` branch, let's look at `git log`. In general, as you can see, both commits from our second branch are now located here with their messages. Thus, if the commit history of your branch is important to you, then `rebase` is better than `merge` in this regard. You can choose a more convenient mechanism for yourself. Both of them work. I, for example, usually use `merge`. If this was a super valuable breakdown for you, please like this video. I will definitely make another video with all these animations, with all this cool format, with screencasts, with all, all, all about advanced Git techniques like cherry-picks, and also tell you how to resolve conflicts in Git, which is a very, very painful topic for beginners. I hope this video was very valuable for you, dear friends. It would be great if you subscribe to the channel, leave a comment, leave a like, anything. It really helps a lot. Also, come to my Telegram and Instagram, where I share a huge amount of unique stories about my work at Uber, life in Amsterdam, about other people from Big Tech, now, in general, a lot of interesting content. Definitely come. Thank you, and [music] see you [music]