Skip to content

Instantly share code, notes, and snippets.

Revisions

  1. @0xkhan 0xkhan revised this gist Sep 22, 2022. 2 changed files with 155 additions and 1 deletion.
    1 change: 0 additions & 1 deletion git-submodules.md
    Original file line number Diff line number Diff line change
    @@ -1 +0,0 @@
    # Git Submodules
    155 changes: 155 additions & 0 deletions push-only-dist-folder-to-liver-server.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,155 @@
    # Push Only `dist/` Folder To Live Server

    I have googled many things and explored many questions on Stack Overflow
    to find the best way to push only `dist/` directory to live server. I
    couldn't find any good solution but one person on Stackoverflow suggested to
    look at Git Submodules and this is the best solution I could come up with. I
    have never heard of submodules before because almost nobody uses them. If you
    never heard of it too then I'll first explain what a submodule is and then I'll
    show you how you can use submodules to push only `dist/` directory to
    a live server.

    ### What is a Submodule?
    A submodule is a repository inside another repository. Basically a project
    within a project. For example we have a set of dependencies that we need for more
    than one project. We can put all those dependencies in a repo and add that repo
    as a submodule in each project. So we bring that repo into our project repo,
    it lives there and we have access to the whole repository.

    ### Why and when would you use it?
    The best example for when you should use submodules is sharing libraries.
    Other example might be when you have a repository and some files are used across
    multiple technologies what you can do is to add it as a submodule across all
    technologies that way every technology will have it available.

    ### So how do you add a submodule?
    Let's suppose we have two repos `MyRepo` and `MySubRepo`. `MyRepo` is our
    working repo, our project and `MySubRepo` is our submodule. Both are separate
    independent repositories. Now to add a submodule into your working repository
    Git has a command for it:
    ```shell
    git submodule add <url>
    ```
    In our case we wanna go inside `MyRepo/` and run the following command:
    ```shell
    /MyRepo$ git submodule add https://github.com/<username>/MySubRepo
    ```
    Now `MySubRepo` is added as a submodule to our working repo `MyRepo`. If
    `MyRepo` had only `README.md` file it will now have `MySubRepo` as well:
    ```shell
    /MyRepo$ ls
    README.md .gitmodules MySubRepo
    ```
    The `.gitmodules` is the file that keeps track of submodules. Next we wanna
    add the new added files and push them to our remote respository.

    ```shell
    /MyRepo$ git status
    new file: .gitmodules
    new file: MySubRepo

    /MyRepo$ git add .
    /MyRepo$ git commit -m "Add submodule"
    /MyRepo$ git push
    ```
    The life cycle of submodules works differently from our standard repository. By
    default when we use git commands it will ignore all submodules unless we
    explicitly tell it. So basically if you do `git clone` it will ignore submodules
    also if you do `git push` or `git branch` it will also by default ignore
    submodules.

    To explicitly tell it to focus on submodule we can use `--recurse-submodules`
    flag e.g:
    ```
    git pull --recurse-submodules
    # For cloning a repo
    git clone <url> --recurse-submodules
    ```
    If you forgot to use the `--recurse-submodules` flag you can alternatively
    use the following command after the repository is cloned:
    ```
    git submodule update --init
    ```
    If we go inside `MySubRepo` you will see that it's on a different branch and
    that's because we are in a different repository. You can manually checkout to
    master branch by running `git checkout master`.

    ### How it works with changes
    If we make changes to `MySubRepo/README.md` file and push the changes it
    will update `MySubRepo` repository but when we go back to `MyRepo` we can see
    that the branch is dirty that means there are changes. It will look like
    following:
    ```shell
    /MyRepo$ git status

    On branch master
    Your branch is up to date with 'origin/master'.

    Changes not staged for commit:
    (use "git add <file>..." to update what will be committed)
    (use "git restore <file>..." to discard changes in working directory)
    modified: MySubRepo (new commits)

    no changes added to commit (use "git add" and/or "git commit -a")
    ```
    As it shows above the main repo is up to date but there were changes in our
    submodule that needs to be committed. Those changes are not actually changes in
    our main repo but it's the last commit hash inside our submodule. What that
    means is that the submodule is updated to a newer version and that specific
    commit has to be realised and committed inside our main repo. When we do that
    our submodule will point to the last commit.
    To update those changes in our working repo we do the following:
    ```shell
    /MyRepo$ git add .
    /MyRepo$ git commit -m "Update submodule version"
    /MyRepo$ git push
    ```
    Now those changes are also committed and both repos are up to date.

    ### How to use submodules to only deploy your `dist/` directory to live server

    > :warning: Disclaimer! This is how I use submodules to deploy only `dist/`
    directory to live server. Other developer might use other methods e.g
    distribution branch etc.

    #### I use the following steps
    * Create a working repo which is the main project repo
    * Add your distribution folder as submodule. I name my submodule as `<project name>-dist`
    * Create your build. The build process has to be done carefully I use `npm` and
    `Webpack` so the auto-generated `dist/` directory is always there. Do NOT
    use your `dist/` directory or your submodule as distribution output in
    webpack because each time you make a build it'll wipe everything out
    inculding git files. Git files gone means your directory is not a
    repository anymore, therefore not a submodule.
    * Commit and push the changes in submodule
    * Go back to your main repo and commit the hash

    #### How do I make a build?
    My way of making a build is that I run `npm run build` and it takes care of
    everything. My build command first bundles everything and then copy the files
    from `dist/` directory to `<project name>-dist/` directory. This way only
    the changes are detected in submodule those changes can then be committed and pushed.

    Build command in my `package.json`:
    ```
    "scripts": {
    "devServer": "webpack serve",
    "watch": "webpack -w",
    "bundle": "webpack",
    "copy": "cp -r dist/* <project name>-dist/",
    "start": "npm-run-all --parallel devServer watch",
    "build": "npm-run-all bundle copy"
    }
    ```

    `npm-run-all` is a npm package that helps you run multiple commands when you do `npm
    run <your command>`.
    Of course you wanna ignore your `dist/` folder as you ignore `node_modules` etc.
    You only push `src/` in main Repo and your distribution is added as submodule
    so it's an independent repo which is only used for deployment.

    To see how it looks check [this repo](https://github.com/0xkhan/encite-website) out. It's just a static website which is deployed from a submodule. You'll not be able to see the submodule because it's a private repo. Yes, you can use a private repo as submodule.

    I hope the information is presented clearly. If you have any questions or
    suggestions then comment them below!
  2. @0xkhan 0xkhan created this gist Sep 18, 2022.
    1 change: 1 addition & 0 deletions git-submodules.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    # Git Submodules