# Git Guide In this guide we are going to show you how to use Gitlab, however before we get going setting things up it's good to get an understanding of the tool works that powers Gitlab (and Github). So let's dive in and take a look. Where possible I'll include instructions for Github but this guide focuses on using Gitlab primarily. Have a read about whatis git first, this will help you understand whats happening under the hood, after that you can get going with learning the following operations: - [Setting up git on your machine](#getting-setup) - [Getting code (clone and pull)](./getting-code.md) - [Sharing code](./commit.md) - [Learning to branch](./branches.md) - [Merging branches](./merging.md) ## So what is Git? At it's core git is a versioning system to store your code also known as a version control system (VCS). It was developed in 2005 by the creator of the Linux Kernel, Linux Torvalds. The system also allows developers to work on code simultaneously as each developer *checks out* a local copy of the *repository* to make their changes on. These changes can then be *committed* back to the central repository and other developers can *pull* these updates into their local copy. These are all terms you'll get familiar with as we go through this guide. Developers can *branch*, *fork* and *merge* repositories allowing flexible workflows to happen, we'll cover these concepts in the documents and video's that follow. ### Structure of a repo (Stages) To understand all these terms lets first look at a git repository and its stages, this is how code gets from the developers working directory to being synchronised with the remote repository. We can think of this in four main areas, your working directory, a staging area, the local repository and the remote repository. Now depending on if the remote repository already exists depends on if you run a ```git init``` or a ```git clone``` command, and these commands kind of do what they sound like. Init sets up the necessary files to start tracking the changes in a **new** repository on the local file system, where as clone pulls all the current content from the remote repository and copies it to your local repository and sets up your working directory also. If you want to get changes from the remote repository that someone else has uploaded you can run *pull* to bring those changes into your working directory. The staging area comes into play as an intermediate space that sits between working directory and local repository. A developer *adds* changes to the stage area, if they are happy with the change they *commit* the changes to the local repository and then when they are happy can *push* those changes to the remote repository. Lets try and visualise this in the diagram below. ```mermaid flowchart TD A[Working Directory] -->|git add| B(Staging Area) B --> |git reset| A B --> |git commit| C(Local Repository) C -->|git push| D[Remote Repository] D --> |git fetch| C D --> |git pull| A ``` ## Sharing code Pushing code to a new repository requires two steps, first you must **commit** the code to your local copy and when you're ready you can **push** that to a remote repository. You can read more about how to commit code [here](./commit.md) ## Sync Issues When working with other developers you're all going to be cloning and pulling the code from the remote repository, if you are all commiting back to the same repository this can lead to something called **merge conflicts**, we'll learn how to deal with them later, but another stratergy is to use branches. You can read more about how to merge [here](./merging.md) ## Branches In a git repository you have a **main** branch. This is where you keep the current code, normally the current working code. When you develop new features, often team members work on these in parallel to each other and you guessed it they don't want to be dealing with loads of merge conflict issues. Luckily, there's a way to avoid this by using a feature called **branch**. This lets you take a point in time copy of the repository and work on the code, adding, committing and pushing files as you please, without breaking things for others. Now when you are ready to move your code into the main branch you do something called a merge, often called a merge request(MR) or pull request(PR) - (these are the same thing). What git does here is move your new files into the main branch and if there are any merge conflicts on files that already existed you'll get the options to handle them like before. You can switch between branches using the **branch** and **checkout** commands. Let's try and visualise this in the diagram below showing we have a main branch and two feature branches called A and B, these branches are taken at different times from the main branch. We can also see that Feature A gets merged back into the main branch. Now you'll also notice numbers next to each dot in the diagram. These are the UID's for the commits you make. These are super important because it means you can roll back to a previous version of the code by using that UID at any time! ```mermaid gitGraph commit commit branch feature-A checkout feature-A commit commit commit checkout main commit branch feature-B checkout feature-B commit commit commit checkout main commit commit commit merge feature-A commit commit ``` Using branches to manage your code is often referred to as Pull Request Workflow, its great for teams for sharing knowledge and encourages code reviews from other team members, but that can introduce delays in getting your feature merged. You can read more about how branch [here](./branches.md) ### HEAD The most recent commit on the currently checked-out branch is indicated by something referred to as the HEAD. This is a pointer to any UID within the repository and when new commits are pushed the HEAD updates. This is how git knows to compare your commit with the HEAD to make a diff on the remote repository. If you have a branch checked out HEAD points to the latest commit on that branch. You can also get something called **detached HEAD state** which is where the HEAD isn't pointing to the latest commit of the branch, but we'll deal with that later. ### Tags You can also take those UID's and tag them. You usually use this feature to mark a particular milestone on the main branch such as the release of v1 or v1.1 and so on. They mark the particular UID meaning that someone is able to check out the code that went into a v1 package for example. We can visualise this with the diagram below. ```mermaid gitGraph commit commit tag: "RC_1" commit commit tag: "v1" commit commit commit tag: "v1.1" ``` ## Forks Forks are kind of like branches, but instead of just making a slight deviation from main you actually get a full working repository of your own. Making commits and pushes will only ever effect your git repo however there is a tie back to the original repository that allows you to pull updates from upstream. Developers can then make merge/pull requests backup stream to the main project. This is particularly useful if you want to make contributions to some code that doesn't belong to your team so you can't create a branch on the main repo. This is known as the Forking Workflow. There are other workflows however such as the Gitflow Workflow which involves having several long lived branches such as main, develop and release branches. You can also completely ignore all these features and do something called Trunk-Based development where everyone commits to main, and this is good for rapid iteration but can give you merge conflict nightmares! ![Git Merge Conflicts](./img/merge.gif) ## Getting Setup Right that's enough theory lets get you set up to start with! The commands I'm about to show you will work on MacOS, Linux or windows. You first need to make sure you have git installed on your system, which you can get from [here](https://git-scm.com/). On MacOS and Linux you can then use your native terminal to run the ```git``` command and on windows you'll want to open the git bash program. ## Username and Email When you pull a private repository or push to a repository you have two options use HTTPS or SSH. You should use SSH where possible, HTTPS can be used when you are cloning someone else's work to use but don't intend on pushing back to that repository. Now hopefully you'll have a login to [Gitlab](https://gitlab.com) or [Github](https://github.com) if not go and set one up now. The first thing you'll need to do is set up your name, so git can use this to show to other who committed the code. Simply run the following in your terminal. ```bash git config --global user.name "Ric Harvey" ``` Now lets go ahead and set up your email address, which will be used to identify you when you commit code and login via SSH. ```bash git config --global user.email ric@rics-superdomain.com ``` Right now we need to generate you an SSH key. These come in two parts private and public. You are going to want to protect your private key and not let anyone else get a copy of it as this is your key to push code on Gitlab or your repository. In your terminal again run: ```bash ssh-keygen -t rsa -b 2048 -C "" ``` Press ``enter`` to the next question which will have an output like this ```bash Generating public/private ed25519 key pair. Enter file in which to save the key (/home/user/.ssh/id_rsa): ``` Now enter a passphrase for your key, alternatively you can leave this blank but best practice says you should protect it! ```bash Enter passphrase (empty for no passphrase): Enter same passphrase again: ``` Now we need to use your public key with repository host normally Gitlab or Github.
Instructions for Gitlab #### Add your key - Copy the contents of your public key. If you followed the example above you can run: ```cat ~/.ssh/id_rsa.pub``` - Sign in to GitLab. - On the left sidebar, select your avatar. - Select Edit profile. - On the left sidebar, select SSH Keys. - Select Add new key. - In the Key box, paste the contents of your public key. - In the Title box, type a description, like Work Laptop or Home Workstation. - Optional. Select the Usage type of the key. It can be used either for Authentication or Signing or both. Authentication & Signing is the default value. - Optional. Update Expiration date to modify the default expiration date. - Administrators can view expiration dates and use them for guidance when deleting keys. - GitLab checks all SSH keys at 01:00 AM UTC every day. It emails an expiration notice for all SSH keys that are scheduled to expire seven days from now. - GitLab checks all SSH keys at 02:00 AM UTC every day. It emails an expiration notice for all SSH keys that expire on the current date. - Select Add key. #### Verify you can connect To ensure you’re connecting to the correct server, check the server’s SSH host keys fingerprint. For: ``` GitLab.com, see the SSH host keys fingerprints documentation. GitLab.com or another GitLab instance, see gitlab.example.com/help/instance_configuration#ssh-host-keys-fingerprints where gitlab.example.com is gitlab.com (for GitLab.com) or the address of the GitLab instance. ``` - Open a terminal and run this command, replacing gitlab.example.com with your GitLab instance URL: ``` ssh -T git@gitlab.example.com ``` - If this is the first time you connect, you should verify the authenticity of the GitLab host. If you see a message like: ``` The authenticity of host 'gitlab.example.com (35.231.145.151)' can't be established. ECDSA key fingerprint is SHA256:HbW3g8zUjNSksFbqTiUWPWg2Bq1x8xdGUrliXFzSnUw. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added 'gitlab.example.com' (ECDSA) to the list of known hosts. ``` - Type yes and press ``Enter``. - Run the ```ssh -T git@gitlab.example.com``` command again. You should receive a Welcome to GitLab, @username! message.
Instructions for Github #### Add your key - Copy the contents of your public key. If you followed the example above you can run: ```cat ~/.ssh/id_rsa.pub``` - Sign in to Github - In the upper-right corner of any page, click your profile photo, then click Settings. - In the "Access" section of the sidebar, click SSH and GPG keys. - Click New SSH key or Add SSH key. - In the "Title" field, add a descriptive label for the new key. For example, if you're using a personal laptop, you might call this key "Personal laptop". - Select the type of key, either authentication or signing. - In the "Key" field, paste your public key. - Click Add SSH key. #### Verify your key - Open Terminal. - Enter the following: ``` ssh -T git@github.com # Attempts to ssh to GitHub ``` > You may see a warning like this: ``` The authenticity of host 'github.com (IP ADDRESS)' can't be established. ED25519 key fingerprint is SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU. Are you sure you want to continue connecting (yes/no)? ``` - Verify that the fingerprint in the message you see matches GitHub's public key fingerprint. If it does, then type yes: ``` Hi USERNAME! You've successfully authenticated, but GitHub does not provide shell access. ``` > You may see this error message: ``` ... Agent admitted failure to sign using the key. debug1: No more authentication methods to try. Permission denied (publickey). ``` > This is a known problem with certain Linux distributions. For more information, see "Error: Agent admitted failure to sign." - Note: The remote command should exit with code 1. - Verify that the resulting message contains your username. If you receive a "permission denied" message, see "Error: Permission denied (publickey)."
## Advanced Setup (Highly Recommended) #### Create a GPG key If you don’t already have a GPG key, create one: - Install GPG for your operating system. If your operating system has gpg2 installed, replace gpg with gpg2 in the commands on this page. - To generate your key pair, run the command appropriate for your version of gpg: ``` # Use this command for the default version of GPG, including # Gpg4win on Windows, and most macOS versions: gpg --gen-key # Use this command for versions of GPG later than 2.1.17: gpg --full-gen-key ``` - Select the algorithm your key should use, or press ``Enter`` to select the default option, RSA and RSA. - Select the key length, in bits. GitLab recommends 4096-bit keys. - Specify the validity period of your key. This value is subjective, and the default value is no expiration. - To confirm your answers, enter y. - Enter your name. - Enter your email address. It must match a verified email address in your GitLab account. - Optional. Enter a comment to display in parentheses after your name. - GPG displays the information you’ve entered so far. Edit the information or press O (for Okay) to continue. - Enter a strong password, then enter it again to confirm it. - To list your private GPG key, run this command, replacing with the email address you used when you generated the key: ``` gpg --list-secret-keys --keyid-format LONG ``` - In the output, identify the sec line, and copy the GPG key ID. It begins after the / character. In this example, the key ID is **30F2B65B9246B6CA**: ``` sec rsa4096/30F2B65B9246B6CA 2017-08-18 [SC] D5E4F29F3275DC0CDA8FFC8730F2B65B9246B6CA uid [ultimate] Mr. Robot ssb rsa4096/B7ABC0813E4028C0 2017-08-18 [E] ``` - To show the associated public key, run this command, replacing with the GPG key ID from the previous step: ``` gpg --armor --export ``` - Copy the public key, including the **BEGIN PGP PUBLIC KEY BLOCK** and **END PGP PUBLIC KEY BLOCK** lines. You need this key in the next step. #### Add the key to your account
Instructions for Gitlab To add a GPG key to your user settings: - Sign in to GitLab. - On the left sidebar, select your avatar. - Select Edit profile. - Select GPG Keys (). - Select Add new key. - In Key, paste your public key. - To add the key to your account, select Add key. GitLab shows the key’s fingerprint, email address, and creation date: ![GPG key single page](./img/gitlab_gpg.png) - After you add a key, you cannot edit it. Instead, remove the offending key and re-add it.
Instructions for Github - Sign into Github - In the upper-right corner of any page, click your profile photo, then click Settings. - In the "Access" section of the sidebar, click SSH and GPG keys. - Next to the "GPG keys" header, click New GPG key. - In the "Title" field, type a name for your GPG key. - In the "Key" field, paste the GPG key you copied when you generated your GPG key. - Click Add GPG key. - To confirm the action, authenticate to your GitHub account.
### Sign your commits After you add your public key to your account, you can sign individual commits manually, or configure Git to default to signed commits. But first we need to let Git know about your GPG key. #### Tell Git about your signing key - Open your terminal. - Use the gpg command to list the long form of the GPG keys for which you have both a public and private key. A private key is required for signing commits or tags. ``` gpg --list-secret-keys --keyid-format=long ``` > Note: Some GPG installations on Linux may require you to use gpg2 --list-keys --keyid-format LONG to view a list of your existing keys instead. In this case you will also need to configure Git to use gpg2 by running git config --global gpg.program gpg2. - From the list of GPG keys, copy the long form of the GPG key ID you'd like to use. In this example, the GPG key ID is ```3AA5C34371567BD2```: ``` $ gpg --list-secret-keys --keyid-format=long /Users/hubot/.gnupg/secring.gpg ------------------------------------ sec 4096R/3AA5C34371567BD2 2016-03-10 [expires: 2017-03-10] uid Hubot ssb 4096R/4BB6D45482678BE3 2016-03-10 ``` - To set your primary GPG signing key in Git, paste the text below, substituting in the GPG primary key ID you'd like to use. In this example, the GPG key ID is ```3AA5C34371567BD2```: ``` git config --global user.signingkey 3AA5C34371567BD2 ``` #### Sign individual Git commits manually Add -S flag to any commit you want to sign: ``` git commit -S -m "My commit message" ``` - Enter the passphrase of your GPG key when asked. - Push to GitLab/Github and check that your commits are verified. #### Sign all Git commits by default If you want to sign all your commits from now on, and I recomend this, run the following command. ``` git config --global commit.gpgsign true ``` Now you're all ready to get started with learning how to use Git and we can start that journey by learning how to **clone** and **pull** code, head [here](./getting-code.md) for more information. --- ##### Follow me for more guides [](https://awscommunity.social/@Ric) [](https://www.linkedin.com/in/richarvey/)