VisionSystemsInc / VisionSystemsInc/vsi_common

Sparse Checkout support for a submodule

Open
#503 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

feature
Dominant language
Shell
Stars
8
Forks
9
Avg merge
36m
Merged PRs (30d)
1

Description

Plugin idea for supporting sparse checkout

Here are some Just targets to consider:

In just sync

    if [ "$(git config submodule.external/data.update)" = "none" ]; then
      echo 'Initializing data'
      justify data init
    fi

Init

Note: Docs say sparse-checkout init is deprecated, so probably should be matching that behavior instead.

    data_init) # git sparse-checkout init for external/data
      local git_version=${git_version-$(git_version)}
      local sm_name=external/data
      local sm_path="$(git config -f .gitmodules "submodule.${sm_name}.path")"

      ### 1. First clone --no-checkout ###
      if version_lt "${git_version}" 1.8.4; then
        # Port of git's submodule update's clone.
        local git_dir="$("${GIT}" rev-parse --git-dir)/modules/${sm_path}"

        "${GIT}" submodule init "${sm_path}"
        mkdir -p "$(dirname "${git_dir}")"
        "${GIT}" clone --no-checkout \
          --separate-git-dir "${git_dir}" \
          "$("${GIT}" config "submodule.${sm_name}.url")" \
          "${sm_path}"
      else
        # A close equivalent of clone no checkout
        "${GIT}" -c "submodule.${sm_name}.update="'!true' submodule update --init external/data
      fi

      ### 2. git sparse-checkout init ###
      pushd "${sm_path}" &> /dev/null
        if version_lt "${git_version}" 2.25.0; then
          "${GIT}" config core.sparseCheckout true
        else # 2.25.0
          "${GIT}" sparse-checkout init --cone
        fi
        justify data set prod .gitlab
      popd &> /dev/null

      ### 3. Now, return normal control over to git submodule
      "${GIT}" config "submodule.${sm_name}.update" checkout
      "${GIT}" submodule update "${sm_path}"
      pushd "${sm_path}" &> /dev/null
        # I'm ok with always doing read-tree here, as I am init-ing and this
        # directory should would have not existed before "data init" started

        # This is needed for corner cases even in git 2.25 like when someone deinit's a sparse submodule
        # which results in a no-checkout scenario where every file is stages as deleted, and we need to
        # read-tree, and not prompt the user, so don't call "just data read-tree"
        "${GIT}" read-tree -mu HEAD
      popd &> /dev/null
      ;;

Add

    data_add) # git sparse-checkout add for external/data
      local git_version=${git_version-$(git_version)}
      pushd "${DATA_DIR}" &> /dev/null
        if version_lt "${git_version}" 2.26.0; then
          echo "Approximation of 'git sparse-checkout add', update to git 2.26.0 or newer for more reliable results" >&2
          local add_dir
          local sparse_file="$("${GIT}" rev-parse --git-dir)/info/sparse-checkout"
          for add_dir in ${@+"${@}"}; do
            # The entry should look like /foo/bar/, starting and ending with a /
            if [ "${add_dir:0:1}" != "/" ]; then
              add_dir="/${add_dir}"
            fi
            if [ "${add_dir:${#add_dir}-1:1}" != "/" ]; then
              add_dir="${add_dir}/"
            fi
            # Just blindly add it, no cone check. TODO: Cone?
            echo "${add_dir}" >> "${sparse_file}"
          done
          justify data read-tree
        else
          "${GIT}" sparse-checkout add ${@+"${@}"}
        fi
      popd &> /dev/null
      extra_args=${#}
      ;;

List

    data_list) # git sparse-checkout list for external/data
      local git_version=${git_version-$(git_version)}
      pushd "${DATA_DIR}" &> /dev/null
        if version_lt "${git_version}" 2.25.0; then
          echo "Approximation of 'git sparse-checkout list', update to git 2.25.0 or newer for more reliable results" >&2
          sed -En 's|^/(.*)/|\1|p'  ../../.git/modules/external/data/info/sparse-checkout
        else
          "${GIT}" sparse-checkout list
        fi
      popd &> /dev/null
      ;;

Disable

    data_disable) # git sparse-checkout disable for external/data
      local git_version=${git_version-$(git_version)}
      pushd "$DATA_DIR}" &> /dev/null
        if version_lt "${git_version}" 2.25.0; then
          echo "Approximation of 'git sparse-checkout disable', update to git 2.25.0 or newer for more reliable results" >&2
          "${GIT}" config core.sparseCheckout false
          "${GIT}" read-tree -mu HEAD
        else
          "${GIT}" sparse-checkout disable
        fi
      popd &> /dev/null
      ;;

Set

    data_set) # git sparse-checkout set for external/data
      local git_version=${git_version-$(git_version)}
      pushd "${DATA_DIR}" &> /dev/null
        if version_lt "${git_version}" 2.25.0; then
          echo '/*
!/*/' > "$("${GIT}" rev-parse --git-dir)/info/sparse-checkout"
          justify data add ${@+"${@}"}
        else
          "${GIT}" sparse-checkout set  ${@+"${@}"}
        fi
      popd &> /dev/null
      extra_args=${#}
      ;;

Other

    data_read-tree) # git read-tree -mu HEAD for external/data
      # Several references refer to read-tree being the way to update the workspace
      # https://vmiklos.hu/blog/sparse-checkout-example-in-git-1-7
      # https://web.archive.org/web/20130121010056/https://blog.quilitz.de/2010/03/checkout-sub-directories-in-git-sparse-checkouts/comment-page-1/
      # https://stackoverflow.com/a/2340860/4166604
      # https://stackoverflow.com/a/50818880/4166604

      # This is more destructive of a command then I thought it was.
      # This will remove any STAGED changes, which is not what I think is the point? I just
      # wanted something like "git checkout" that will update the workspace after the sparse-checkout
      # is updated. I originally thought this was less intrusive.

      # This behavior is also what we want on initial clone. A clone --no-checkout looks like all files
      # are staged as deleted. So reverting that is exactly what we need on data init
      pushd "${DATA_DIR}" &> /dev/null
        if [ -z "$(${GIT} status --untracked-files=no --porcelain 2>/dev/null)" ]; then
          "${GIT}" read-tree -mu HEAD
        else
          echo "external/data is in a dirty state. This command will revert the ${RED}staged changes in external/data!${NC}."
          git status --untracked-files=no
          local ans
          ask_question "Are you sure you want to execute 'git read-tree -mu HEAD' on external/data?" ans y
          if [ "${ans}" = "1" ]; then
            "${GIT}" read-tree -mu HEAD
          else
            echo "To complete sparse checkout, run: ${YELLOW}git read-tree -mu HEAD${NC}"
          fi
        fi
      popd &> /dev/null
      ;;

    data_ls-files) # git ls-files for external/data
      pushd "${DATA_DIR}" &> /dev/null
        "${GIT}" ls-files
      popd &> /dev/null
      ;;

    data_ls-dirs) # Print directory tree for external/data
      pushd "${DATA_DIR}" &> /dev/null
        "${GIT}" ls-files -z | xargs -0 dirname | sort -u
      popd &> /dev/null
      ;;

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by locating the shell command dispatcher and the existing data_* entry points referenced in the issue, then review how submodules and Git version checks are handled. Done should provide the proposed sparse-checkout operations for external/data, including init, add, list, disable, set, read-tree, and file or directory listing behavior across the cited Git versions.

Written by the indexing model from the issue text.

Assessment

Tech stack
git, shell
Domain
cli
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.