有没有办法从 git 只下载一个子目录?

Posted

技术标签:

【中文标题】有没有办法从 git 只下载一个子目录?【英文标题】:Is there a way to download only a subdirectory from git? 【发布时间】:2012-10-25 16:46:28 【问题描述】:

有没有办法从 git 存储库只下载给定的子目录?假设我只想从 https://github.com/djdeath/toys.git 获取 nyancat 目录。

我可以克隆整个存储库并忽略我不想要的文件,或者转到https://github.com/djdeath/toys/tree/master/nyancat并一一下载相关文件。我认为一定有更简单的方法。

注意我不是在问是否可以克隆目录,这是asked before,显然是不可能的。我只是对快速获取文件感兴趣,不需要重新提交或再次对它们使用 git。

【问题讨论】:

缺乏这种能力是git最糟糕的地方。 【参考方案1】:

git-archive 命令几乎可以满足您的需求,但它需要在已经克隆的 repo 上运行,因此如果您可以通过 SSH 访问主机,您可以这样做:

cd /path/to/destination
ssh user@host "cd /path/to/repo && git archive HEAD dir/you/want" | tar xf -

或者,对网络传输进行压缩:

cd /path/to/destination
ssh user@host "cd /path/to/repo && git archive HEAD dir/you/want | gzip" | tar xzf -

【讨论】:

【参考方案2】:

嘿,我只是wrote a script

用法

      python get_git_sub_dir.py path/to/sub/dir <RECURSIVE>

【讨论】:

【参考方案3】:

一个完整的参数化 bash 函数(不依赖)

#!/bin/bash

gitsub() 

  usage() 
        cat <<- EOF
        ------------------------------------------------------------------------
        GNU gitsub 0.0.1, a non-interactive github filtered subrepo retriever.
        Usage: gitsub [-h] [[-d[dir] -s[strip] -e[ext]] -o owner -r repo -b sub]
        ------------------------------------------------------------------------
        Mandatory arguments to long options are mandatory for short options too.
        ------------------------------------------------------------------------
        MANDATORY:
          -o, --owner           repo's owner
          -r, --repo            repo's name
          -b, --subrepo         directory(s) to be cloned
        OPTIONS:
          -s, --strip           number of dirs (/) to be skipped, default 0
          -d, --dir             output directory default current directory
          -e, --extension       filter by ext, if missing clone all (including subdirs)
        COMMANDS:
          -h, --help            display this help and exit
        ------------------------------------------------------------------------
        Mail bug reports and suggestions to makramjandar@gmail.com
        ------------------------------------------------------------------------
        EOF
  

  error()  echo -e "\033[1;31mError: $1\033[0m" ;

  # check supplied args
  is_arg()  
    [[ -n "$2" && $2:0:1 != "-" ]] \
    ||  error "Argument for $1 is missing..." >&2 \
    && usage \
    && exit 1 ;
  

  POSITIONAL=()
  while (( "$#" )); do
    case "$1" in
      # commands
      -h|--help)      usage && exit 0                                    ;;
      # mandatory flags with arguments
      -o|--owner)     is_arg $1 $2 && OWNER=$2                 ; shift 2 ;;
      -r|--repo)      is_arg $1 $2 && REPO=$2                  ; shift 2 ;;
      -b|--subrepo)   is_arg $1 $2 && SUBREPO=$2               ; shift 2 ;;
      # optional flags with arguments
      -d|--dir)       is_arg $1 $2 && DIR=$2 && mkdir -p $DIR  ; shift 2 ;;
      -s|--strip)     is_arg $1 $2 && STRIP=$2                 ; shift 2 ;;
      -e|--extension) is_arg $1 $2 && EXTENSION=$2             ; shift 2 ;;
      # unsupported flags 
      -*|--*=) error "Unsupported flag $1" >&2 && usage        ; exit 1  ;;
      # preserve positional arguments
      *) POSITIONAL+=("$1")                                    ; shift   ;;
    esac
  done
  # set positional arguments in their proper place
  set -- "$POSITIONAL[@]"

  # check mandatory arguments
  [[ -z "$OWNER" || -z "$REPO" || -z "$SUBREPO" ]] \
  &&  error "Missing mandatory arguments..." >&2 \
  && usage \
  && exit 1 ;

  # get github filtered (optional) subrepository
  
    curl -L "https://api.github.com/repos/$OWNER/$REPO/tarball" \
    | 
      tar \
      --verbose \
      --extract \
      --gzip \
      --directory=$DIR:-$PWD \
      --strip=$STRIP:-0 \
      --wildcards */$SUBREPO/*.$EXTENSION*
   2>/dev/null \
    && echo "Done" \
    || \
   
    error "Invalid args..." \
    && usage \
    && exit 1
  


gitsub "$@"

对于给定的仓库:https://github.com/jenskutilek/free-fonts

下载子文件夹 Fira 的全部内容,包括目录和文件

$ bash gitsub.sh -o "jenskutilek" -r "free-fonts" -b "Fira" -d "FiraUnfiltered" -s 2

$ tree -d FiraUnfiltered/
FiraUnfiltered/
├── Fira Mono
│   ├── OTF
│   ├── TTF
│   ├── VFB
│   └── WOFF
└── Fira Sans
    ├── OTF
    ├── TTF
    ├── VFB
    └── WOFF

下载相同的子文件夹,但使用字体 TTF 过滤

$ bash gitsub.sh -o "jenskutilek" -r "free-fonts" -b "Fira" -d "FiraFiltered" -s 2 -e "ttf"

$ tree -d FiraFiltered/
FiraFiltered/
├── Fira Mono
│   └── TTF
└── Fira Sans
    └── TTF

通过将 -s|--strip 设置为 4,仅将过滤后的文件下载到 outdir

bash gitsub.sh -o "jenskutilek" -r "free-fonts" -b "Fira" -d "ttfFilesOnly" -s 4 -e "ttf"

$ tree ttfFilesOnly/
ttfFilesOnly/
├── FiraMono-Bold.ttf
├── FiraMono-Regular.ttf
├── FiraSans-Bold.ttf
├── FiraSans-BoldItalic.ttf
├── FiraSans-Light.ttf
├── FiraSans-LightItalic.ttf
├── FiraSans-Medium.ttf
├── FiraSans-MediumItalic.ttf
├── FiraSans-Regular.ttf
└── FiraSans-RegularItalic.ttf

【讨论】:

你应该稍微解释一下你的脚本。 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center。 我的函数提供了嵌入式帮助...我应该打印它还是必须为帮助本身重写第二个帮助!有点一致性,请先生 @Ale 我的意思是编辑答案,而不是添加评论添加答案的详细信息。

以上是关于有没有办法从 git 只下载一个子目录?的主要内容,如果未能解决你的问题,请参考以下文章

git选择源代码版本

在 Windows 7 Git Bash 中,有没有办法探索当前位置的目录?

有没有办法在一个命令中获取 git 根目录?

如何从 git grep 搜索中排除某些目录/文件

使用git-gui克隆远程代码出现目录地址已存在的问题(解决办法)

从远程 git 存储库获取单个文件