{
  "nbformat": 4,
  "nbformat_minor": 5,
  "metadata": {
    "kernelspec": {
      "language": "python",
      "name": "base"
    },
    "language_info": {
      "name": "python"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "source": [
        "Git provides the tools to collaboratively work on a single codebase, collaboration also requires infrastructure for sharing and publishing code.\n",
        "GitHub, which is owned by Microsoft, is the dominant platform for code hosting and collaboration with over 100 million developers and 400 million repositories worldwide.\n",
        "While GitHub is the most popular choice, there are alternatives that provide a similar service such as [GitLab](https://about.gitlab.com/) or the community-centered nonprofit [Codeberg](https://codeberg.org/).\n",
        "\n",
        "In this lesson, you will learn how to connect a local Git repository to GitHub, clone an existing repository to work locally, and fork repositories to contribute to open-source projects or collaborate with others. If you don't have a GitHub account yet you can [sign up for free](https://github.com/signup), fill in the required details and verify your email and complete the account setup.\n",
        "\n"
      ],
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Pushing a Local Repository to GitHub\n",
        "\n",
        "### Background\n",
        "\n",
        "To push your local repository to GitHub, you can create a new empty repository on GitHub and add it as a remote. A remote is simply a URL that points to an online repository that Git can track. We can give the remote any name but typically it is called `origin` because it is the \"source of truth\" that reflects the current state of the project where others copy from. To push to the registered remote we have to set it as upstream to mark it as a target to push to. Setting the upstream requires two inputs the remote repository (i.e. `origin`) and the branch we want to push. If you haven't created any branches there is only a single one and it is called either `main` (newer name) or `master` (older name).\n",
        "Once the upstream is registered we can use `git push` to push local changes to the remote repository. You can also register the upstream and push in a single command\n",
        "\n",
        "### Exercises\n",
        "\n",
        "In the following exercises you are going to create a new repository on GitHub, add it as a remote to you local repository and push it to the remote. You can use any existing Git repository on your machine or create one from scratch (you'll need at least one file so there is something to push). Here are the commands you'll need to know:\n",
        "\n",
        "| Code                           | Description                                              | VS Code GUI |\n",
        "|-----------------------------------|----------------------------------------------------------|-------------|\n",
        "| `git remote add origin <URL>`     | Link the local repository to a remote GitHub repository | Click **Source Control (Ctrl + Shift + G)** \u2192 Click **Publish Repository** |\n",
        "| `git push -u origin main`         | Push local commits to the remote repository and set upstream | Click **Source Control** \u2192 Click **...** \u2192 Click **Push** |\n",
        "| `git push`         | Push local commits to the remote repository (once upstream is set) | Click **Source Control** \u2192 Click **...** \u2192 Click **Push** |\n"
      ],
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "**Exercise**: Move to an existing local Git repository or create one."
      ],
      "metadata": {}
    },
    {
      "cell_type": "code",
      "source": [
        "# in a new empty folder:\n",
        "git init\n",
        "# create a new file\n",
        "git add .\n",
        "git commit -m \"Initial commit\""
      ],
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "/tmp/new_repo\n",
            "\u001b[33mhint: Using 'master' as the name for the initial branch. This default branch name\u001b[m\r\n",
            "\u001b[33mhint: is subject to change. To configure the initial branch name to use in all\u001b[m\r\n",
            "\u001b[33mhint: of your new repositories, which will suppress this warning, call:\u001b[m\r\n",
            "\u001b[33mhint: \u001b[m\r\n",
            "\u001b[33mhint: \tgit config --global init.defaultBranch <name>\u001b[m\r\n",
            "\u001b[33mhint: \u001b[m\r\n",
            "\u001b[33mhint: Names commonly chosen instead of 'master' are 'main', 'trunk' and\u001b[m\r\n",
            "\u001b[33mhint: 'development'. The just-created branch can be renamed via this command:\u001b[m\r\n",
            "\u001b[33mhint: \u001b[m\r\n",
            "\u001b[33mhint: \tgit branch -m <name>\u001b[m\r\n",
            "Initialized empty Git repository in /tmp/new_repo/.git/\r\n",
            "[master (root-commit) ee88f62] initial commit\r\n",
            " 1 file changed, 1 insertion(+)\r\n",
            " create mode 100644 hello.txt\r\n"
          ]
        }
      ],
      "execution_count": null,
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "**Exercise**: Create a new **public** repository on GitHub (**without** initializing it with README. It should be **completely** empty) and copy the clone URL. \n",
        "\n",
        "![](img/gh5.png)\n"
      ],
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "\n",
        "![](img/gh6.png)"
      ],
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "**Exercise**: In your local repository, add the remote URL using `git remote add origin <repo-url>`."
      ],
      "metadata": {}
    },
    {
      "cell_type": "code",
      "source": [
        "git remote add origin https://github.com/OleBialas/test-repo.git"
      ],
      "outputs": [],
      "execution_count": null,
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "**Exercise**: Push the local repository to GitHub using `git push -u origin main` or `git push -u origin master` and authenticate yourself when you are prompted."
      ],
      "metadata": {}
    },
    {
      "cell_type": "code",
      "source": [
        "git push -u origin main # or master"
      ],
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\n",
            "Username for 'https://github.com': OleBialas\n",
            "Password for 'https://OleBialas@github.com':\n",
            "Enumerating objects: 3, done.\n",
            "Counting objects: 100% (3/3), done.\n",
            "Writing objects: 100% (3/3), 218 bytes | 218.00 KiB/s, done.\n",
            "Total 3 (delta 0), reused 0 (delta 0), pack-reused 0\n",
            "To https://github.com/OleBialas/test-repo.git\n",
            " * [new branch]      master -> master\n",
            "branch 'master' set up to track 'origin/master'.\n",
            "\n"
          ]
        }
      ],
      "execution_count": null,
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "**Exercise**: Verify that the repository's content is now visible on GitHub.  "
      ],
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "![](img/gh7.png)"
      ],
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "**Exercise**: Add a new text file with some content and commit the changes to the repository. Then, `git push` the changes to the remote and check the GitHub repository in the browser to verify the file was transferred."
      ],
      "metadata": {}
    },
    {
      "cell_type": "code",
      "source": [
        "# after adding a new file:\n",
        "git add .\n",
        "git commit -m \"add new file\"\n",
        "git push"
      ],
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\n",
            "[master f21b091] add new file\n",
            " 1 file changed, 1 insertion(+)\n",
            " create mode 100644 hello2.txt\n",
            "Enumerating objects: 4, done.\n",
            "Counting objects: 100% (4/4), done.\n",
            "Delta compression using up to 20 threads\n",
            "Compressing objects: 100% (2/2), done.\n",
            "Writing objects: 100% (3/3), 275 bytes | 275.00 KiB/s, done.\n",
            "Total 3 (delta 0), reused 0 (delta 0), pack-reused 0\n",
            "To https://github.com/OleBialas/test-repo.git\n",
            "   81cca8f..f21b091  master -> master\n",
            "\n"
          ]
        }
      ],
      "execution_count": null,
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "**Exercise**: Add a new line to the file, commit the changes and `git push` to the remote again. Then, check the GitHub repository in the browser to verify the file was transferred."
      ],
      "metadata": {}
    },
    {
      "cell_type": "code",
      "source": [
        "# after adding a line:\n",
        "git commit -am \"add line\"\n",
        "git push"
      ],
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\n",
            "[master 35d40d7] add line\n",
            " 1 file changed, 1 insertion(+)\n",
            "Enumerating objects: 5, done.\n",
            "Counting objects: 100% (5/5), done.\n",
            "Delta compression using up to 20 threads\n",
            "Compressing objects: 100% (2/2), done.\n",
            "Writing objects: 100% (3/3), 276 bytes | 276.00 KiB/s, done.\n",
            "Total 3 (delta 0), reused 0 (delta 0), pack-reused 0\n",
            "To https://github.com/OleBialas/test-repo.git\n",
            "   f21b091..5c98649  master -> master \n",
            "    \n"
          ]
        }
      ],
      "execution_count": null,
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Cloning a GitHub Repository to a Local Machine  \n",
        "\n",
        "### Background\n",
        "\n",
        "A repository on GitHub can be cloned, which means that all of its content, including the full commit history, will be cloned to your local machine. Because the repository will automatically be aware of it's origin, you can `git pull` to receive updates. Note that you can clone and pull from any public repository from GitHub but you can only `git push` if you own the repository.\n",
        "\n",
        "### Exercises\n",
        "\n",
        "In the follwing exercises, you are going to clone repositories from GitHub and use `git pull` to receive updates after the repository changes. Here are the commands you need to know:\n",
        "\n",
        "| Code                           | Description                                    | VS Code GUI |\n",
        "|-----------------------------------|------------------------------------------------|-------------|\n",
        "| `git clone <repo-url>`           | Clone a GitHub repository to a local machine  | Click **Source Control (Ctrl + Shift + G)** \u2192 Click **Clone Repository** |\n",
        "| `git pull`           | Pull the latest changes from GitHub           | Click **Source Control** \u2192 Click **...** \u2192 Click **Pull** |\n",
        "| `git pull origin main`           | Pull and explicitly list the branches           | Click **Source Control** \u2192 Click **...** \u2192 Click **Pull** |\n"
      ],
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "**Exercise**: In VSCode open a new window that is NOT a git repository and clone the repository from this URL: https://github.com/ibehave-ibots/iBOTS-Collaboration.git"
      ],
      "metadata": {}
    },
    {
      "cell_type": "code",
      "source": [
        "git clone"
      ],
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\n",
            "Cloning into 'iBOTS-Collaboration'...\n",
            "remote: Enumerating objects: 6, done.\n",
            "remote: Counting objects: 100% (6/6), done.\n",
            "remote: Compressing objects: 100% (3/3), done.\n",
            "remote: Total 6 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)\n",
            "Receiving objects: 100% (6/6), done.\n",
            "\n"
          ]
        }
      ],
      "execution_count": null,
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "**Exercise**: Open the cloned folder in VSCode and inspect its contents."
      ],
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "The folder should look like this:\n",
        "\n",
        "![](img/vscode1.png)"
      ],
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "**Exercise**: Create a **new public repository on GitHub**, **this time initializing it with a README** and note the URL.\n",
        "\n",
        "![](img/gh12.png)"
      ],
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "In the example above, the URL would be `https://github.com/OleBialas/miniature-octo-waddle.git`\n"
      ],
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "**Exercise**: Clone the new repository, then open the cloned folder in VS Code and check that the README file exists.  "
      ],
      "metadata": {}
    },
    {
      "cell_type": "code",
      "source": [
        "git clone https://github.com/OleBialas/miniature-octo-waddle.git"
      ],
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\n",
            "Cloning into 'miniature-octo-waddle'...\n",
            "remote: Enumerating objects: 3, done.\n",
            "remote: Counting objects: 100% (3/3), done.\n",
            "remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)\n",
            "Receiving objects: 100% (3/3), done.\n",
            "\n"
          ]
        }
      ],
      "execution_count": null,
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "**Exercise**: Make a change directly on GitHub (edit the README file and commit).\n",
        "\n",
        "![](img/gh13.png)"
      ],
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "The change (e.g. \"Hello there\") should be visible in the README right away:\n",
        "\n",
        "![](img/gh14.png)"
      ],
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "**Exercise**: Pull from origin and inspect the folder in VSCode to verify the changes were copied."
      ],
      "metadata": {}
    },
    {
      "cell_type": "code",
      "source": [
        "git pull"
      ],
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\n",
            "remote: Enumerating objects: 5, done.\n",
            "remote: Counting objects: 100% (5/5), done.\n",
            "remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)\n",
            "Unpacking objects: 100% (3/3), 931 bytes | 931.00 KiB/s, done.\n",
            "From https://github.com/OleBialas/miniature-octo-waddle\n",
            "   a39c4b2..519f573  main       -> origin/main\n",
            "Updating a39c4b2..519f573\n",
            "Fast-forward\n",
            "README.md | 4 \u001b[32m+++\u001b[0m\u001b[31m-\u001b[0m\n",
            " 1 file changed, 3 insertions(+), 1 deletion(-)\n",
            "\n"
          ]
        }
      ],
      "execution_count": null,
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Forking and Creating Merge Requests\n",
        "\n",
        "### Background\n",
        "\n",
        "Instead of cloning a repository you can also fork it. A fork is a copy of the original repository on GitHub that you own and can make changes to.\n",
        "After you made changes (e.g. adding a new feature or fixing a bug), you can als ask the owner of the original repository to incorporate your changes.\n",
        "This is called a pull request or merge request and it is the standard mechanism for contributing to open-source projects.\n",
        "The owner of the original repository can review the merge request, comment on it and, reject or accept it.\n",
        "\n",
        "### Exercises\n",
        "\n",
        "In the following exercises you will fork a repository, modify your fork, and then create a merge request for the original repository. Here are the commands you need to know:\n",
        "\n",
        "| Code                                      | Description                                                  | VS Code GUI |\n",
        "|----------------------------------------------|--------------------------------------------------------------|-------------|\n",
        "| **(GitHub UI)**                              | Fork a repository on GitHub                                  | Click **Fork** on the GitHub repository page |\n",
        "| `git clone <your-fork-url>`                  | Clone your forked repository locally                        | Click **Source Control (Ctrl + Shift + G)** \u2192 Click **Clone Repository** |\n",
        "| `git remote add upstream <original-repo-url>` | Link the original repository as an upstream remote          | NA |\n",
        "| `git push origin main`                        | Push the merged changes to your forked repository on GitHub | Click **Source Control** \u2192 Click **...** \u2192 Click **Push** |"
      ],
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "\n",
        "**Exercise**: On GitHub, fork the repository from this URL: https://github.com/ibehave-ibots/iBOTS-Collaboration.git\n",
        "\n",
        "![](img/gh9.png)"
      ],
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "You should now see the forked repository under your own account:\n",
        "\n",
        "![](img/gh10.png)"
      ],
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "**Exercise**: Clone your own fork"
      ],
      "metadata": {}
    },
    {
      "cell_type": "code",
      "source": [
        "git clone https://github.com/OleBialas/iBOTS-Collaboration.git"
      ],
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\n",
            "Cloning into 'iBOTS-Collaboration'...\n",
            "remote: Enumerating objects: 10, done.\n",
            "remote: Counting objects: 100% (10/10), done.\n",
            "remote: Compressing objects: 100% (5/5), done.\n",
            "remote: Total 10 (delta 0), reused 4 (delta 0), pack-reused 0 (from 0)\n",
            "Receiving objects: 100% (10/10), done.\n",
            "\n"
          ]
        }
      ],
      "execution_count": null,
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "**Exercise**: Add yourself to the participants/ folder by adding a text file (e.g. jim.txt) with a little message (make sure the file name is unique). Then, commit the new file."
      ],
      "metadata": {}
    },
    {
      "cell_type": "code",
      "source": [
        "# after adding file, e.g. participants/jim.txt:\n",
        "git add .\n",
        "git commit -m \"add new collaborator\""
      ],
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\n",
            "[main e8a3d66] add new collaborator\n",
            " 1 file changed, 1 insertion(+)\n",
            " create mode 100644 participants/jim.txt\n",
            " \n"
          ]
        }
      ],
      "execution_count": null,
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "**Exercise**: Push the changes to your fork"
      ],
      "metadata": {}
    },
    {
      "cell_type": "code",
      "source": [
        "git push"
      ],
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\n",
            "Enumerating objects: 6, done.\n",
            "Counting objects: 100% (6/6), done.\n",
            "Delta compression using up to 20 threads\n",
            "Compressing objects: 100% (3/3), done.\n",
            "Writing objects: 100% (4/4), 365 bytes | 365.00 KiB/s, done.\n",
            "Total 4 (delta 0), reused 0 (delta 0), pack-reused 0\n",
            "To https://github.com/OleBialas/iBOTS-Collaboration.git\n",
            "   5afcc73..e8a3d66  main -> main\n",
            "\n"
          ]
        }
      ],
      "execution_count": null,
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "**Exercise**: Go to GitHub to create a pull request (it may take a bit until it is merged).\n",
        "\n",
        "![](img/gh8.png)"
      ],
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "You should now see your pull request on the original repository:\n",
        "\n",
        "![](img/gh10.png)"
      ],
      "metadata": {}
    },
    {
      "cell_type": "markdown",
      "source": [
        "**Bonus Exercise**: Choose a partner. You each create a new public repository with a README that contains your name. Then, you fork each others repositories, add your name to the README, commit the changes and create a pull request.\n",
        "Finally, you accept each others pull request and verify that the change was added to your original repository."
      ],
      "metadata": {}
    }
  ]
}