├── .gitignore ├── tests ├── git-get │ ├── no-x-tag.test │ ├── file-stdout.test │ ├── no-git-x.test │ ├── dir-stdout.test │ ├── no-git-tag.test │ ├── file-sub.test │ ├── github-bare-blob.test │ ├── perm.test │ ├── sha1.test │ ├── sha1-atag.test │ ├── file.test │ ├── github-blob-fail2.test │ ├── github-blob.test │ ├── github-tree-dir-fail2.test │ ├── github-blob-fail.test │ ├── github-blob-fail3.test │ ├── github-tree-dir-fail.test │ ├── github-tree-dir-fail3.test │ ├── url.test │ ├── github-tree-fail.test │ ├── gist-file.test │ ├── dir.test │ ├── link.test │ ├── github-blob-dir.test │ ├── github-blob-ref.test │ ├── github-commit-path.test │ ├── dir-sub.test │ ├── github-tree-dir.test │ ├── dir-force.test │ ├── file-in-dir-fail.test │ ├── github-blob-perm.test │ ├── github-tree-path.test │ ├── file-in-dir-fail-f.test │ ├── file-in-dir-fail-rf.test │ ├── file-stdout-tag.test │ ├── file-in-dir.test │ ├── dir-stdout-tag.test │ ├── dir-force-force.test │ ├── file-tag.test │ ├── dir-fail.test │ ├── file-force.test │ ├── dir-fail-f.test │ ├── file-tag-file.test │ ├── file-force-fail.test │ ├── whole-output.test │ ├── dir-tag.test │ ├── dir-tag-file.test │ ├── whole-sub.test │ ├── file-sub-tag-file.test │ ├── whole.test │ ├── file-force-tag-coal.test │ ├── dir-sub-tag.test │ ├── gist-whole.test │ ├── whole-sub-tag.test │ ├── git-output.test │ ├── github-bare-tree.test │ ├── github-tree.test │ ├── github-commit.test │ ├── git.test │ ├── git-tag.test │ ├── git-tag-x-B.test │ ├── git-tag-x.test │ ├── git-tag-x-T.test │ ├── git-x-T.test │ ├── git-x.test │ └── git-x-B.test └── git-gets │ ├── no-git-tag.test │ ├── no-git-x.test │ ├── no-x-tag.test │ ├── github-tree-fail.test │ ├── github-blob-fail.test │ ├── sm-dirty-fail.test │ ├── sm-extra-fail.test │ ├── simple.test │ ├── github-tree.test │ ├── simple-confirm.test │ ├── simple-tag.test │ ├── simple-tag-file.test │ ├── simple-no-recursive.test │ ├── sm-g-no-recursive.test │ ├── sm-g-no-init.test │ ├── g-output.test │ ├── g-output2.test │ ├── g-output3.test │ ├── g.test │ ├── g-sha1.test │ ├── g-parallel.test │ ├── sm-g.test │ ├── sm-g-cwd.test │ ├── sm-g-in.test │ ├── sm-g-gw.test │ ├── x-B.test │ ├── x-T.test │ ├── x.test │ ├── x-parallel.test │ ├── sm.test │ └── sm-x.test ├── Makefile ├── appveyor.yml ├── run-test ├── LICENSE ├── zsh ├── _git-get └── _git-gets ├── release.sh ├── man ├── git-gets.1 └── git-get.1 ├── README.md ├── git-get └── git-gets /.gitignore: -------------------------------------------------------------------------------- 1 | /report/ 2 | /build/ 3 | /coverage/ 4 | -------------------------------------------------------------------------------- /tests/git-get/no-x-tag.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo0 -x --tag || echo good)" 2 | 3 | [ "$R" = "good" ] 4 | -------------------------------------------------------------------------------- /tests/git-gets/no-git-tag.test: -------------------------------------------------------------------------------- 1 | R="$(git-gets b1f6c1c4/git-get example-repo2 -g -t || echo good)" 2 | 3 | [ "$R" = "good" ] 4 | -------------------------------------------------------------------------------- /tests/git-gets/no-git-x.test: -------------------------------------------------------------------------------- 1 | R="$(git-gets b1f6c1c4/git-get example-repo2 -g -x || echo good)" 2 | 3 | [ "$R" = "good" ] 4 | -------------------------------------------------------------------------------- /tests/git-gets/no-x-tag.test: -------------------------------------------------------------------------------- 1 | R="$(git-gets b1f6c1c4/git-get example-repo2 -x -t || echo good)" 2 | 3 | [ "$R" = "good" ] 4 | -------------------------------------------------------------------------------- /tests/git-get/file-stdout.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo2 -o- -- link)" 2 | 3 | [ "$R" = "dir/file-in-dir" ] 4 | -------------------------------------------------------------------------------- /tests/git-get/no-git-x.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo0 --preserve-git -x || echo good)" 2 | 3 | [ "$R" = "good" ] 4 | -------------------------------------------------------------------------------- /tests/git-get/dir-stdout.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo2 -o- -- dir | tar t)" 2 | 3 | [ "$R" = $'dir/\ndir/file-in-dir' ] 4 | -------------------------------------------------------------------------------- /tests/git-get/no-git-tag.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo0 --preserve-git --tag || echo good)" 2 | 3 | [ "$R" = "good" ] 4 | -------------------------------------------------------------------------------- /tests/git-get/file-sub.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo2 -- xsub/sub/file)" 2 | 3 | [ -z "$R" ] 4 | [ -x file ] 5 | 6 | rm file 7 | -------------------------------------------------------------------------------- /tests/git-get/github-bare-blob.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get/blob/example-repo2/file)" 2 | 3 | [ -z "$R" ] 4 | [ -x file ] 5 | 6 | rm file 7 | -------------------------------------------------------------------------------- /tests/git-get/perm.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo2 -- file)" 2 | 3 | [ -z "$R" ] 4 | [ -f file ] 5 | [ -x file ] 6 | 7 | rm file 8 | -------------------------------------------------------------------------------- /tests/git-get/sha1.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get bff5 -- dir/file-in-dir)" 2 | 3 | [ -z "$R" ] 4 | [ -f file-in-dir ] 5 | 6 | rm file-in-dir 7 | -------------------------------------------------------------------------------- /tests/git-gets/github-tree-fail.test: -------------------------------------------------------------------------------- 1 | R="$(git-gets https://github.com/b1f6c1c4/git-get/tree/example-repo2/dir || echo good)" 2 | 3 | [ "$R" = good ] 4 | -------------------------------------------------------------------------------- /tests/git-get/sha1-atag.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get f774 -- dir/file-in-dir)" 2 | 3 | [ -z "$R" ] 4 | [ -f file-in-dir ] 5 | 6 | rm file-in-dir 7 | -------------------------------------------------------------------------------- /tests/git-get/file.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo2 -- dir/file-in-dir)" 2 | 3 | [ -z "$R" ] 4 | [ -f file-in-dir ] 5 | 6 | rm file-in-dir 7 | -------------------------------------------------------------------------------- /tests/git-get/github-blob-fail2.test: -------------------------------------------------------------------------------- 1 | R="$(git-get https://github.com/b1f6c1c4/git-get/blob/example-repo2/file -- file || echo good)" 2 | 3 | [ "$R" = good ] 4 | -------------------------------------------------------------------------------- /tests/git-get/github-blob.test: -------------------------------------------------------------------------------- 1 | R="$(git-get https://github.com/b1f6c1c4/git-get/blob/example-repo2/file)" 2 | 3 | [ -z "$R" ] 4 | [ -x file ] 5 | 6 | rm file 7 | -------------------------------------------------------------------------------- /tests/git-get/github-tree-dir-fail2.test: -------------------------------------------------------------------------------- 1 | R="$(git-get https://github.com/b1f6c1c4/git-get/tree/example-repo2/dir -- dir || echo good)" 2 | 3 | [ "$R" = good ] 4 | -------------------------------------------------------------------------------- /tests/git-get/github-blob-fail.test: -------------------------------------------------------------------------------- 1 | R="$(git-get https://github.com/b1f6c1c4/git-get/blob/example-repo2/file example-repo0 || echo good)" 2 | 3 | [ "$R" = good ] 4 | -------------------------------------------------------------------------------- /tests/git-get/github-blob-fail3.test: -------------------------------------------------------------------------------- 1 | R="$(git-get https://github.com/b1f6c1c4/git-get/blob/example-repo2/file --preserve-git || echo good)" 2 | 3 | [ "$R" = good ] 4 | -------------------------------------------------------------------------------- /tests/git-gets/github-blob-fail.test: -------------------------------------------------------------------------------- 1 | R="$(git-gets https://github.com/b1f6c1c4/git-get/blob/example-repo2/file example-repo0 || echo good)" 2 | 3 | [ "$R" = good ] 4 | -------------------------------------------------------------------------------- /tests/git-get/github-tree-dir-fail.test: -------------------------------------------------------------------------------- 1 | R="$(git-get https://github.com/b1f6c1c4/git-get/tree/example-repo2/dir example-repo0 || echo good)" 2 | 3 | [ "$R" = good ] 4 | -------------------------------------------------------------------------------- /tests/git-get/github-tree-dir-fail3.test: -------------------------------------------------------------------------------- 1 | R="$(git-get https://github.com/b1f6c1c4/git-get/tree/example-repo2/dir --preserve-git || echo good)" 2 | 3 | [ "$R" = good ] 4 | -------------------------------------------------------------------------------- /tests/git-get/url.test: -------------------------------------------------------------------------------- 1 | R="$(git-get https://github.com/b1f6c1c4/git-get example-repo2 -- file)" 2 | 3 | [ -z "$R" ] 4 | [ -f file ] 5 | [ -x file ] 6 | 7 | rm file 8 | -------------------------------------------------------------------------------- /tests/git-get/github-tree-fail.test: -------------------------------------------------------------------------------- 1 | R="$(git-get https://github.com/b1f6c1c4/git-get/tree/example-repo0 example-repo0 --preserve-git || echo good)" 2 | 3 | [ "$R" = good ] 4 | -------------------------------------------------------------------------------- /tests/git-get/gist-file.test: -------------------------------------------------------------------------------- 1 | R="$(git-get https://gist.github.com/b1f6c1c4/861f29441b09e22c161fa9cce6be7f53\#file-file2)" 2 | 3 | [ -z "$R" ] 4 | [ -x file2 ] 5 | 6 | rm file2 7 | -------------------------------------------------------------------------------- /tests/git-get/dir.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo2 -- dir)" 2 | 3 | [ -z "$R" ] 4 | [ -d dir ] 5 | [ -f dir/file-in-dir ] 6 | 7 | rm dir/file-in-dir 8 | rmdir dir 9 | -------------------------------------------------------------------------------- /tests/git-get/link.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo2 -- link)" 2 | 3 | [ -z "$R" ] 4 | [ -L link ] 5 | [ "$(readlink link)" = "dir/file-in-dir" ] 6 | 7 | unlink link 8 | -------------------------------------------------------------------------------- /tests/git-get/github-blob-dir.test: -------------------------------------------------------------------------------- 1 | R="$(git-get https://github.com/b1f6c1c4/git-get/blob/example-repo2/dir/file-in-dir)" 2 | 3 | [ -z "$R" ] 4 | [ -f file-in-dir ] 5 | 6 | rm file-in-dir 7 | -------------------------------------------------------------------------------- /tests/git-get/github-blob-ref.test: -------------------------------------------------------------------------------- 1 | R="$(git-get https://github.com/b1f6c1c4/git-get/blob/example/repo3/dir/file-in-dir)" 2 | 3 | [ -z "$R" ] 4 | [ -f file-in-dir ] 5 | 6 | rm file-in-dir 7 | -------------------------------------------------------------------------------- /tests/git-get/github-commit-path.test: -------------------------------------------------------------------------------- 1 | R="$(git-get https://github.com/b1f6c1c4/git-get/commit/bff5 -- dir/file-in-dir)" 2 | 3 | [ -z "$R" ] 4 | [ -f file-in-dir ] 5 | 6 | rm file-in-dir 7 | -------------------------------------------------------------------------------- /tests/git-get/dir-sub.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo2 -- xsub/sub/dir)" 2 | 3 | [ -z "$R" ] 4 | [ -d dir ] 5 | [ -f dir/file-in-dir ] 6 | 7 | rm dir/file-in-dir 8 | rmdir dir 9 | -------------------------------------------------------------------------------- /tests/git-get/github-tree-dir.test: -------------------------------------------------------------------------------- 1 | R="$(git-get https://github.com/b1f6c1c4/git-get/tree/example-repo2/dir)" 2 | 3 | [ -z "$R" ] 4 | [ -d dir ] 5 | [ -f dir/file-in-dir ] 6 | 7 | rm dir/file-in-dir 8 | rmdir dir 9 | -------------------------------------------------------------------------------- /tests/git-get/dir-force.test: -------------------------------------------------------------------------------- 1 | touch dir 2 | 3 | R="$(git-get b1f6c1c4/git-get example-repo2 -f -- dir)" 4 | 5 | [ -z "$R" ] 6 | [ -d dir ] 7 | [ -f dir/file-in-dir ] 8 | 9 | rm dir/file-in-dir 10 | rmdir dir 11 | -------------------------------------------------------------------------------- /tests/git-get/file-in-dir-fail.test: -------------------------------------------------------------------------------- 1 | mkdir file-in-dir 2 | 3 | R="$(git-get b1f6c1c4/git-get example-repo2 -- dir/file-in-dir || echo good)" 4 | 5 | [ "$R" = good ] 6 | [ -d file-in-dir ] 7 | 8 | rmdir file-in-dir 9 | -------------------------------------------------------------------------------- /tests/git-get/github-blob-perm.test: -------------------------------------------------------------------------------- 1 | R="$(git-get https://github.com/b1f6c1c4/git-get/blob/2dd50b6425c7d79f4695aa69d05467e1a00fc20f/dir/file-in-dir)" 2 | 3 | [ -z "$R" ] 4 | [ -f file-in-dir ] 5 | 6 | rm file-in-dir 7 | -------------------------------------------------------------------------------- /tests/git-get/github-tree-path.test: -------------------------------------------------------------------------------- 1 | R="$(git-get https://github.com/b1f6c1c4/git-get/tree/example-repo2 -- dir)" 2 | 3 | [ -z "$R" ] 4 | [ -d dir ] 5 | [ -f dir/file-in-dir ] 6 | 7 | rm dir/file-in-dir 8 | rmdir dir 9 | -------------------------------------------------------------------------------- /tests/git-get/file-in-dir-fail-f.test: -------------------------------------------------------------------------------- 1 | mkdir file-in-dir 2 | 3 | R="$(git-get b1f6c1c4/git-get example-repo2 -f -- dir/file-in-dir || echo good)" 4 | 5 | [ "$R" = good ] 6 | [ -d file-in-dir ] 7 | 8 | rmdir file-in-dir 9 | -------------------------------------------------------------------------------- /tests/git-get/file-in-dir-fail-rf.test: -------------------------------------------------------------------------------- 1 | mkdir file-in-dir 2 | 3 | R="$(git-get b1f6c1c4/git-get example-repo2 -F -- dir/file-in-dir || echo good)" 4 | 5 | [ "$R" = good ] 6 | [ -d file-in-dir ] 7 | 8 | rmdir file-in-dir 9 | -------------------------------------------------------------------------------- /tests/git-get/file-stdout-tag.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo2 -o- -t -- link)" 2 | 3 | [ "$R" = "dir/file-in-dir" ] 4 | [ "$(cat VERSION)" = "2dd50b6425c7d79f4695aa69d05467e1a00fc20f" ] 5 | 6 | rm VERSION 7 | -------------------------------------------------------------------------------- /tests/git-get/file-in-dir.test: -------------------------------------------------------------------------------- 1 | mkdir d 2 | 3 | R="$(git-get b1f6c1c4/git-get example-repo2 -o=d -- dir/file-in-dir)" 4 | 5 | [ -z "$R" ] 6 | [ -d d ] 7 | [ -f d/file-in-dir ] 8 | 9 | rm d/file-in-dir 10 | rmdir d 11 | -------------------------------------------------------------------------------- /tests/git-get/dir-stdout-tag.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo2 -o- -t -- dir | tar t)" 2 | 3 | [ "$R" = $'dir/\ndir/file-in-dir' ] 4 | [ "$(cat VERSION)" = "2dd50b6425c7d79f4695aa69d05467e1a00fc20f" ] 5 | 6 | rm VERSION 7 | -------------------------------------------------------------------------------- /tests/git-get/dir-force-force.test: -------------------------------------------------------------------------------- 1 | mkdir dir 2 | touch dir/old-file 3 | 4 | R="$(git-get b1f6c1c4/git-get example-repo2 -F -- dir)" 5 | 6 | [ -z "$R" ] 7 | [ -d dir ] 8 | [ -f dir/file-in-dir ] 9 | 10 | rm dir/file-in-dir 11 | rmdir dir 12 | -------------------------------------------------------------------------------- /tests/git-get/file-tag.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo2 -t -- dir/file-in-dir)" 2 | 3 | [ -z "$R" ] 4 | [ -f file-in-dir ] 5 | [ "$(cat VERSION)" = "2dd50b6425c7d79f4695aa69d05467e1a00fc20f" ] 6 | 7 | rm VERSION 8 | rm file-in-dir 9 | -------------------------------------------------------------------------------- /tests/git-get/dir-fail.test: -------------------------------------------------------------------------------- 1 | mkdir dir 2 | touch dir/old-file 3 | 4 | R="$(git-get b1f6c1c4/git-get example-repo2 -- dir || echo good)" 5 | 6 | [ "$R" = "good" ] 7 | [ -d dir ] 8 | [ -f dir/old-file ] 9 | 10 | rm dir/old-file 11 | rmdir dir 12 | -------------------------------------------------------------------------------- /tests/git-get/file-force.test: -------------------------------------------------------------------------------- 1 | touch file-in-dir 2 | chmod +x file-in-dir 3 | 4 | R="$(git-get b1f6c1c4/git-get example-repo2 -f -- dir/file-in-dir)" 5 | 6 | [ -z "$R" ] 7 | [ -f file-in-dir ] 8 | [ ! -x file-in-dir ] 9 | 10 | rm file-in-dir 11 | -------------------------------------------------------------------------------- /tests/git-get/dir-fail-f.test: -------------------------------------------------------------------------------- 1 | mkdir dir 2 | touch dir/old-file 3 | 4 | R="$(git-get b1f6c1c4/git-get example-repo2 -f -- dir || echo good)" 5 | 6 | [ "$R" = "good" ] 7 | [ -d dir ] 8 | [ -f dir/old-file ] 9 | 10 | rm dir/old-file 11 | rmdir dir 12 | -------------------------------------------------------------------------------- /tests/git-get/file-tag-file.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo2 --tag-file tag -- dir/file-in-dir)" 2 | 3 | [ -z "$R" ] 4 | [ -f file-in-dir ] 5 | [ "$(cat tag)" = "2dd50b6425c7d79f4695aa69d05467e1a00fc20f" ] 6 | 7 | rm tag 8 | rm file-in-dir 9 | -------------------------------------------------------------------------------- /tests/git-get/file-force-fail.test: -------------------------------------------------------------------------------- 1 | touch file-in-dir 2 | chmod +x file-in-dir 3 | 4 | R="$(git-get b1f6c1c4/git-get example-repo2 -- dir/file-in-dir || echo good)" 5 | 6 | [ "$R" = good ] 7 | [ -f file-in-dir ] 8 | [ -x file-in-dir ] 9 | 10 | rm file-in-dir 11 | -------------------------------------------------------------------------------- /tests/git-get/whole-output.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo0 -o d)" 2 | 3 | [ -z "$R" ] 4 | [ -L d/link ] 5 | [ -x d/file ] 6 | [ -d d/dir ] 7 | [ -f d/dir/file-in-dir ] 8 | 9 | rm d/dir/file-in-dir 10 | rmdir d/dir 11 | rm d/file 12 | unlink d/link 13 | rmdir d 14 | -------------------------------------------------------------------------------- /tests/git-get/dir-tag.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo2 -t -- dir)" 2 | 3 | [ -z "$R" ] 4 | [ -d dir ] 5 | [ -f dir/file-in-dir ] 6 | [ "$(cat dir/VERSION)" = "2dd50b6425c7d79f4695aa69d05467e1a00fc20f" ] 7 | 8 | rm dir/VERSION 9 | rm dir/file-in-dir 10 | rmdir dir 11 | -------------------------------------------------------------------------------- /tests/git-get/dir-tag-file.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo2 --tag-file=tag -- dir)" 2 | 3 | [ -z "$R" ] 4 | [ -d dir ] 5 | [ -f dir/file-in-dir ] 6 | [ "$(cat dir/tag)" = "2dd50b6425c7d79f4695aa69d05467e1a00fc20f" ] 7 | 8 | rm dir/tag 9 | rm dir/file-in-dir 10 | rmdir dir 11 | -------------------------------------------------------------------------------- /tests/git-get/whole-sub.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo2 -- xsub/sub/ )" 2 | 3 | [ -z "$R" ] 4 | [ -L sub/link ] 5 | [ -x sub/file ] 6 | [ -d sub/dir ] 7 | [ -f sub/dir/file-in-dir ] 8 | 9 | rm sub/dir/file-in-dir 10 | rmdir sub/dir 11 | rm sub/file 12 | unlink sub/link 13 | rmdir sub 14 | -------------------------------------------------------------------------------- /tests/git-get/file-sub-tag-file.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo2 --tag-file tag -- xsub/sub/file)" 2 | 3 | [ -z "$R" ] 4 | [ -x file ] 5 | [ "$(cat tag)" = $'2dd50b6425c7d79f4695aa69d05467e1a00fc20f\n2c0d59d84b729758f978c827a47980946f9a0e99\nbff56f7a1c9585780950dce5c1964410e0aa2ecc' ] 6 | 7 | rm tag 8 | rm file 9 | -------------------------------------------------------------------------------- /tests/git-get/whole.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo0)" 2 | 3 | [ -z "$R" ] 4 | [ -L git-get/link ] 5 | [ -x git-get/file ] 6 | [ -d git-get/dir ] 7 | [ -f git-get/dir/file-in-dir ] 8 | 9 | rm git-get/dir/file-in-dir 10 | rmdir git-get/dir 11 | rm git-get/file 12 | unlink git-get/link 13 | rmdir git-get 14 | -------------------------------------------------------------------------------- /tests/git-get/file-force-tag-coal.test: -------------------------------------------------------------------------------- 1 | touch file-in-dir 2 | chmod +x file-in-dir 3 | 4 | R="$(git-get b1f6c1c4/git-get example-repo2 -fvt -- dir/file-in-dir)" 5 | 6 | [ -z "$R" ] 7 | [ -f file-in-dir ] 8 | [ ! -x file-in-dir ] 9 | [ "$(cat VERSION)" = "2dd50b6425c7d79f4695aa69d05467e1a00fc20f" ] 10 | 11 | rm VERSION 12 | rm file-in-dir 13 | -------------------------------------------------------------------------------- /tests/git-get/dir-sub-tag.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo2 -t -- xsub/sub/dir)" 2 | 3 | [ -z "$R" ] 4 | [ -d dir ] 5 | [ -f dir/file-in-dir ] 6 | [ "$(cat dir/VERSION)" = $'2dd50b6425c7d79f4695aa69d05467e1a00fc20f\n2c0d59d84b729758f978c827a47980946f9a0e99\nbff56f7a1c9585780950dce5c1964410e0aa2ecc' ] 7 | 8 | rm dir/VERSION 9 | rm dir/file-in-dir 10 | rmdir dir 11 | -------------------------------------------------------------------------------- /tests/git-get/gist-whole.test: -------------------------------------------------------------------------------- 1 | R="$(git-get https://gist.github.com/b1f6c1c4/861f29441b09e22c161fa9cce6be7f53)" 2 | 3 | [ -z "$R" ] 4 | [ -f 861f29441b09e22c161fa9cce6be7f53/file1 ] 5 | [ -x 861f29441b09e22c161fa9cce6be7f53/file2 ] 6 | [ -L 861f29441b09e22c161fa9cce6be7f53/link ] 7 | 8 | rm 861f29441b09e22c161fa9cce6be7f53/file1 9 | rm 861f29441b09e22c161fa9cce6be7f53/file2 10 | unlink 861f29441b09e22c161fa9cce6be7f53/link 11 | rmdir 861f29441b09e22c161fa9cce6be7f53 12 | -------------------------------------------------------------------------------- /tests/git-get/whole-sub-tag.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo2 -t -- xsub/sub/ )" 2 | 3 | [ -z "$R" ] 4 | [ -L sub/link ] 5 | [ -x sub/file ] 6 | [ -d sub/dir ] 7 | [ -f sub/dir/file-in-dir ] 8 | [ "$(cat sub/VERSION)" = $'2dd50b6425c7d79f4695aa69d05467e1a00fc20f\n2c0d59d84b729758f978c827a47980946f9a0e99\nbff56f7a1c9585780950dce5c1964410e0aa2ecc' ] 9 | 10 | rm sub/VERSION 11 | rm sub/dir/file-in-dir 12 | rmdir sub/dir 13 | rm sub/file 14 | unlink sub/link 15 | rmdir sub 16 | -------------------------------------------------------------------------------- /tests/git-get/git-output.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo0 -o d --preserve-git)" 2 | 3 | [ -z "$R" ] 4 | [ "$(git -C d rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 5 | [ -L d/link ] 6 | [ -x d/file ] 7 | [ -d d/dir ] 8 | [ -f d/dir/file-in-dir ] 9 | [ "$(git -C d config --get remote.origin.tagOpt)" = "--no-tags" ] 10 | [ -z "$(git -C d config --get remote.origin.mirror)" ] 11 | [ -z "$(git -C d config --get remote.origin.fetch)" ] 12 | ! git -C d symbolic-ref HEAD 13 | 14 | rm -rf d 15 | -------------------------------------------------------------------------------- /tests/git-gets/sm-dirty-fail.test: -------------------------------------------------------------------------------- 1 | git clone --depth=2 --no-tags --branch example-repo2 https://github.com/b1f6c1c4/git-get.git repo 2 | git -C repo update-ref refs/heads/whatever 1beea7d7bf112446f5a3beda9dfa8b51727a5ae1 3 | 4 | echo a > repo/fo 5 | git -C repo add fo 6 | echo b > repo/fo 7 | 8 | R="$(cd repo && git-gets || echo good)" 9 | 10 | [ "$R" = good ] 11 | [ "$(cat repo/fo)" = b ] 12 | git -C repo restore --worktree fo 13 | [ "$(cat repo/fo)" = a ] 14 | rmdir repo/sub 15 | rmdir repo/xsub 16 | 17 | rm -rf repo 18 | -------------------------------------------------------------------------------- /tests/git-get/github-bare-tree.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get/tree/example-repo0 --preserve-git)" 2 | 3 | [ -z "$R" ] 4 | [ "$(git -C git-get rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 5 | [ -L git-get/link ] 6 | [ -x git-get/file ] 7 | [ -d git-get/dir ] 8 | [ -f git-get/dir/file-in-dir ] 9 | [ "$(git -C git-get config --get remote.origin.tagOpt)" = "--no-tags" ] 10 | [ -z "$(git -C git-get config --get remote.origin.mirror)" ] 11 | [ -z "$(git -C git-get config --get remote.origin.fetch)" ] 12 | 13 | rm -rf git-get 14 | -------------------------------------------------------------------------------- /tests/git-get/github-tree.test: -------------------------------------------------------------------------------- 1 | R="$(git-get https://github.com/b1f6c1c4/git-get/tree/example-repo2 --preserve-git)" 2 | 3 | [ -z "$R" ] 4 | [ "$(git -C git-get rev-parse HEAD)" = "2dd50b6425c7d79f4695aa69d05467e1a00fc20f" ] 5 | [ -L git-get/link ] 6 | [ -x git-get/file ] 7 | [ -d git-get/dir ] 8 | [ -f git-get/dir/file-in-dir ] 9 | [ "$(git -C git-get config --get remote.origin.tagOpt)" = "--no-tags" ] 10 | [ -z "$(git -C git-get config --get remote.origin.mirror)" ] 11 | [ -z "$(git -C git-get config --get remote.origin.fetch)" ] 12 | 13 | rm -rf git-get 14 | -------------------------------------------------------------------------------- /tests/git-get/github-commit.test: -------------------------------------------------------------------------------- 1 | R="$(git-get https://github.com/b1f6c1c4/git-get/commit/2dd5 --preserve-git)" 2 | 3 | [ -z "$R" ] 4 | [ "$(git -C git-get rev-parse HEAD)" = "2dd50b6425c7d79f4695aa69d05467e1a00fc20f" ] 5 | [ -L git-get/link ] 6 | [ -x git-get/file ] 7 | [ -d git-get/dir ] 8 | [ -f git-get/dir/file-in-dir ] 9 | [ -z "$(git -C git-get config --get remote.origin.tagOpt)" ] 10 | [ "$(git -C git-get config --get remote.origin.mirror)" = "true" ] 11 | [ "$(git -C git-get config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 12 | 13 | rm -rf git-get 14 | -------------------------------------------------------------------------------- /tests/git-get/git.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo0 --preserve-git)" 2 | 3 | [ -z "$R" ] 4 | [ "$(git -C git-get rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 5 | [ -L git-get/link ] 6 | [ -x git-get/file ] 7 | [ -d git-get/dir ] 8 | [ -f git-get/dir/file-in-dir ] 9 | [ "$(git -C git-get config --get remote.origin.tagOpt)" = "--no-tags" ] 10 | [ -z "$(git -C git-get config --get remote.origin.mirror)" ] 11 | [ -z "$(git -C git-get config --get remote.origin.fetch)" ] 12 | ! git -C git-get symbolic-ref HEAD 13 | 14 | rm -rf git-get 15 | -------------------------------------------------------------------------------- /tests/git-gets/sm-extra-fail.test: -------------------------------------------------------------------------------- 1 | git clone --depth=3 --no-tags --branch example-repo2 https://github.com/b1f6c1c4/git-get.git repo 2 | git -C repo update-ref refs/heads/whatever 1beea7d7bf112446f5a3beda9dfa8b51727a5ae1 3 | 4 | git -C repo switch --detach 2c0d59d 5 | git -C repo restore -s example-repo2 --staged --worktree xsub 6 | 7 | R="$(cd repo && git-gets || echo good)" 8 | 9 | [ "$R" = good ] 10 | [ "$(git -C repo ls-files -s -- xsub)" = $'160000 2c0d59d84b729758f978c827a47980946f9a0e99 0\txsub' ] 11 | rmdir repo/sub 12 | rmdir repo/xsub 13 | 14 | rm -rf repo 15 | -------------------------------------------------------------------------------- /tests/git-gets/simple.test: -------------------------------------------------------------------------------- 1 | R="$(git-gets b1f6c1c4/git-get example-repo2)" 2 | 3 | [ -z "$R" ] 4 | [ ! -e git-get/.git ] 5 | [ ! -e git-get/sub/.git ] 6 | [ ! -e git-get/xsub/.git ] 7 | [ ! -e git-get/xsub/sub/.git ] 8 | [ -L git-get/link ] 9 | [ -L git-get/sub/link ] 10 | [ -L git-get/xsub/link ] 11 | [ -L git-get/xsub/sub/link ] 12 | [ -x git-get/file ] 13 | [ -x git-get/sub/file ] 14 | [ -x git-get/xsub/file ] 15 | [ -x git-get/xsub/sub/file ] 16 | [ -f git-get/dir/file-in-dir ] 17 | [ -f git-get/sub/dir/file-in-dir ] 18 | [ -f git-get/xsub/dir/file-in-dir ] 19 | [ -f git-get/xsub/sub/dir/file-in-dir ] 20 | 21 | rm -rf git-get 22 | -------------------------------------------------------------------------------- /tests/git-gets/github-tree.test: -------------------------------------------------------------------------------- 1 | R="$(git-gets https://github.com/b1f6c1c4/git-get/tree/example-repo2)" 2 | 3 | [ -z "$R" ] 4 | [ ! -e git-get/.git ] 5 | [ ! -e git-get/sub/.git ] 6 | [ ! -e git-get/xsub/.git ] 7 | [ ! -e git-get/xsub/sub/.git ] 8 | [ -L git-get/link ] 9 | [ -L git-get/sub/link ] 10 | [ -L git-get/xsub/link ] 11 | [ -L git-get/xsub/sub/link ] 12 | [ -x git-get/file ] 13 | [ -x git-get/sub/file ] 14 | [ -x git-get/xsub/file ] 15 | [ -x git-get/xsub/sub/file ] 16 | [ -f git-get/dir/file-in-dir ] 17 | [ -f git-get/sub/dir/file-in-dir ] 18 | [ -f git-get/xsub/dir/file-in-dir ] 19 | [ -f git-get/xsub/sub/dir/file-in-dir ] 20 | 21 | rm -rf git-get 22 | -------------------------------------------------------------------------------- /tests/git-get/git-tag.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-tag --preserve-git)" 2 | 3 | [ -z "$R" ] 4 | [ "$(git -C git-get rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 5 | [ -L git-get/link ] 6 | [ -x git-get/file ] 7 | [ -d git-get/dir ] 8 | [ -f git-get/dir/file-in-dir ] 9 | [ "$(git -C git-get config --get remote.origin.tagOpt)" = "--no-tags" ] 10 | [ -z "$(git -C git-get config --get remote.origin.mirror)" ] 11 | [ -z "$(git -C git-get config --get remote.origin.fetch)" ] 12 | [ "$(git -C git-get rev-parse refs/tags/example-tag)" = "f774e3273eae40457109d04b0b5c5504047fac9d" ] 13 | ! git -C git-get symbolic-ref HEAD 14 | 15 | rm -rf git-get 16 | -------------------------------------------------------------------------------- /tests/git-gets/simple-confirm.test: -------------------------------------------------------------------------------- 1 | R="$(git-gets b1f6c1c4/git-get example-repo2 -c <<&1 | tee "$@" 15 | 16 | coverage/%: tests/% git-get git-gets 17 | mkdir -p "$$(dirname "$@")" 18 | ./run-test "$<" "$@" || { rm -rf "$@"; false; } 19 | 20 | clean: 21 | rm -rf report/ coverage/ 22 | 23 | .PHONY: test cover clean 24 | 25 | .DELETE_ON_ERROR: $(REPORTS) 26 | -------------------------------------------------------------------------------- /tests/git-get/git-tag-x-B.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-tag -x --single-branch)" 2 | 3 | [ -z "$R" ] 4 | [ "$(git -C git-get rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 5 | [ -L git-get/link ] 6 | [ -x git-get/file ] 7 | [ -d git-get/dir ] 8 | [ -f git-get/dir/file-in-dir ] 9 | [ ! -e git-get/sub ] 10 | [ -z "$(git -C git-get config --get remote.origin.tagOpt)" ] 11 | [ -z "$(git -C git-get config --get remote.origin.mirror)" ] 12 | [ -z "$(git -C git-get config --get remote.origin.fetch)" ] 13 | [ "$(git -C git-get rev-parse refs/heads/example-repo0 -- || echo good)" = "good" ] 14 | [ "$(git -C git-get rev-parse refs/remotes/origin/example-repo0 -- || echo good)" = "good" ] 15 | [ "$(git -C git-get rev-parse refs/tags/example-tag)" = "f774e3273eae40457109d04b0b5c5504047fac9d" ] 16 | ! git -C git-get symbolic-ref HEAD 17 | 18 | rm -rf git-get 19 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | 3 | branches: 4 | except: 5 | - /^example-/ 6 | 7 | skip_commits: 8 | message: /\[ci skip\]|\[skip ci\]/ 9 | 10 | image: 11 | - Ubuntu2004 12 | - Visual Studio 2022 13 | - macos 14 | 15 | environment: 16 | MAKEFLAGS: -j8 17 | COVERALLS_REPO_TOKEN: 18 | secure: 8t5ZKdyCWpby/hrKVV5kjvOst7QzfnaW4HKKEh7DKjmxDuwFWdkD8Oizq4Hsoe3N 19 | 20 | for: 21 | - 22 | matrix: 23 | only: 24 | - image: Visual Studio 2022 25 | 26 | install: 27 | - choco install make 28 | - 29 | matrix: 30 | only: 31 | - image: Ubuntu2004 32 | 33 | install: 34 | - sudo apt-get update || true 35 | - sudo apt-get install kcov 36 | build_script: 37 | - make cover 38 | 39 | before_build: 40 | - make --version 41 | - git version 42 | - grep --version 43 | - make clean 44 | 45 | build_script: 46 | - make test 47 | -------------------------------------------------------------------------------- /tests/git-get/git-tag-x.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-tag -x)" 2 | 3 | [ -z "$R" ] 4 | [ "$(git -C git-get rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 5 | [ -L git-get/link ] 6 | [ -x git-get/file ] 7 | [ -d git-get/dir ] 8 | [ -f git-get/dir/file-in-dir ] 9 | [ ! -e git-get/sub ] 10 | [ -z "$(git -C git-get config --get remote.origin.tagOpt)" ] 11 | [ -z "$(git -C git-get config --get remote.origin.mirror)" ] 12 | [ "$(git -C git-get config --get remote.origin.fetch)" = "+refs/heads/*:refs/remotes/origin/*" ] 13 | [ "$(git -C git-get rev-parse refs/heads/example-repo0 -- || echo good)" = "good" ] 14 | [ "$(git -C git-get rev-parse refs/remotes/origin/example-repo0)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 15 | [ "$(git -C git-get rev-parse refs/tags/example-tag)" = "f774e3273eae40457109d04b0b5c5504047fac9d" ] 16 | ! git -C git-get symbolic-ref HEAD 17 | 18 | rm -rf git-get 19 | -------------------------------------------------------------------------------- /tests/git-get/git-tag-x-T.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-tag -x --no-tags)" 2 | 3 | [ -z "$R" ] 4 | [ "$(git -C git-get rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 5 | [ -L git-get/link ] 6 | [ -x git-get/file ] 7 | [ -d git-get/dir ] 8 | [ -f git-get/dir/file-in-dir ] 9 | [ ! -e git-get/sub ] 10 | [ "$(git -C git-get config --get remote.origin.tagOpt)" = "--no-tags" ] 11 | [ -z "$(git -C git-get config --get remote.origin.mirror)" ] 12 | [ "$(git -C git-get config --get remote.origin.fetch)" = "+refs/heads/*:refs/remotes/origin/*" ] 13 | [ "$(git -C git-get rev-parse refs/heads/example-repo0 -- || echo good)" = "good" ] 14 | [ "$(git -C git-get rev-parse refs/remotes/origin/example-repo0)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 15 | [ "$(git -C git-get rev-parse refs/tags/example-tag -- || echo good)" = "good" ] 16 | ! git -C git-get symbolic-ref HEAD 17 | 18 | rm -rf git-get 19 | -------------------------------------------------------------------------------- /run-test: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | FILE="$(realpath "$1")" 6 | 7 | export GH_USE_HTTPS=YES 8 | 9 | if [ "$#" -le 1 ]; then 10 | export PATH="$(realpath "$(dirname "$0")"):$PATH" 11 | else 12 | MY="$(realpath "$(dirname "$0")")" 13 | OU="$(realpath "$2")" 14 | rm -rf "$OU" 15 | git-get() { 16 | kcov \ 17 | --skip-solibs --collect-only \ 18 | "--include-path=$MY/git-get,$MY/git-gets" \ 19 | "$OU" "$MY/git-get" --color=never "$@" 20 | } 21 | git-gets() { 22 | kcov \ 23 | --skip-solibs --collect-only \ 24 | "--include-path=$MY/git-get,$MY/git-gets" \ 25 | "$OU" "$MY/git-gets" --color=never "$@" 26 | } 27 | fi 28 | 29 | WORK_DIR="$(realpath "$(mktemp -d)")" 30 | finish() { 31 | cd / 32 | rm -rf "$WORK_DIR" 33 | } 34 | trap finish EXIT 35 | 36 | ( 37 | cd "$WORK_DIR" 38 | set -euxo pipefail 39 | source "$FILE" 40 | ) 41 | cd / 42 | rmdir "$WORK_DIR" 43 | -------------------------------------------------------------------------------- /tests/git-get/git-x-T.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo1 -x --no-tags)" 2 | 3 | [ -z "$R" ] 4 | [ "$(git -C git-get rev-parse HEAD)" = "e97348c1ba3072a1c108218f6ba88c3177a7456f" ] 5 | [ -L git-get/link ] 6 | [ -x git-get/file ] 7 | [ -d git-get/dir ] 8 | [ -f git-get/dir/file-in-dir ] 9 | [ -d git-get/sub ] 10 | [ "$(git -C git-get config --get remote.origin.tagOpt)" = "--no-tags" ] 11 | [ -z "$(git -C git-get config --get remote.origin.mirror)" ] 12 | [ "$(git -C git-get config --get remote.origin.fetch)" = "+refs/heads/*:refs/remotes/origin/*" ] 13 | [ "$(git -C git-get rev-parse HEAD~)" = "ac33e9e9ff337727a71d982fe84f9c66ea405171" ] 14 | [ "$(git -C git-get rev-parse refs/heads/example-repo0 -- || echo good)" = "good" ] 15 | [ "$(git -C git-get rev-parse refs/remotes/origin/example-repo0)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 16 | [ "$(git -C git-get rev-parse refs/tags/example-tag -- || echo good)" = "good" ] 17 | [ "$(git -C git-get symbolic-ref HEAD)" = "refs/heads/example-repo1" ] 18 | 19 | rm -rf git-get 20 | -------------------------------------------------------------------------------- /tests/git-get/git-x.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo1 -x)" 2 | 3 | [ -z "$R" ] 4 | [ "$(git -C git-get rev-parse HEAD)" = "e97348c1ba3072a1c108218f6ba88c3177a7456f" ] 5 | [ -L git-get/link ] 6 | [ -x git-get/file ] 7 | [ -d git-get/dir ] 8 | [ -f git-get/dir/file-in-dir ] 9 | [ -d git-get/sub ] 10 | [ -z "$(git -C git-get config --get remote.origin.tagOpt)" ] 11 | [ -z "$(git -C git-get config --get remote.origin.mirror)" ] 12 | [ "$(git -C git-get config --get remote.origin.fetch)" = "+refs/heads/*:refs/remotes/origin/*" ] 13 | [ "$(git -C git-get rev-parse HEAD~)" = "ac33e9e9ff337727a71d982fe84f9c66ea405171" ] 14 | [ "$(git -C git-get rev-parse refs/heads/example-repo0 -- || echo good)" = "good" ] 15 | [ "$(git -C git-get rev-parse refs/remotes/origin/example-repo0)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 16 | [ "$(git -C git-get rev-parse refs/tags/example-tag)" = "f774e3273eae40457109d04b0b5c5504047fac9d" ] 17 | [ "$(git -C git-get symbolic-ref HEAD)" = "refs/heads/example-repo1" ] 18 | 19 | rm -rf git-get 20 | -------------------------------------------------------------------------------- /tests/git-get/git-x-B.test: -------------------------------------------------------------------------------- 1 | R="$(git-get b1f6c1c4/git-get example-repo1 -x --single-branch)" 2 | 3 | [ -z "$R" ] 4 | [ "$(git -C git-get rev-parse HEAD)" = "e97348c1ba3072a1c108218f6ba88c3177a7456f" ] 5 | [ -L git-get/link ] 6 | [ -x git-get/file ] 7 | [ -d git-get/dir ] 8 | [ -f git-get/dir/file-in-dir ] 9 | [ -d git-get/sub ] 10 | [ -z "$(git -C git-get config --get remote.origin.tagOpt)" ] 11 | [ -z "$(git -C git-get config --get remote.origin.mirror)" ] 12 | [ "$(git -C git-get config --get remote.origin.fetch)" = "+refs/heads/example-repo1:refs/remotes/origin/example-repo1" ] 13 | [ "$(git -C git-get rev-parse HEAD~)" = "ac33e9e9ff337727a71d982fe84f9c66ea405171" ] 14 | [ "$(git -C git-get rev-parse refs/heads/example-repo0 -- || echo good)" = "good" ] 15 | [ "$(git -C git-get rev-parse refs/remotes/origin/example-repo0 -- || echo good)" = "good" ] 16 | [ "$(git -C git-get rev-parse refs/tags/example-tag)" = "f774e3273eae40457109d04b0b5c5504047fac9d" ] 17 | [ "$(git -C git-get symbolic-ref HEAD)" = "refs/heads/example-repo1" ] 18 | 19 | rm -rf git-get 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-2021 b1f6c1c4 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/git-gets/simple-no-recursive.test: -------------------------------------------------------------------------------- 1 | R="$(git-gets b1f6c1c4/git-get example-repo2 -g --no-recursive)" 2 | 3 | [ -z "$R" ] 4 | [ "$(git -C git-get rev-parse HEAD)" = "2dd50b6425c7d79f4695aa69d05467e1a00fc20f" ] 5 | [ "$(git -C git-get config --get remote.origin.tagOpt)" = "--no-tags" ] 6 | [ -z "$(git -C git-get config --get remote.origin.mirror)" ] 7 | [ -z "$(git -C git-get config --get remote.origin.fetch)" ] 8 | ! git -C git-get symbolic-ref HEAD 9 | 10 | [ "$(git -C git-get/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 11 | [ -z "$(git -C git-get/sub config --get remote.origin.tagOpt)" ] 12 | [ "$(git -C git-get/sub config --get remote.origin.mirror)" = "true" ] 13 | [ "$(git -C git-get/sub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 14 | ! git -C git-get/sub symbolic-ref HEAD 15 | 16 | [ "$(git -C git-get/xsub rev-parse HEAD)" = "2c0d59d84b729758f978c827a47980946f9a0e99" ] 17 | [ -z "$(git -C git-get/xsub config --get remote.origin.tagOpt)" ] 18 | [ "$(git -C git-get/xsub config --get remote.origin.mirror)" = "true" ] 19 | [ "$(git -C git-get/xsub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 20 | ! git -C git-get/xsub symbolic-ref HEAD 21 | 22 | rmdir git-get/xsub/sub 23 | 24 | rm -rf git-get 25 | -------------------------------------------------------------------------------- /tests/git-gets/sm-g-no-recursive.test: -------------------------------------------------------------------------------- 1 | git clone --depth=2 --no-tags --branch example-repo2 https://github.com/b1f6c1c4/git-get.git repo 2 | git -C repo update-ref refs/heads/whatever 1beea7d7bf112446f5a3beda9dfa8b51727a5ae1 3 | 4 | R="$(cd repo && git-gets -g --no-recursive)" 5 | 6 | [ -z "$R" ] 7 | [ "$(git -C repo config --get remote.origin.tagOpt)" = "--no-tags" ] 8 | [ "$(git -C repo rev-parse HEAD~~ -- || echo good)" = "good" ] 9 | [ "$(git -C repo rev-parse refs/heads/whatever)" = "1beea7d7bf112446f5a3beda9dfa8b51727a5ae1" ] 10 | ! git -C repo symbolic-ref HEAD 11 | 12 | [ "$(git -C repo/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 13 | [ -z "$(git -C repo/sub config --get remote.origin.tagOpt)" ] 14 | [ "$(git -C repo/sub config --get remote.origin.mirror)" = "true" ] 15 | [ "$(git -C repo/sub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 16 | ! git -C repo/sub symbolic-ref HEAD 17 | 18 | [ "$(git -C repo/xsub rev-parse HEAD)" = "2c0d59d84b729758f978c827a47980946f9a0e99" ] 19 | [ -z "$(git -C repo/xsub config --get remote.origin.tagOpt)" ] 20 | [ "$(git -C repo/xsub config --get remote.origin.mirror)" = "true" ] 21 | [ "$(git -C repo/xsub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 22 | ! git -C repo/sub symbolic-ref HEAD 23 | 24 | rmdir repo/xsub/sub 25 | 26 | rm -rf repo 27 | -------------------------------------------------------------------------------- /tests/git-gets/sm-g-no-init.test: -------------------------------------------------------------------------------- 1 | git clone --depth=2 --no-tags --branch example-repo2 https://github.com/b1f6c1c4/git-get.git repo 2 | git -C repo update-ref refs/heads/whatever 1beea7d7bf112446f5a3beda9dfa8b51727a5ae1 3 | git -C repo submodule init -- xsub 4 | 5 | R="$(cd repo && git-gets -g --no-init)" 6 | 7 | [ -z "$R" ] 8 | [ "$(git -C repo config --get remote.origin.tagOpt)" = "--no-tags" ] 9 | [ "$(git -C repo rev-parse HEAD~~ -- || echo good)" = "good" ] 10 | [ "$(git -C repo rev-parse refs/heads/whatever)" = "1beea7d7bf112446f5a3beda9dfa8b51727a5ae1" ] 11 | ! git -C repo symbolic-ref HEAD 12 | 13 | rmdir repo/sub 14 | 15 | [ "$(git -C repo/xsub rev-parse HEAD)" = "2c0d59d84b729758f978c827a47980946f9a0e99" ] 16 | [ -z "$(git -C repo/xsub config --get remote.origin.tagOpt)" ] 17 | [ "$(git -C repo/xsub config --get remote.origin.mirror)" = "true" ] 18 | [ "$(git -C repo/xsub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 19 | ! git -C repo/xsub symbolic-ref HEAD 20 | 21 | [ "$(git -C repo/xsub/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 22 | [ -z "$(git -C repo/xsub/sub config --get remote.origin.tagOpt)" ] 23 | [ "$(git -C repo/xsub/sub config --get remote.origin.mirror)" = "true" ] 24 | [ "$(git -C repo/xsub/sub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 25 | ! git -C repo/xsub/sub symbolic-ref HEAD 26 | 27 | rm -rf repo 28 | -------------------------------------------------------------------------------- /tests/git-gets/g-output.test: -------------------------------------------------------------------------------- 1 | R="$(git-gets b1f6c1c4/git-get example-repo2 -g -o d)" 2 | 3 | [ -z "$R" ] 4 | [ "$(git -C d rev-parse HEAD)" = "2dd50b6425c7d79f4695aa69d05467e1a00fc20f" ] 5 | [ "$(git -C d config --get remote.origin.tagOpt)" = "--no-tags" ] 6 | [ -z "$(git -C d config --get remote.origin.mirror)" ] 7 | [ -z "$(git -C d config --get remote.origin.fetch)" ] 8 | ! git -C d symbolic-ref HEAD 9 | 10 | [ "$(git -C d/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 11 | [ -z "$(git -C d/sub config --get remote.origin.tagOpt)" ] 12 | [ "$(git -C d/sub config --get remote.origin.mirror)" = "true" ] 13 | [ "$(git -C d/sub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 14 | ! git -C d/sub symbolic-ref HEAD 15 | 16 | [ "$(git -C d/xsub rev-parse HEAD)" = "2c0d59d84b729758f978c827a47980946f9a0e99" ] 17 | [ -z "$(git -C d/xsub config --get remote.origin.tagOpt)" ] 18 | [ "$(git -C d/xsub config --get remote.origin.mirror)" = "true" ] 19 | [ "$(git -C d/xsub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 20 | ! git -C d/xsub symbolic-ref HEAD 21 | 22 | [ "$(git -C d/xsub/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 23 | [ -z "$(git -C d/xsub/sub config --get remote.origin.tagOpt)" ] 24 | [ "$(git -C d/xsub/sub config --get remote.origin.mirror)" = "true" ] 25 | [ "$(git -C d/xsub/sub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 26 | ! git -C d/xsub/sub symbolic-ref HEAD 27 | 28 | rm -rf d 29 | -------------------------------------------------------------------------------- /tests/git-gets/g-output2.test: -------------------------------------------------------------------------------- 1 | R="$(git-gets b1f6c1c4/git-get example-repo2 -g -o=d)" 2 | 3 | [ -z "$R" ] 4 | [ "$(git -C d rev-parse HEAD)" = "2dd50b6425c7d79f4695aa69d05467e1a00fc20f" ] 5 | [ "$(git -C d config --get remote.origin.tagOpt)" = "--no-tags" ] 6 | [ -z "$(git -C d config --get remote.origin.mirror)" ] 7 | [ -z "$(git -C d config --get remote.origin.fetch)" ] 8 | ! git -C d symbolic-ref HEAD 9 | 10 | [ "$(git -C d/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 11 | [ -z "$(git -C d/sub config --get remote.origin.tagOpt)" ] 12 | [ "$(git -C d/sub config --get remote.origin.mirror)" = "true" ] 13 | [ "$(git -C d/sub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 14 | ! git -C d/sub symbolic-ref HEAD 15 | 16 | [ "$(git -C d/xsub rev-parse HEAD)" = "2c0d59d84b729758f978c827a47980946f9a0e99" ] 17 | [ -z "$(git -C d/xsub config --get remote.origin.tagOpt)" ] 18 | [ "$(git -C d/xsub config --get remote.origin.mirror)" = "true" ] 19 | [ "$(git -C d/xsub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 20 | ! git -C d/xsub symbolic-ref HEAD 21 | 22 | [ "$(git -C d/xsub/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 23 | [ -z "$(git -C d/xsub/sub config --get remote.origin.tagOpt)" ] 24 | [ "$(git -C d/xsub/sub config --get remote.origin.mirror)" = "true" ] 25 | [ "$(git -C d/xsub/sub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 26 | ! git -C d/xsub/sub symbolic-ref HEAD 27 | 28 | rm -rf d 29 | -------------------------------------------------------------------------------- /tests/git-gets/g-output3.test: -------------------------------------------------------------------------------- 1 | R="$(git-gets b1f6c1c4/git-get example-repo2 -g d)" 2 | 3 | [ -z "$R" ] 4 | [ "$(git -C d rev-parse HEAD)" = "2dd50b6425c7d79f4695aa69d05467e1a00fc20f" ] 5 | [ "$(git -C d config --get remote.origin.tagOpt)" = "--no-tags" ] 6 | [ -z "$(git -C d config --get remote.origin.mirror)" ] 7 | [ -z "$(git -C d config --get remote.origin.fetch)" ] 8 | ! git -C d symbolic-ref HEAD 9 | 10 | [ "$(git -C d/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 11 | [ -z "$(git -C d/sub config --get remote.origin.tagOpt)" ] 12 | [ "$(git -C d/sub config --get remote.origin.mirror)" = "true" ] 13 | [ "$(git -C d/sub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 14 | ! git -C d/sub symbolic-ref HEAD 15 | 16 | [ "$(git -C d/xsub rev-parse HEAD)" = "2c0d59d84b729758f978c827a47980946f9a0e99" ] 17 | [ -z "$(git -C d/xsub config --get remote.origin.tagOpt)" ] 18 | [ "$(git -C d/xsub config --get remote.origin.mirror)" = "true" ] 19 | [ "$(git -C d/xsub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 20 | ! git -C d/xsub symbolic-ref HEAD 21 | 22 | [ "$(git -C d/xsub/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 23 | [ -z "$(git -C d/xsub/sub config --get remote.origin.tagOpt)" ] 24 | [ "$(git -C d/xsub/sub config --get remote.origin.mirror)" = "true" ] 25 | [ "$(git -C d/xsub/sub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 26 | ! git -C d/xsub/sub symbolic-ref HEAD 27 | 28 | rm -rf d 29 | -------------------------------------------------------------------------------- /zsh/_git-get: -------------------------------------------------------------------------------- 1 | #compdef git-get 2 | 3 | _arguments -s -S -A "-*" \ 4 | '(*)'{-V,--version}'[Show git-get version]' \ 5 | '(*)'{-h,--help}'[Show documentation]' \ 6 | '(-v --verbose)'{-v,--verbose}'[Show intermediate steps]' \ 7 | '(-q --quiet)'{-q,--quiet}'[Hide every intermediate information but errors]' \ 8 | '(--color --colour)'{--color=,--colour=}'[Display steps in color]:when:(never always auto)' \ 9 | '(-s --ssh -H --https)'{-s,--ssh}'[Enforce SSH protocol]' \ 10 | '(-H --https -s --ssh)'{-H,--https}'[Enforce HTTPS protocol]' \ 11 | '(-X -Y -x -u --upstream -B --single-branch -T --no-tags -t --tag-file)-X[Optimize clone for making changes]' \ 12 | '(-X -Y -x -u --upstream -B --single-branch -T --no-tags -t --tag-file)-Y[Optimize clone for not making changes]' \ 13 | '(-o --output)'{-o+,--output=}'[Put the download file or directory here]:directory:_files' \ 14 | '(-f --force)'{-f,--force}'[Override an existing file]' \ 15 | '(-F --rm-rf -f --force)'{-F,--rm-rf}'[Override an existing folder]' \ 16 | '(-g --preserve-git -t --tag-file)-x[Preserve and enhance the .git directory]' \ 17 | '(-u --upstream)'{-u,--upstream}'[Clone upstream GitHub repo as well (if available)]' \ 18 | '(-B --single-branch)'{-B,--single-branch}'[Cleanup unnecessary branches]' \ 19 | '(-T --no-tags)'{-T,--no-tags}'[Cleanup all tags]' \ 20 | '(-g --preserve-git -x -t --tag-file)'{-g,--preserve-git}'[Preserve the .git directory]' \ 21 | '(-t --tag-file)'{-t+,--tag-file=}'[Generate a tag file (default=VERSION)]:file:_files' 22 | -------------------------------------------------------------------------------- /tests/git-gets/g.test: -------------------------------------------------------------------------------- 1 | R="$(git-gets b1f6c1c4/git-get example-repo2 -g)" 2 | 3 | [ -z "$R" ] 4 | [ "$(git -C git-get rev-parse HEAD)" = "2dd50b6425c7d79f4695aa69d05467e1a00fc20f" ] 5 | [ "$(git -C git-get config --get remote.origin.tagOpt)" = "--no-tags" ] 6 | [ -z "$(git -C git-get config --get remote.origin.mirror)" ] 7 | [ -z "$(git -C git-get config --get remote.origin.fetch)" ] 8 | ! git -C git-get symbolic-ref HEAD 9 | 10 | [ "$(git -C git-get/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 11 | [ -z "$(git -C git-get/sub config --get remote.origin.tagOpt)" ] 12 | [ "$(git -C git-get/sub config --get remote.origin.mirror)" = "true" ] 13 | [ "$(git -C git-get/sub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 14 | ! git -C git-get/sub symbolic-ref HEAD 15 | 16 | [ "$(git -C git-get/xsub rev-parse HEAD)" = "2c0d59d84b729758f978c827a47980946f9a0e99" ] 17 | [ -z "$(git -C git-get/xsub config --get remote.origin.tagOpt)" ] 18 | [ "$(git -C git-get/xsub config --get remote.origin.mirror)" = "true" ] 19 | [ "$(git -C git-get/xsub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 20 | ! git -C git-get/xsub symbolic-ref HEAD 21 | 22 | [ "$(git -C git-get/xsub/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 23 | [ -z "$(git -C git-get/xsub/sub config --get remote.origin.tagOpt)" ] 24 | [ "$(git -C git-get/xsub/sub config --get remote.origin.mirror)" = "true" ] 25 | [ "$(git -C git-get/xsub/sub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 26 | ! git -C git-get/xsub/sub symbolic-ref HEAD 27 | 28 | rm -rf git-get 29 | -------------------------------------------------------------------------------- /tests/git-gets/g-sha1.test: -------------------------------------------------------------------------------- 1 | R="$(git-gets b1f6c1c4/git-get -g 2dd5)" 2 | 3 | [ -z "$R" ] 4 | [ "$(git -C git-get rev-parse HEAD)" = "2dd50b6425c7d79f4695aa69d05467e1a00fc20f" ] 5 | [ -z "$(git -C git-get config --get remote.origin.tagOpt)" ] 6 | [ "$(git -C git-get config --get remote.origin.mirror)" = "true" ] 7 | [ "$(git -C git-get config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 8 | ! git -C git-get symbolic-ref HEAD 9 | 10 | [ "$(git -C git-get/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 11 | [ -z "$(git -C git-get/sub config --get remote.origin.tagOpt)" ] 12 | [ "$(git -C git-get/sub config --get remote.origin.mirror)" = "true" ] 13 | [ "$(git -C git-get/sub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 14 | ! git -C git-get/sub symbolic-ref HEAD 15 | 16 | [ "$(git -C git-get/xsub rev-parse HEAD)" = "2c0d59d84b729758f978c827a47980946f9a0e99" ] 17 | [ -z "$(git -C git-get/xsub config --get remote.origin.tagOpt)" ] 18 | [ "$(git -C git-get/xsub config --get remote.origin.mirror)" = "true" ] 19 | [ "$(git -C git-get/xsub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 20 | ! git -C git-get/xsub symbolic-ref HEAD 21 | 22 | [ "$(git -C git-get/xsub/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 23 | [ -z "$(git -C git-get/xsub/sub config --get remote.origin.tagOpt)" ] 24 | [ "$(git -C git-get/xsub/sub config --get remote.origin.mirror)" = "true" ] 25 | [ "$(git -C git-get/xsub/sub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 26 | ! git -C git-get/xsub/sub symbolic-ref HEAD 27 | 28 | rm -rf git-get 29 | -------------------------------------------------------------------------------- /tests/git-gets/g-parallel.test: -------------------------------------------------------------------------------- 1 | R="$(git-gets b1f6c1c4/git-get example-repo2 -gP)" 2 | 3 | [ -z "$R" ] 4 | [ "$(git -C git-get rev-parse HEAD)" = "2dd50b6425c7d79f4695aa69d05467e1a00fc20f" ] 5 | [ "$(git -C git-get config --get remote.origin.tagOpt)" = "--no-tags" ] 6 | [ -z "$(git -C git-get config --get remote.origin.mirror)" ] 7 | [ -z "$(git -C git-get config --get remote.origin.fetch)" ] 8 | ! git -C git-get symbolic-ref HEAD 9 | 10 | [ "$(git -C git-get/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 11 | [ -z "$(git -C git-get/sub config --get remote.origin.tagOpt)" ] 12 | [ "$(git -C git-get/sub config --get remote.origin.mirror)" = "true" ] 13 | [ "$(git -C git-get/sub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 14 | ! git -C git-get/sub symbolic-ref HEAD 15 | 16 | [ "$(git -C git-get/xsub rev-parse HEAD)" = "2c0d59d84b729758f978c827a47980946f9a0e99" ] 17 | [ -z "$(git -C git-get/xsub config --get remote.origin.tagOpt)" ] 18 | [ "$(git -C git-get/xsub config --get remote.origin.mirror)" = "true" ] 19 | [ "$(git -C git-get/xsub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 20 | ! git -C git-get/xsub symbolic-ref HEAD 21 | 22 | [ "$(git -C git-get/xsub/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 23 | [ -z "$(git -C git-get/xsub/sub config --get remote.origin.tagOpt)" ] 24 | [ "$(git -C git-get/xsub/sub config --get remote.origin.mirror)" = "true" ] 25 | [ "$(git -C git-get/xsub/sub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 26 | ! git -C git-get/xsub/sub symbolic-ref HEAD 27 | 28 | rm -rf git-get 29 | -------------------------------------------------------------------------------- /tests/git-gets/sm-g.test: -------------------------------------------------------------------------------- 1 | git clone --depth=2 --no-tags --branch example-repo2 https://github.com/b1f6c1c4/git-get.git repo 2 | git -C repo update-ref refs/heads/whatever 1beea7d7bf112446f5a3beda9dfa8b51727a5ae1 3 | 4 | R="$(cd repo && git-gets -g)" 5 | 6 | [ -z "$R" ] 7 | [ "$(git -C repo config --get remote.origin.tagOpt)" = "--no-tags" ] 8 | [ "$(git -C repo rev-parse HEAD~~ -- || echo good)" = "good" ] 9 | [ "$(git -C repo rev-parse refs/heads/whatever)" = "1beea7d7bf112446f5a3beda9dfa8b51727a5ae1" ] 10 | ! git -C repo symbolic-ref HEAD 11 | 12 | [ "$(git -C repo/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 13 | [ -z "$(git -C repo/sub config --get remote.origin.tagOpt)" ] 14 | [ "$(git -C repo/sub config --get remote.origin.mirror)" = "true" ] 15 | [ "$(git -C repo/sub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 16 | ! git -C repo/sub symbolic-ref HEAD 17 | 18 | [ "$(git -C repo/xsub rev-parse HEAD)" = "2c0d59d84b729758f978c827a47980946f9a0e99" ] 19 | [ -z "$(git -C repo/xsub config --get remote.origin.tagOpt)" ] 20 | [ "$(git -C repo/xsub config --get remote.origin.mirror)" = "true" ] 21 | [ "$(git -C repo/xsub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 22 | ! git -C repo/xsub symbolic-ref HEAD 23 | 24 | [ "$(git -C repo/xsub/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 25 | [ -z "$(git -C repo/xsub/sub config --get remote.origin.tagOpt)" ] 26 | [ "$(git -C repo/xsub/sub config --get remote.origin.mirror)" = "true" ] 27 | [ "$(git -C repo/xsub/sub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 28 | ! git -C repo/xsub/sub symbolic-ref HEAD 29 | 30 | rm -rf repo 31 | -------------------------------------------------------------------------------- /tests/git-gets/sm-g-cwd.test: -------------------------------------------------------------------------------- 1 | git clone --depth=2 --no-tags --branch example-repo2 https://github.com/b1f6c1c4/git-get.git repo 2 | git -C repo update-ref refs/heads/whatever 1beea7d7bf112446f5a3beda9dfa8b51727a5ae1 3 | 4 | R="$(cd repo && git-gets -g)" 5 | 6 | [ -z "$R" ] 7 | [ "$(git -C repo config --get remote.origin.tagOpt)" = "--no-tags" ] 8 | [ "$(git -C repo rev-parse HEAD~~ -- || echo good)" = "good" ] 9 | [ "$(git -C repo rev-parse refs/heads/whatever)" = "1beea7d7bf112446f5a3beda9dfa8b51727a5ae1" ] 10 | ! git -C repo symbolic-ref HEAD 11 | 12 | [ "$(git -C repo/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 13 | [ -z "$(git -C repo/sub config --get remote.origin.tagOpt)" ] 14 | [ "$(git -C repo/sub config --get remote.origin.mirror)" = "true" ] 15 | [ "$(git -C repo/sub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 16 | ! git -C repo/sub symbolic-ref HEAD 17 | 18 | [ "$(git -C repo/xsub rev-parse HEAD)" = "2c0d59d84b729758f978c827a47980946f9a0e99" ] 19 | [ -z "$(git -C repo/xsub config --get remote.origin.tagOpt)" ] 20 | [ "$(git -C repo/xsub config --get remote.origin.mirror)" = "true" ] 21 | [ "$(git -C repo/xsub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 22 | ! git -C repo/xsub symbolic-ref HEAD 23 | 24 | [ "$(git -C repo/xsub/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 25 | [ -z "$(git -C repo/xsub/sub config --get remote.origin.tagOpt)" ] 26 | [ "$(git -C repo/xsub/sub config --get remote.origin.mirror)" = "true" ] 27 | [ "$(git -C repo/xsub/sub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 28 | ! git -C repo/xsub/sub symbolic-ref HEAD 29 | 30 | rm -rf repo 31 | -------------------------------------------------------------------------------- /tests/git-gets/sm-g-in.test: -------------------------------------------------------------------------------- 1 | git clone --depth=2 --no-tags --branch example-repo2 https://github.com/b1f6c1c4/git-get.git repo 2 | git -C repo update-ref refs/heads/whatever 1beea7d7bf112446f5a3beda9dfa8b51727a5ae1 3 | 4 | R="$(cd repo/dir && git-gets -g)" 5 | 6 | [ -z "$R" ] 7 | [ "$(git -C repo config --get remote.origin.tagOpt)" = "--no-tags" ] 8 | [ "$(git -C repo rev-parse HEAD~~ -- || echo good)" = "good" ] 9 | [ "$(git -C repo rev-parse refs/heads/whatever)" = "1beea7d7bf112446f5a3beda9dfa8b51727a5ae1" ] 10 | ! git -C repo symbolic-ref HEAD 11 | 12 | [ "$(git -C repo/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 13 | [ -z "$(git -C repo/sub config --get remote.origin.tagOpt)" ] 14 | [ "$(git -C repo/sub config --get remote.origin.mirror)" = "true" ] 15 | [ "$(git -C repo/sub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 16 | ! git -C repo/sub symbolic-ref HEAD 17 | 18 | [ "$(git -C repo/xsub rev-parse HEAD)" = "2c0d59d84b729758f978c827a47980946f9a0e99" ] 19 | [ -z "$(git -C repo/xsub config --get remote.origin.tagOpt)" ] 20 | [ "$(git -C repo/xsub config --get remote.origin.mirror)" = "true" ] 21 | [ "$(git -C repo/xsub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 22 | ! git -C repo/xsub symbolic-ref HEAD 23 | 24 | [ "$(git -C repo/xsub/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 25 | [ -z "$(git -C repo/xsub/sub config --get remote.origin.tagOpt)" ] 26 | [ "$(git -C repo/xsub/sub config --get remote.origin.mirror)" = "true" ] 27 | [ "$(git -C repo/xsub/sub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 28 | ! git -C repo/xsub/sub symbolic-ref HEAD 29 | 30 | rm -rf repo 31 | -------------------------------------------------------------------------------- /zsh/_git-gets: -------------------------------------------------------------------------------- 1 | #compdef git-gets 2 | 3 | _arguments -s -S -A "-*" \ 4 | '(*)'{-V,--version}'[Show git-gets version]' \ 5 | '(*)'{-h,--help}'[Show documentation]' \ 6 | '(-v --verbose)'{-v,--verbose}'[Show intermediate steps]' \ 7 | '(-q --quiet)'{-q,--quiet}'[Hide every intermediate information but errors]' \ 8 | '(--color --colour)'{--color=,--colour=}'[Display steps in color]:when:(never always auto)' \ 9 | '(-s --ssh -H --https)'{-s,--ssh}'[Enforce SSH protocol]' \ 10 | '(-H --https -s --ssh)'{-H,--https}'[Enforce HTTPS protocol]' \ 11 | '(-X -Y -x -u --upstream -B --single-branch -T --no-tags -t --tag-file -P --parallel)-X[Optimize clone for making changes]' \ 12 | '(-X -Y -x -u --upstream -B --single-branch -T --no-tags -t --tag-file -P --parallel)-Y[Optimize clone for not making changes]' \ 13 | '--no-recursive[Only top-level submodules]' \ 14 | '(-o --output)'{-o+,--output=}'[Put the download file or directory here]:directory:_files' \ 15 | '(-F --rm-rf)'{-F,--rm-rf}'[Override an existing folder]' \ 16 | '(-g --preserve-git -t --tag-file)-x[Preserve and enhance the .git directory]' \ 17 | '(-B --single-branch)'{-B,--single-branch}'[Cleanup unnecessary branches]' \ 18 | '(-T --no-tags)'{-T,--no-tags}'[Cleanup all tags]' \ 19 | '(-g --preserve-git -x -t --tag-file)'{-g,--preserve-git}'[Preserve the .git directory]' \ 20 | '(-u --upstream)'{-u,--upstream}'[Clone upstream GitHub repo as well (if available)]' \ 21 | '(-t --tag-file)'{-t+,--tag-file=}'[Generate a tag file (default=VERSION)]:file:_files' \ 22 | '(-P --parallel)'{-P,--parallel}'[Launch multiple instances of git-clone]' \ 23 | '(-c --confirm)'{-c,--confirm}'[Prompt the user before downloading]' \ 24 | '--no-init[Only download already inited top-level submodules]' 25 | -------------------------------------------------------------------------------- /tests/git-gets/sm-g-gw.test: -------------------------------------------------------------------------------- 1 | git clone --depth=2 --no-tags --branch example-repo2 https://github.com/b1f6c1c4/git-get.git --separate-git-dir repo worktree 2 | git -C repo update-ref refs/heads/whatever 1beea7d7bf112446f5a3beda9dfa8b51727a5ae1 3 | 4 | R="$(GIT_DIR=repo GIT_WORK_TREE=worktree git-gets -g)" 5 | 6 | [ -z "$R" ] 7 | [ "$(git -C worktree config --get remote.origin.tagOpt)" = "--no-tags" ] 8 | [ "$(git -C worktree rev-parse HEAD~~ -- || echo good)" = "good" ] 9 | [ "$(git -C worktree rev-parse refs/heads/whatever)" = "1beea7d7bf112446f5a3beda9dfa8b51727a5ae1" ] 10 | ! git -C worktree symbolic-ref HEAD 11 | 12 | [ "$(git -C worktree/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 13 | [ -z "$(git -C worktree/sub config --get remote.origin.tagOpt)" ] 14 | [ "$(git -C worktree/sub config --get remote.origin.mirror)" = "true" ] 15 | [ "$(git -C worktree/sub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 16 | ! git -C worktree/sub symbolic-ref HEAD 17 | 18 | [ "$(git -C worktree/xsub rev-parse HEAD)" = "2c0d59d84b729758f978c827a47980946f9a0e99" ] 19 | [ -z "$(git -C worktree/xsub config --get remote.origin.tagOpt)" ] 20 | [ "$(git -C worktree/xsub config --get remote.origin.mirror)" = "true" ] 21 | [ "$(git -C worktree/xsub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 22 | ! git -C worktree/xsub symbolic-ref HEAD 23 | 24 | [ "$(git -C worktree/xsub/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 25 | [ -z "$(git -C worktree/xsub/sub config --get remote.origin.tagOpt)" ] 26 | [ "$(git -C worktree/xsub/sub config --get remote.origin.mirror)" = "true" ] 27 | [ "$(git -C worktree/xsub/sub config --get remote.origin.fetch)" = "+refs/*:refs/*" ] 28 | ! git -C worktree/xsub/sub symbolic-ref HEAD 29 | 30 | rm -rf repo worktree 31 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eux 4 | 5 | find build/ -mindepth 1 -delete 6 | 7 | VERSION="$(git describe --always --dirty | sed 's/-/_/g')" 8 | DATE="$(date -Id)" 9 | 10 | mkdir -p build/bin/ 11 | sed "s|GIT_GET_VERSION=|GIT_GET_VERSION=$VERSION|" git-get >build/bin/git-get 12 | sed "s|GIT_GET_VERSION=|GIT_GET_VERSION=$VERSION|" git-gets >build/bin/git-gets 13 | 14 | mkdir -p build/share/man/man1/ 15 | sed "s|GIT_GET_VERSION|$VERSION|; s|GIT_GET_DATE|$DATE|" man/git-get.1 >build/share/man/man1/git-get.1 16 | sed "s|GIT_GET_VERSION|$VERSION|; s|GIT_GET_DATE|$DATE|" man/git-gets.1 >build/share/man/man1/git-gets.1 17 | 18 | mkdir -p build/share/licenses/git-get/ 19 | cp LICENSE build/share/licenses/git-get/ 20 | 21 | mkdir -p build/share/zsh/site-functions/ 22 | cp zsh/_git-get build/share/zsh/site-functions/_git-get 23 | cp zsh/_git-gets build/share/zsh/site-functions/_git-gets 24 | 25 | chmod +x build/bin/git-get build/bin/git-gets 26 | 27 | ( 28 | cd build/ 29 | tar -czvf git-get.tar.gz --owner=root --group=root bin/ share/ 30 | tar -cJvf git-get.tar.xz --owner=root --group=root bin/ share/ 31 | zip -r git-get.zip bin/ share/ 32 | ) 33 | 34 | echo "git-get(1) $VERSION" 35 | 36 | gpg --detach-sign build/git-get.tar.gz 37 | gpg --detach-sign build/git-get.tar.xz 38 | gpg --detach-sign build/git-get.zip 39 | 40 | mkdir -p build/arch/ 41 | cat - <build/arch/PKGBUILD 42 | # Maintainer: b1f6c1c4 43 | pkgname=git-get 44 | pkgver=$VERSION 45 | pkgrel=1 46 | pkgdesc="Blazingly fast, incredibly handy git clone alternative" 47 | arch=('any') 48 | url="https://github.com/b1f6c1c4/git-get" 49 | license=('MIT') 50 | depends=('git' 'bash' 'grep' 'sed') 51 | source=("\$pkgname-\$pkgver.tar.xz::\$url/releases/download/\$pkgver/\$pkgname.tar.xz") 52 | sha256sums=('$(sha256sum build/git-get.tar.xz | awk '{ print $1; }')') 53 | 54 | package() { 55 | mkdir -p "\$pkgdir/usr/" 56 | cp -r "\$srcdir/bin" "\$pkgdir/usr/" 57 | cp -r "\$srcdir/share" "\$pkgdir/usr/" 58 | } 59 | EOF 60 | -------------------------------------------------------------------------------- /tests/git-gets/x-B.test: -------------------------------------------------------------------------------- 1 | R="$(git-gets b1f6c1c4/git-get example-repo2 -x --single-branch)" 2 | 3 | [ -z "$R" ] 4 | [ "$(git -C git-get rev-parse HEAD)" = "2dd50b6425c7d79f4695aa69d05467e1a00fc20f" ] 5 | [ -z "$(git -C git-get config --get remote.origin.tagOpt)" ] 6 | [ -z "$(git -C git-get config --get remote.origin.mirror)" ] 7 | [ "$(git -C git-get config --get remote.origin.fetch)" = "+refs/heads/example-repo2:refs/remotes/origin/example-repo2" ] 8 | [ "$(git -C git-get symbolic-ref HEAD)" = "refs/heads/example-repo2" ] 9 | 10 | [ "$(git -C git-get/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 11 | [ -z "$(git -C git-get/sub config --get remote.origin.tagOpt)" ] 12 | [ -z "$(git -C git-get/sub config --get remote.origin.mirror)" ] 13 | [ -z "$(git -C git-get/sub config --get remote.origin.fetch)" ] 14 | [ "$(git -C git-get/sub rev-parse refs/heads/example-repo0 -- || echo good)" = "good" ] 15 | [ "$(git -C git-get/sub rev-parse refs/remotes/origin/example-repo0 -- || echo good)" = "good" ] 16 | [ "$(git -C git-get/sub rev-parse refs/tags/example-tag)" = "f774e3273eae40457109d04b0b5c5504047fac9d" ] 17 | ! git -C git-get/sub symbolic-ref HEAD 18 | 19 | [ "$(git -C git-get/xsub rev-parse HEAD)" = "2c0d59d84b729758f978c827a47980946f9a0e99" ] 20 | [ -z "$(git -C git-get/xsub config --get remote.origin.tagOpt)" ] 21 | [ -z "$(git -C git-get/xsub config --get remote.origin.mirror)" ] 22 | [ -z "$(git -C git-get/xsub config --get remote.origin.fetch)" ] 23 | [ "$(git -C git-get/xsub rev-parse HEAD~)" = "e7b2ae86f8574a1e16c71150ec538d102e574ca5" ] 24 | [ "$(git -C git-get/xsub rev-parse refs/heads/example-repo0 -- || echo good)" = "good" ] 25 | [ "$(git -C git-get/xsub rev-parse refs/remotes/origin/example-repo0 -- || echo good)" = "good" ] 26 | [ "$(git -C git-get/xsub rev-parse refs/tags/example-tag)" = "f774e3273eae40457109d04b0b5c5504047fac9d" ] 27 | ! git -C git-get/xsub symbolic-ref HEAD 28 | 29 | [ "$(git -C git-get/xsub/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 30 | [ -z "$(git -C git-get/xsub/sub config --get remote.origin.tagOpt)" ] 31 | [ -z "$(git -C git-get/xsub/sub config --get remote.origin.mirror)" ] 32 | [ -z "$(git -C git-get/xsub/sub config --get remote.origin.fetch)" ] 33 | [ "$(git -C git-get/xsub/sub rev-parse refs/heads/example-repo0 -- || echo good)" = "good" ] 34 | [ "$(git -C git-get/xsub rev-parse refs/remotes/origin/example-repo0 -- || echo good)" = "good" ] 35 | [ "$(git -C git-get/xsub/sub rev-parse refs/tags/example-tag)" = "f774e3273eae40457109d04b0b5c5504047fac9d" ] 36 | ! git -C git-get/xsub/sub symbolic-ref HEAD 37 | 38 | rm -rf git-get 39 | -------------------------------------------------------------------------------- /tests/git-gets/x-T.test: -------------------------------------------------------------------------------- 1 | R="$(git-gets b1f6c1c4/git-get example-repo2 -x --no-tags)" 2 | 3 | [ -z "$R" ] 4 | [ "$(git -C git-get rev-parse HEAD)" = "2dd50b6425c7d79f4695aa69d05467e1a00fc20f" ] 5 | [ "$(git -C git-get config --get remote.origin.tagOpt)" = "--no-tags" ] 6 | [ -z "$(git -C git-get config --get remote.origin.mirror)" ] 7 | [ "$(git -C git-get config --get remote.origin.fetch)" = "+refs/heads/*:refs/remotes/origin/*" ] 8 | [ "$(git -C git-get symbolic-ref HEAD)" = "refs/heads/example-repo2" ] 9 | 10 | [ "$(git -C git-get/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 11 | [ "$(git -C git-get/sub config --get remote.origin.tagOpt)" = "--no-tags" ] 12 | [ -z "$(git -C git-get/sub config --get remote.origin.mirror)" ] 13 | [ "$(git -C git-get/sub config --get remote.origin.fetch)" = "+refs/heads/*:refs/remotes/origin/*" ] 14 | [ "$(git -C git-get/sub rev-parse refs/heads/example-repo0 -- || echo good)" = "good" ] 15 | [ "$(git -C git-get/sub rev-parse refs/remotes/origin/example-repo0)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 16 | [ "$(git -C git-get/sub rev-parse refs/tags/example-tag -- || echo good)" = "good" ] 17 | ! git -C git-get/sub symbolic-ref HEAD 18 | 19 | [ "$(git -C git-get/xsub rev-parse HEAD)" = "2c0d59d84b729758f978c827a47980946f9a0e99" ] 20 | [ "$(git -C git-get/xsub config --get remote.origin.tagOpt)" = "--no-tags" ] 21 | [ -z "$(git -C git-get/xsub config --get remote.origin.mirror)" ] 22 | [ "$(git -C git-get/xsub config --get remote.origin.fetch)" = "+refs/heads/*:refs/remotes/origin/*" ] 23 | [ "$(git -C git-get/xsub rev-parse HEAD~)" = "e7b2ae86f8574a1e16c71150ec538d102e574ca5" ] 24 | [ "$(git -C git-get/xsub rev-parse refs/heads/example-repo0 -- || echo good)" = "good" ] 25 | [ "$(git -C git-get/xsub rev-parse refs/remotes/origin/example-repo0)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 26 | [ "$(git -C git-get/xsub rev-parse refs/tags/example-tag -- || echo good)" = "good" ] 27 | ! git -C git-get/xsub symbolic-ref HEAD 28 | 29 | [ "$(git -C git-get/xsub/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 30 | [ "$(git -C git-get/xsub/sub config --get remote.origin.tagOpt)" = "--no-tags" ] 31 | [ -z "$(git -C git-get/xsub/sub config --get remote.origin.mirror)" ] 32 | [ "$(git -C git-get/xsub/sub config --get remote.origin.fetch)" = "+refs/heads/*:refs/remotes/origin/*" ] 33 | [ "$(git -C git-get/xsub/sub rev-parse refs/heads/example-repo0 -- || echo good)" = "good" ] 34 | [ "$(git -C git-get/xsub/sub rev-parse refs/remotes/origin/example-repo0)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 35 | [ "$(git -C git-get/xsub/sub rev-parse refs/tags/example-tag -- || echo good)" = "good" ] 36 | ! git -C git-get/xsub/sub symbolic-ref HEAD 37 | 38 | rm -rf git-get 39 | -------------------------------------------------------------------------------- /tests/git-gets/x.test: -------------------------------------------------------------------------------- 1 | R="$(git-gets b1f6c1c4/git-get example-repo2 -x)" 2 | 3 | [ -z "$R" ] 4 | [ "$(git -C git-get rev-parse HEAD)" = "2dd50b6425c7d79f4695aa69d05467e1a00fc20f" ] 5 | [ -z "$(git -C git-get config --get remote.origin.tagOpt)" ] 6 | [ -z "$(git -C git-get config --get remote.origin.mirror)" ] 7 | [ "$(git -C git-get config --get remote.origin.fetch)" = "+refs/heads/*:refs/remotes/origin/*" ] 8 | [ "$(git -C git-get symbolic-ref HEAD)" = "refs/heads/example-repo2" ] 9 | 10 | [ "$(git -C git-get/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 11 | [ -z "$(git -C git-get/sub config --get remote.origin.tagOpt)" ] 12 | [ -z "$(git -C git-get/sub config --get remote.origin.mirror)" ] 13 | [ "$(git -C git-get/sub config --get remote.origin.fetch)" = "+refs/heads/*:refs/remotes/origin/*" ] 14 | [ "$(git -C git-get/sub rev-parse refs/heads/example-repo0 -- || echo good)" = "good" ] 15 | [ "$(git -C git-get/sub rev-parse refs/remotes/origin/example-repo0)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 16 | [ "$(git -C git-get/sub rev-parse refs/tags/example-tag)" = "f774e3273eae40457109d04b0b5c5504047fac9d" ] 17 | ! git -C git-get/sub symbolic-ref HEAD 18 | 19 | [ "$(git -C git-get/xsub rev-parse HEAD)" = "2c0d59d84b729758f978c827a47980946f9a0e99" ] 20 | [ -z "$(git -C git-get/xsub config --get remote.origin.tagOpt)" ] 21 | [ -z "$(git -C git-get/xsub config --get remote.origin.mirror)" ] 22 | [ "$(git -C git-get/xsub config --get remote.origin.fetch)" = "+refs/heads/*:refs/remotes/origin/*" ] 23 | [ "$(git -C git-get/xsub rev-parse HEAD~)" = "e7b2ae86f8574a1e16c71150ec538d102e574ca5" ] 24 | [ "$(git -C git-get/xsub rev-parse refs/heads/example-repo0 -- || echo good)" = "good" ] 25 | [ "$(git -C git-get/xsub rev-parse refs/remotes/origin/example-repo0)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 26 | [ "$(git -C git-get/xsub rev-parse refs/tags/example-tag)" = "f774e3273eae40457109d04b0b5c5504047fac9d" ] 27 | ! git -C git-get/xsub symbolic-ref HEAD 28 | 29 | [ "$(git -C git-get/xsub/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 30 | [ -z "$(git -C git-get/xsub/sub config --get remote.origin.tagOpt)" ] 31 | [ -z "$(git -C git-get/xsub/sub config --get remote.origin.mirror)" ] 32 | [ "$(git -C git-get/xsub/sub config --get remote.origin.fetch)" = "+refs/heads/*:refs/remotes/origin/*" ] 33 | [ "$(git -C git-get/xsub/sub rev-parse refs/heads/example-repo0 -- || echo good)" = "good" ] 34 | [ "$(git -C git-get/xsub/sub rev-parse refs/remotes/origin/example-repo0)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 35 | [ "$(git -C git-get/xsub/sub rev-parse refs/tags/example-tag)" = "f774e3273eae40457109d04b0b5c5504047fac9d" ] 36 | ! git -C git-get/xsub/sub symbolic-ref HEAD 37 | 38 | rm -rf git-get 39 | -------------------------------------------------------------------------------- /tests/git-gets/x-parallel.test: -------------------------------------------------------------------------------- 1 | R="$(git-gets b1f6c1c4/git-get example-repo2 -xP)" 2 | 3 | [ -z "$R" ] 4 | [ "$(git -C git-get rev-parse HEAD)" = "2dd50b6425c7d79f4695aa69d05467e1a00fc20f" ] 5 | [ -z "$(git -C git-get config --get remote.origin.tagOpt)" ] 6 | [ -z "$(git -C git-get config --get remote.origin.mirror)" ] 7 | [ "$(git -C git-get config --get remote.origin.fetch)" = "+refs/heads/*:refs/remotes/origin/*" ] 8 | [ "$(git -C git-get symbolic-ref HEAD)" = "refs/heads/example-repo2" ] 9 | 10 | [ "$(git -C git-get/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 11 | [ -z "$(git -C git-get/sub config --get remote.origin.tagOpt)" ] 12 | [ -z "$(git -C git-get/sub config --get remote.origin.mirror)" ] 13 | [ "$(git -C git-get/sub config --get remote.origin.fetch)" = "+refs/heads/*:refs/remotes/origin/*" ] 14 | [ "$(git -C git-get/sub rev-parse refs/heads/example-repo0 -- || echo good)" = "good" ] 15 | [ "$(git -C git-get/sub rev-parse refs/remotes/origin/example-repo0)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 16 | [ "$(git -C git-get/sub rev-parse refs/tags/example-tag)" = "f774e3273eae40457109d04b0b5c5504047fac9d" ] 17 | ! git -C git-get/sub symbolic-ref HEAD 18 | 19 | [ "$(git -C git-get/xsub rev-parse HEAD)" = "2c0d59d84b729758f978c827a47980946f9a0e99" ] 20 | [ -z "$(git -C git-get/xsub config --get remote.origin.tagOpt)" ] 21 | [ -z "$(git -C git-get/xsub config --get remote.origin.mirror)" ] 22 | [ "$(git -C git-get/xsub config --get remote.origin.fetch)" = "+refs/heads/*:refs/remotes/origin/*" ] 23 | [ "$(git -C git-get/xsub rev-parse HEAD~)" = "e7b2ae86f8574a1e16c71150ec538d102e574ca5" ] 24 | [ "$(git -C git-get/xsub rev-parse refs/heads/example-repo0 -- || echo good)" = "good" ] 25 | [ "$(git -C git-get/xsub rev-parse refs/remotes/origin/example-repo0)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 26 | [ "$(git -C git-get/xsub rev-parse refs/tags/example-tag)" = "f774e3273eae40457109d04b0b5c5504047fac9d" ] 27 | ! git -C git-get/xsub symbolic-ref HEAD 28 | 29 | [ "$(git -C git-get/xsub/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 30 | [ -z "$(git -C git-get/xsub/sub config --get remote.origin.tagOpt)" ] 31 | [ -z "$(git -C git-get/xsub/sub config --get remote.origin.mirror)" ] 32 | [ "$(git -C git-get/xsub/sub config --get remote.origin.fetch)" = "+refs/heads/*:refs/remotes/origin/*" ] 33 | [ "$(git -C git-get/xsub/sub rev-parse refs/heads/example-repo0 -- || echo good)" = "good" ] 34 | [ "$(git -C git-get/xsub/sub rev-parse refs/remotes/origin/example-repo0)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 35 | [ "$(git -C git-get/xsub/sub rev-parse refs/tags/example-tag)" = "f774e3273eae40457109d04b0b5c5504047fac9d" ] 36 | ! git -C git-get/xsub/sub symbolic-ref HEAD 37 | 38 | rm -rf git-get 39 | -------------------------------------------------------------------------------- /tests/git-gets/sm.test: -------------------------------------------------------------------------------- 1 | git clone --depth=2 --no-tags --branch example-repo2 https://github.com/b1f6c1c4/git-get.git repo 2 | git -C repo update-ref refs/heads/whatever 1beea7d7bf112446f5a3beda9dfa8b51727a5ae1 3 | 4 | R="$(cd repo && git-gets)" 5 | 6 | [ -z "$R" ] 7 | [ "$(git -C repo config --get remote.origin.tagOpt)" = "--no-tags" ] 8 | [ "$(git -C repo rev-parse HEAD~~ -- || echo good)" = "good" ] 9 | [ "$(git -C repo rev-parse refs/heads/whatever)" = "1beea7d7bf112446f5a3beda9dfa8b51727a5ae1" ] 10 | [ "$(git -C repo symbolic-ref HEAD)" = "refs/heads/example-repo2" ] 11 | 12 | [ "$(git -C repo/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 13 | [ -z "$(git -C repo/sub config --get remote.origin.tagOpt)" ] 14 | [ -z "$(git -C repo/sub config --get remote.origin.mirror)" ] 15 | [ "$(git -C repo/sub config --get remote.origin.fetch)" = "+refs/heads/*:refs/remotes/origin/*" ] 16 | [ "$(git -C repo/sub rev-parse refs/heads/example-repo0 -- || echo good)" = "good" ] 17 | [ "$(git -C repo/sub rev-parse refs/remotes/origin/example-repo0)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 18 | [ "$(git -C repo/sub rev-parse refs/tags/example-tag)" = "f774e3273eae40457109d04b0b5c5504047fac9d" ] 19 | ! git -C repo/sub symbolic-ref HEAD 20 | 21 | [ "$(git -C repo/xsub rev-parse HEAD)" = "2c0d59d84b729758f978c827a47980946f9a0e99" ] 22 | [ -z "$(git -C repo/xsub config --get remote.origin.tagOpt)" ] 23 | [ -z "$(git -C repo/xsub config --get remote.origin.mirror)" ] 24 | [ "$(git -C repo/xsub config --get remote.origin.fetch)" = "+refs/heads/*:refs/remotes/origin/*" ] 25 | [ "$(git -C repo/xsub rev-parse HEAD~)" = "e7b2ae86f8574a1e16c71150ec538d102e574ca5" ] 26 | [ "$(git -C repo/xsub rev-parse refs/heads/example-repo0 -- || echo good)" = "good" ] 27 | [ "$(git -C repo/xsub rev-parse refs/remotes/origin/example-repo0)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 28 | [ "$(git -C repo/xsub rev-parse refs/tags/example-tag)" = "f774e3273eae40457109d04b0b5c5504047fac9d" ] 29 | ! git -C repo/xsub symbolic-ref HEAD 30 | 31 | [ "$(git -C repo/xsub/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 32 | [ -z "$(git -C repo/xsub/sub config --get remote.origin.tagOpt)" ] 33 | [ -z "$(git -C repo/xsub/sub config --get remote.origin.mirror)" ] 34 | [ "$(git -C repo/xsub/sub config --get remote.origin.fetch)" = "+refs/heads/*:refs/remotes/origin/*" ] 35 | [ "$(git -C repo/xsub/sub rev-parse refs/heads/example-repo0 -- || echo good)" = "good" ] 36 | [ "$(git -C repo/xsub/sub rev-parse refs/remotes/origin/example-repo0)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 37 | [ "$(git -C repo/xsub/sub rev-parse refs/tags/example-tag)" = "f774e3273eae40457109d04b0b5c5504047fac9d" ] 38 | ! git -C repo/xsub/sub symbolic-ref HEAD 39 | 40 | rm -rf repo 41 | -------------------------------------------------------------------------------- /tests/git-gets/sm-x.test: -------------------------------------------------------------------------------- 1 | git clone --depth=2 --no-tags --branch example-repo2 https://github.com/b1f6c1c4/git-get.git repo 2 | git -C repo update-ref refs/heads/whatever 1beea7d7bf112446f5a3beda9dfa8b51727a5ae1 3 | 4 | R="$(cd repo && git-gets -x)" 5 | 6 | [ -z "$R" ] 7 | [ "$(git -C repo config --get remote.origin.tagOpt)" = "--no-tags" ] 8 | [ "$(git -C repo rev-parse HEAD~~ -- || echo good)" = "good" ] 9 | [ "$(git -C repo rev-parse refs/heads/whatever)" = "1beea7d7bf112446f5a3beda9dfa8b51727a5ae1" ] 10 | [ "$(git -C repo symbolic-ref HEAD)" = "refs/heads/example-repo2" ] 11 | 12 | [ "$(git -C repo/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 13 | [ -z "$(git -C repo/sub config --get remote.origin.tagOpt)" ] 14 | [ -z "$(git -C repo/sub config --get remote.origin.mirror)" ] 15 | [ "$(git -C repo/sub config --get remote.origin.fetch)" = "+refs/heads/*:refs/remotes/origin/*" ] 16 | [ "$(git -C repo/sub rev-parse refs/heads/example-repo0 -- || echo good)" = "good" ] 17 | [ "$(git -C repo/sub rev-parse refs/remotes/origin/example-repo0)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 18 | [ "$(git -C repo/sub rev-parse refs/tags/example-tag)" = "f774e3273eae40457109d04b0b5c5504047fac9d" ] 19 | ! git -C repo/sub symbolic-ref HEAD 20 | 21 | [ "$(git -C repo/xsub rev-parse HEAD)" = "2c0d59d84b729758f978c827a47980946f9a0e99" ] 22 | [ -z "$(git -C repo/xsub config --get remote.origin.tagOpt)" ] 23 | [ -z "$(git -C repo/xsub config --get remote.origin.mirror)" ] 24 | [ "$(git -C repo/xsub config --get remote.origin.fetch)" = "+refs/heads/*:refs/remotes/origin/*" ] 25 | [ "$(git -C repo/xsub rev-parse HEAD~)" = "e7b2ae86f8574a1e16c71150ec538d102e574ca5" ] 26 | [ "$(git -C repo/xsub rev-parse refs/heads/example-repo0 -- || echo good)" = "good" ] 27 | [ "$(git -C repo/xsub rev-parse refs/remotes/origin/example-repo0)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 28 | [ "$(git -C repo/xsub rev-parse refs/tags/example-tag)" = "f774e3273eae40457109d04b0b5c5504047fac9d" ] 29 | ! git -C repo/xsub symbolic-ref HEAD 30 | 31 | [ "$(git -C repo/xsub/sub rev-parse HEAD)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 32 | [ -z "$(git -C repo/xsub/sub config --get remote.origin.tagOpt)" ] 33 | [ -z "$(git -C repo/xsub/sub config --get remote.origin.mirror)" ] 34 | [ "$(git -C repo/xsub/sub config --get remote.origin.fetch)" = "+refs/heads/*:refs/remotes/origin/*" ] 35 | [ "$(git -C repo/xsub/sub rev-parse refs/heads/example-repo0 -- || echo good)" = "good" ] 36 | [ "$(git -C repo/xsub/sub rev-parse refs/remotes/origin/example-repo0)" = "bff56f7a1c9585780950dce5c1964410e0aa2ecc" ] 37 | [ "$(git -C repo/xsub/sub rev-parse refs/tags/example-tag)" = "f774e3273eae40457109d04b0b5c5504047fac9d" ] 38 | ! git -C repo/xsub/sub symbolic-ref HEAD 39 | 40 | rm -rf repo 41 | -------------------------------------------------------------------------------- /man/git-gets.1: -------------------------------------------------------------------------------- 1 | .TH "GIT-GET" "1" "GIT_GET_DATE" "git-get" "git-get manual" 2 | .nh 3 | .SH "NAME" 4 | git-gets - Blazingly fast git clone alternative with submodules support 5 | .SH "SYNOPSIS" 6 | .sp 7 | .nf 8 | \fIgit gets\fR [] [||] \fB(1)\fR 9 | \fIgit gets\fR [] / [||] \fB(1)\fR 10 | \fIgit gets\fR [] \fB(2)\fR 11 | .fi 12 | .sp 13 | .SH "DESCRIPTION" 14 | .sp 15 | git-gets uses git(1) to \fB(1)\fR download a repo and its submodules from a remote repog; 16 | or \fB(2)\fR download submodules of an existing repo. 17 | Only minimium amount of data will be transferred. 18 | It cannot restrict itself to a single file or directory; use \fBgit-get\fR(1) if you only need a part of a repo. 19 | .SH "OPTIONS" 20 | .PP 21 | -X 22 | .RS 4 23 | Our recommended settings for keeping the repo, equivalent to \fB-xuBTP\fR. 24 | This might change in the future. 25 | .RE 26 | .PP 27 | -Y 28 | .RS 4 29 | Our recommended settings for compiling the repo, equivalent to \fB-tP\fR. 30 | This might change in the future. 31 | .RE 32 | .PP 33 | -V, --version 34 | .RS 4 35 | Show \fBgit-get\fR(1) version. 36 | .RE 37 | .PP 38 | -h, --help 39 | .RS 4 40 | Show documentation. 41 | .RE 42 | .PP 43 | -v, --verbose 44 | .RS 4 45 | Show intermediate steps. 46 | .RE 47 | .PP 48 | -q, --quiet 49 | .RS 4 50 | Hide every intermediate information but errors. 51 | This will suppress \fBgit-clone\fR(1) progress report. 52 | .RE 53 | .PP 54 | --color[=WHEN], --colour[=WHEN] 55 | .RS 4 56 | Surround important messages with escaping sequences to display them in color. WHEN is \fBnever\fR, \fBalways\fR, or \fB auto \fR. 57 | .RE 58 | .PP 59 | -s, --ssh, -H, --https 60 | .RS 4 61 | Switch between SSH protocol and HTTPS protocol when accessing GitHub. 62 | By default, ssh will be used to access github.com (including gist.github.com). 63 | However, SSH may fail if you are on a machine 64 | without any ssh keypair that can be used to connect to GitHub. 65 | You can manually change such behaviors by \fB-H\fR. 66 | Alternatively, setting environment variable \fBGH_USE_HTTPS\fR 67 | or \fBGH_USE_SSH\fR to any non-empty value has similar effects. 68 | Note that any access to non-GitHub remote repository is NOT affected. 69 | .RE 70 | .PP 71 | --no-recursive 72 | .RS 4 73 | Only the top-level submodules will be downloaded, don't recurse down. 74 | .RE 75 | .PP 76 | -o , --output= 77 | .RS 4 78 | Put the downloaded file or directory to . 79 | See \fB-F\fR options for overwrite policies. 80 | Only valid in form \fB(1)\fR. 81 | .RE 82 | .PP 83 | -F, --rm-rf 84 | .RS 4 85 | If is an existing directory, 86 | you may override the directory with \fB-F\fR. 87 | Otherwise \fBgit-gets\fR(1) will fail. 88 | Only valid in form \fB(1)\fR. 89 | .RE 90 | .PP 91 | -x 92 | .RS 4 93 | Preserve and enhance the \fB.git\fR directory to 94 | make the downloaded repository look as similar as one 95 | created by an ordinary \fBgit clone\fR at the cost of a little bit 96 | more network bandwidth and disk space. 97 | This option is only usable in form \fB(1)\fR. 98 | You cannot use it together with \fB-g\fR nor \fB-t\fR. 99 | Specifically, using \fB-x\fR has the following effects: 100 | .IP \[bu] 2 101 | All commits will be downloaded: you can still view the full history 102 | when doing a normal \fBgit log\fR. 103 | .IP \[bu] 104 | All trees and blobs will be lazy loaded: they won't be downloaded 105 | until you explicitly checkout / switch / show it. 106 | Thus, running \fBgit log -p\fR or \fBgit log --stat\fR WITHOUT ANY RESTRICTION 107 | will trigger downloading the WHOLE REPOSITORY, an absolute disaster. 108 | .IP \[bu] 109 | \fBgit fetch\fR, \fBgit pull\fR, and \fBgit push\fR will behave (mostly) normal, 110 | instead of mirroring by default. 111 | To take a deeper look on this, please read the following reference: 112 | .I git-partial-clone 113 | .UR https://git-scm.com/docs/partial-clone 114 | .UE . 115 | .RE 116 | .PP 117 | -B, --single-branch 118 | .RS 4 119 | Cleanup unnecessary remote-tracking branches except those explicitly 120 | specified in the command line. 121 | Only makes sense when \fB-x\fR is enabled. 122 | .RE 123 | .PP 124 | -T, --no-tags 125 | .RS 4 126 | Cleanup all tags, including those explicitly specified in the command line. 127 | Only makes sense when \fB-x\fR is enabled. 128 | .RE 129 | .PP 130 | -g, --preserve-git 131 | .RS 4 132 | Preserve the \fB.git\fR directory, but don't do anything superfluous 133 | that may waste network bandwidth. 134 | Compared to \fB-x\fR, using this option will not incur any additional 135 | cost compared to that with neither of \fB-x\fR nor \fB-g\fR. 136 | However, the actual respository may not be as exploitable as before. 137 | See the discussion of \fB-x\fR to see the difference. 138 | You cannot use it together with \fB-x\fR nor \fB-t\fR. 139 | .RE 140 | .PP 141 | -u, --upstream 142 | .RS 4 143 | In addition to origin, add a remote reference to the cloned repository's 144 | upstream repository. Only possible when \fB-x\fR is enabled. 145 | Currently only repositories from github.com are supported. 146 | .RE 147 | .PP 148 | -t, --tag-file=VERSION 149 | .RS 4 150 | These options are only valid in form \fB(1)\fR. 151 | Enable the generation of tag file by specifying \fB-t\fR. 152 | Rename and relocate the tag file by specifying \fB--tag-file\fR (which implies \fB-t\fR.) 153 | Tag file is a file, usually named VERSION, that is put along side with your downloaded file or inside your downloaded directory. 154 | It records the SHA-1 of the commit you downloaded it from. 155 | Without this file and without \fB.git\fR repo, others will lose track of where the code came from. 156 | You cannot use it together with \fB-g\fR. 157 | .RE 158 | .PP 159 | -P, --parallel 160 | .RS 4 161 | Launch multiple instances of \fBgit-clone\fR(1) to speed things up. 162 | .RE 163 | .PP 164 | -c, --confirm 165 | .RS 4 166 | Prompt the user before downloading a submodule. 167 | .RE 168 | .PP 169 | --no-init 170 | .RS 4 171 | Do not call \fBgit-submodule init\fR so that only the submodules that have already been inited will be downloaded. 172 | All second-level submodules will, however, still be inited and downloaded unless you specified \fB--no-recursive\fR. 173 | Only valid in form \fB(2)\fR. 174 | .RE 175 | .SH "EXAMPLES" 176 | .PP 177 | Download a repo and submodules: 178 | .sp 179 | .if n \{\ 180 | .RS 4 181 | .\} 182 | .nf 183 | Method 1: Paste the original URL into the terminal: 184 | $ git gets https://github.com/b1f6c1c4/git-get 185 | Method 2: Type a few words in the terminal: 186 | $ git gets b1f6c1c4/git-get 187 | .sp 188 | If you want it to be even faster: 189 | $ git gets -P ... 190 | .sp 191 | If you want to make changes and push back: 192 | $ git gets -x ... 193 | .fi 194 | .if n \{\ 195 | .RE 196 | .\} 197 | .RE 198 | .PP 199 | You already have a repo, and you want its submodules: 200 | (Usually you will need \fB-x\R, but that's not required) 201 | .sp 202 | .if n \{\ 203 | .RS 4 204 | .\} 205 | .nf 206 | $ git gets # Just give me all 207 | $ git gets -c # Let me choose 208 | $ git gets --no-init # Only those with 'git submodule init ...' 209 | .fi 210 | .if n \{\ 211 | .RE 212 | .\} 213 | .RE 214 | .SH "VARIABLES" 215 | .PP 216 | GH_USE_HTTPS 217 | .RS 4 218 | When called in the minimalistic / form, 219 | clone from https://github.com instead of git@github.com. 220 | Helpful if there isn't an SSH key. 221 | .RE 222 | .SH "SEE ALSO" 223 | .sp 224 | \fBgit-get\fR(1) \fBgit-clone\fR(1) 225 | .SH "GIT-GET" 226 | .sp 227 | Part of the \fBgit-get\fR(1) suite, version GIT_GET_VERSION 228 | -------------------------------------------------------------------------------- /man/git-get.1: -------------------------------------------------------------------------------- 1 | .TH "GIT-GET" "1" "GIT_GET_DATE" "git-get" "git-get manual" 2 | .nh 3 | .SH "NAME" 4 | git-get - Blazingly fast, incredibly handy git clone alternative 5 | .SH "SYNOPSIS" 6 | .sp 7 | .nf 8 | \fIgit get\fR [] [||] [-- []] 9 | \fIgit get\fR [] / [||] [-- []] 10 | \fIgit get\fR [] https://github.com///... [--] 11 | .fi 12 | .sp 13 | .SH "DESCRIPTION" 14 | .sp 15 | git-get uses git(1) to download a single file, directory, or repo from a remote repo. 16 | Only minimium amount of data will be transferred. 17 | It doesn't take care of git submodules; use \fBgit-gets\fR(1) if you want to interact with submodules. 18 | However, if \fB\fR is inside a submodule, \fBgit-get\fR(1) recursively calls itself 19 | to handle this situation automatically. 20 | .sp 21 | If the command line ends with a \fB--\fR, \fBgit-sparse-checkout\fR(1) will be used to reduce network and disk usage. 22 | You would need to manually invoke \fIgit sparse-checkout add \fR to checkout the directories you want after \fBgit-get\fR. 23 | .SH "OPTIONS" 24 | .PP 25 | -X 26 | .RS 4 27 | Our recommended settings for keeping the repo, equivalent to \fB-xuBT\fR. 28 | This might change in the future. 29 | .RE 30 | .PP 31 | -Y 32 | .RS 4 33 | Our recommended settings for compiling the repo, equivalent to \fB-t\fR. 34 | This might change in the future. 35 | .RE 36 | .PP 37 | -V, --version 38 | .RS 4 39 | Show \fBgit-get\fR(1) version. 40 | .RE 41 | .PP 42 | -h, --help 43 | .RS 4 44 | Show documentation. 45 | .RE 46 | .PP 47 | -v, --verbose 48 | .RS 4 49 | Show intermediate steps. 50 | .RE 51 | .PP 52 | -q, --quiet 53 | .RS 4 54 | Hide every intermediate information but errors. 55 | This will suppress \fBgit-clone\fR(1) progress report. 56 | .RE 57 | .PP 58 | --color[=WHEN], --colour[=WHEN] 59 | .RS 4 60 | Surround important messages with escaping sequences to display them in color. WHEN is \fBnever\fR, \fBalways\fR, or \fB auto \fR. 61 | .RE 62 | .PP 63 | -s, --ssh, -H, --https 64 | .RS 4 65 | Switch between SSH protocol and HTTPS protocol when accessing GitHub. 66 | By default, ssh will be used to access github.com (including gist.github.com). 67 | However, SSH may fail if you are on a machine 68 | without any ssh keypair that can be used to connect to GitHub. 69 | You can manually change such behaviors by \fB-H\fR. 70 | Alternatively, setting environment variable \fBGH_USE_HTTPS\fR 71 | or \fBGH_USE_SSH\fR to any non-empty value has similar effects. 72 | Note that any access to non-GitHub remote repository is NOT affected. 73 | .RE 74 | .PP 75 | -o , --output= 76 | .RS 4 77 | Put the downloaded file or directory to . 78 | See \fB-f\fR and \fB-F\fR options for overwrite policies. 79 | .RE 80 | .PP 81 | -f, --force, -F, --rm-rf 82 | .RS 4 83 | \fB-f\fR is synonymous with \fB--force\fR. 84 | \fB-F\fR is synonymous with \fB--rm-rf\fR. 85 | \fB-F\fR implies \fB-f\fR. 86 | If you downloaded a file/directory and is an existing file, 87 | you may override the file with \fB-f\fR. 88 | If you downloaded a file and is an existing directory, 89 | the file is put into the directory. 90 | If you downloaded a directory and is an existing directory, 91 | you may override the directory with \fB-F\fR. 92 | In no case will a directory be put into an existing directory. 93 | .RE 94 | .PP 95 | -x 96 | .RS 4 97 | Preserve and enhance the \fB.git\fR directory to 98 | make the downloaded repository look as similar as one 99 | created by an ordinary \fBgit clone\fR at the cost of a little bit 100 | more network bandwidth and disk space. 101 | You cannot use it together with \fB-g\fR nor \fB-t\fR. 102 | Besides, you cannot use \fB-- \fR when \fB-x\fR is set. 103 | Specifically, using \fB-x\fR has the following effects: 104 | .IP \[bu] 2 105 | All commits will be downloaded: you can still view the full history 106 | when doing a normal \fBgit log\fR. 107 | .IP \[bu] 108 | All trees and blobs will be lazy loaded: they won't be downloaded 109 | until you explicitly checkout / switch / show it. 110 | Thus, running \fBgit log -p\fR or \fBgit log --stat\fR WITHOUT ANY RESTRICTION 111 | will trigger downloading the WHOLE REPOSITORY, an absolute disaster. 112 | .IP \[bu] 113 | \fBgit fetch\fR, \fBgit pull\fR, and \fBgit push\fR will behave (mostly) normal, 114 | instead of mirroring by default. 115 | .PP 116 | To take a deeper look on this, please read the following reference: 117 | .I git-partial-clone 118 | .UR https://git-scm.com/docs/partial-clone 119 | .UE . 120 | .RE 121 | .PP 122 | -B, --single-branch 123 | .RS 4 124 | Cleanup unnecessary remote-tracking branches except those explicitly 125 | specified in the command line. 126 | Only makes sense when \fB-x\fR is enabled. 127 | .RE 128 | .PP 129 | -T, --no-tags 130 | .RS 4 131 | Cleanup all tags, including those explicitly specified in the command line. 132 | Only makes sense when \fB-x\fR is enabled. 133 | .RE 134 | .PP 135 | -g, --preserve-git 136 | .RS 4 137 | Preserve the \fB.git\fR directory, but don't do anything superfluous 138 | that may waste network bandwidth. 139 | Compared to \fB-x\fR, using this option will not incur any additional 140 | cost compared to that with neither of \fB-x\fR nor \fB-g\fR. 141 | However, the actual respository may not be as exploitable as before. 142 | See the discussion of \fB-x\fR to see the difference. 143 | You cannot use it together with \fB-x\fR nor \fB-t\fR. 144 | Besides, you cannot use \fB-- \fR when \fB-g\fR is set. 145 | .RE 146 | .PP 147 | -u, --upstream 148 | .RS 4 149 | In addition to origin, add a remote reference to the cloned repository's 150 | upstream repository. Only possible when \fB-x\fR is enabled. 151 | Currently only repositories from github.com are supported. 152 | .RE 153 | .PP 154 | -t, --tag-file=VERSION 155 | .RS 4 156 | Enable the generation of tag file by specifying \fB-t\fR. 157 | Rename and relocate the tag file by specifying \fB--tag-file\fR (which implies \fB-t\fR.) 158 | Tag file is a file, usually named VERSION, that is put along side with your downloaded file or inside your downloaded directory. 159 | It records the SHA-1 of the commit you downloaded it from. 160 | Without this file and without \fB.git\fR repo, others will lose track of where the code came from. 161 | You cannot use it together with \fB-x\fR nor \fB-g\fR. 162 | .RE 163 | .SH "EXAMPLES" 164 | .PP 165 | Download a file: 166 | .sp 167 | .if n \{\ 168 | .RS 4 169 | .\} 170 | .nf 171 | Method 1: Paste the original URL into the terminal: 172 | $ git get https://github.com/b1f6c1c4/git-get/blob/master/README.md 173 | .sp 174 | Method 2: Of course, a full URL is acceptable: 175 | $ git get git@github.com:b1f6c1c4/git-get -- README.md 176 | .sp 177 | Method 3a: Type a few words in the terminal: 178 | $ git get b1f6c1c4/git-get -- README.md 179 | .sp 180 | Method 3b: If the above doesn't work because of SSH, use HTTPS: 181 | $ git get -H b1f6c1c4/git-get -- README.md 182 | .fi 183 | .if n \{\ 184 | .RE 185 | .\} 186 | .RE 187 | .PP 188 | Download a folder: 189 | .sp 190 | .if n \{\ 191 | .RS 4 192 | .\} 193 | .nf 194 | The same as before: 195 | $ git get https://github.com/b1f6c1c4/git-get/tree/master/tests 196 | $ git get b1f6c1c4/git-get -- tests 197 | .sp 198 | Optionally, you may want a VERSION file to record the commit SHA1: 199 | $ git get -t ... 200 | .fi 201 | .if n \{\ 202 | .RE 203 | .\} 204 | .RE 205 | .PP 206 | Download a repo/branch/tag/commit: 207 | .sp 208 | .if n \{\ 209 | .RS 4 210 | .\} 211 | .nf 212 | Also the same: 213 | $ git get https://github.com/b1f6c1c4/git-get 214 | $ git get https://github.com/b1f6c1c4/git-get/tree/example-repo2 215 | $ git get https://github.com/b1f6c1c4/git-get/commit/2dd50b6 216 | $ git get b1f6c1c4/git-get 217 | $ git get b1f6c1c4/git-get example-repo2 218 | $ git get b1f6c1c4/git-get 2dd50b6 219 | 220 | You may wonder where did the .git go. 221 | We automatically 'rm -rf .git' for you because in 95% of the cases 222 | you won't even look at it. But if you really want your .git back: 223 | $ git get -x ... 224 | .fi 225 | .if n \{\ 226 | .RE 227 | .\} 228 | .RE 229 | .PP 230 | Download a file/folder of a branch/tag/commit: 231 | .sp 232 | .if n \{\ 233 | .RS 4 234 | .\} 235 | .nf 236 | Combine what you've learned before: 237 | $ git get https://github.com/b1f6c1c4/git-get/blob/example-repo2/file 238 | $ git get https://github.com/b1f6c1c4/git-get/tree/example-repo2/dir 239 | $ git get b1f6c1c4/git-get example-repo2 -- file 240 | $ git get b1f6c1c4/git-get example-repo2 -- dir 241 | .sp 242 | You \fBcannot\fR do -x and -t at the same time: 243 | # git get -xt ... # Error!!! 244 | .fi 245 | .if n \{\ 246 | .RE 247 | .\} 248 | .RE 249 | .SH "VARIABLES" 250 | .PP 251 | GH_USE_HTTPS 252 | .RS 4 253 | When called in the minimalistic / form, 254 | clone from https://github.com instead of git@github.com. 255 | Helpful if there isn't an SSH key. 256 | .RE 257 | .SH "SEE ALSO" 258 | .sp 259 | \fBgit-gets\fR(1) \fBgit-clone\fR(1) 260 | .SH "GIT-GET" 261 | .sp 262 | Part of the \fBgit-get\fR(1) suite, version GIT_GET_VERSION 263 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `git-get`: Blazingly fast, incredibly handy `git clone` 2 | 3 | [![Appveyor](https://img.shields.io/appveyor/build/b1f6c1c4/git-get?style=flat-square)](https://ci.appveyor.com/project/b1f6c1c4/git-get/build/master) 4 | [![Coveralls](https://img.shields.io/coveralls/github/b1f6c1c4/git-get?style=flat-square)](https://coveralls.io/github/b1f6c1c4/git-get) 5 | 6 | - ✅ Automatic shallow clone 7 | - ✅ Automatic partial clone 8 | - ✅ Single file/directory clone, even crossing submodule boundaries 9 | - ✅ Arbitrary clone given commit SHA1 10 | - ✅ Fast parallel submodules clone 11 | - ✅ Interactive submodules clone selection 12 | - ✅ Full `git sparse-checkout` support 13 | - ✅ Optional single branch/tag clone 14 | - ✅ Tag file `VERSION` 15 | - ✅ Automatic origin + upstream clone (for GitHub only) 16 | 17 | ## TL;DR 18 | 19 | - Download a file: 20 | ```bash 21 | # Method 1: Paste the original URL into the terminal: 22 | git get https://github.com/b1f6c1c4/git-get/blob/master/README.md 23 | # Method 2: Of course, a full URL is acceptable: 24 | git get git@github.com:b1f6c1c4/git-get.git -- README.md 25 | # Method 3a: Type a few words in the terminal: 26 | git get b1f6c1c4/git-get -- README.md 27 | # Method 3b: If the above doesn't work because of SSH, use HTTPS: 28 | git get -H b1f6c1c4/git-get -- README.md 29 | ``` 30 | - Download a folder: 31 | ```bash 32 | # The same as before: 33 | git get https://github.com/b1f6c1c4/git-get/tree/master/tests 34 | git get b1f6c1c4/git-get -- tests 35 | # Optionally, you may want a VERSION file to record the commit SHA1: 36 | git get -t ... 37 | ``` 38 | - Download a repo: 39 | ```bash 40 | git get[s] [-X|-Y] https://github.com/b1f6c1c4/git-get 41 | git get[s] [-X|-Y] https://github.com/b1f6c1c4/git-get/tree/example-repo2 42 | git get[s] [-X|-Y] https://github.com/b1f6c1c4/git-get/commit/2dd50b6 43 | git get[s] [-X|-Y] b1f6c1c4/git-get 44 | git get[s] [-X|-Y] b1f6c1c4/git-get example-repo2 45 | git get[s] [-X|-Y] b1f6c1c4/git-get 2dd50b6 46 | ``` 47 | - __`s`__ to include submodules 48 | - Depending on the scenario, use __one__ of the following: 49 | - __`-X`__: clone a repo and make changes 50 | - __`-Y`__: download a repo to compile it 51 | - You already have a cloned repo, and you want its submodules: 52 | ```bash 53 | git gets # Just give me all 54 | git gets -c # Let me choose 55 | git gets --no-init # Only those with 'git submodule init ...' 56 | ``` 57 | 58 | ## Performance 59 | 60 | ```bash 61 | git get -t 62 | # is 1x~10000x faster than: 63 | # git clone repo 64 | # git -C repo rev-parse HEAD > repo/VERSION 65 | # rm -rf repo/.git 66 | 67 | git get -o -- 68 | # is 1x~1000000x faster than: 69 | # git clone repo 70 | # git -C repo submodule update --init --recursive 71 | # cp repo/ && rm -rf repo 72 | 73 | git get -- 74 | # is 1x~1000000000x faster than: 75 | # git clone --mirror repo 76 | # git -C repo switch --detach 77 | # rm -rf repo/.git 78 | 79 | git gets -P 80 | # is 1x~10000000x faster than: 81 | # git clone --mirror repo 82 | # git -C repo switch --detach 83 | # git -C repo submodule update --init --recursive 84 | # rm -rf repo/**/.git 85 | 86 | # If you already have a repo and want to inflate all its submodules: 87 | git gets 88 | # is 1x~10000000x faster than (and 8x shorter to type): 89 | # git submodule update --init --recursive 90 | ``` 91 | 92 | ## Why we need it, and why is it so fast? 93 | 94 | ### A brief but lengthened story of `git clone` performance 95 | 96 | So many times we want to download something hosted on GitHub. 97 | What we actually want is a complete working copy of the code and configurations, 98 | without any development history or irrelavent informations. 99 | Once upon a time, there were only two ways to retrieve data from git/GitHub: 100 | 101 | 1. Simply call `git clone`. 102 | Well, by default `git` downloads the entire development history. 103 | Some huge projects can have 100,000 commits, each with 1GiB files. 104 | Even though there are some duplicated files that saves some space, 105 | this is **totally undesirable unless you are one of the developer**. 106 | 107 | 1. On GitHub, click `Clone or download`/`Download ZIP`. 108 | OK, now we only have what we want downloaded. 109 | But is that complete? What about `git submodule`s? 110 | Some huge projects can have more than 30 nested submodules. 111 | Are you willing to download one by another with your own hands? 112 | This is **only applicable if there is no or very few submodules**. 113 | 114 | 1. On GitHub, click `Raw` button when displaying a file. 115 | OK, but it only works for a single file. 116 | Are you willing to download one by another with your own hands? 117 | This is **only applicable if you need up to a few files**. 118 | 119 | Some time later, `git` has improved. 120 | 121 | 1. We now have `git clone --depth=1`: to clone the very first commit of a branch. 122 | But some problems also arose: 123 | We cannot get a specific commit buried inside the development history. 124 | This may not be a problem for big matured project where there 125 | people only need to look for its tags and branches. 126 | However, we frequently need to retrieve a specified version of a repo, 127 | especially when we are using `git submodule`. 128 | Long words short, `--depth=1` works well for the parent repo, 129 | but dysfunctions so frequently when working with submodules. 130 | 131 | And even later, in 2018, `git` improved again. 132 | 133 | 1. We now have `git clone --filter tree:0`: to clone commits eagerly but files lazily. 134 | That's a great improvement! 135 | But GitHub hadn't been offering support for `--filter` until 2019. 136 | So, now, we have all the tools necessary to download whatever you what from GitHub! 137 | 138 | ### Benefits of using `git-get` 139 | 140 | 1. It leverages both `--depth` and `--filter` to save bandwidth. 141 | Only the files you actually want (that commit that file) are downloaded. 142 | No entire development history. 143 | No entire repository folder. 144 | Remember, this applies to the parent repo as well as all sub repos. 145 | 1. It handles `git submodule`s very well. 146 | Just tell `git-get` the path of your file with respect to the parent repo. 147 | `git-get` will recursively scan through the submodule chain and grab the file for you. 148 | 1. It handles optional dependencies also pretty well: 149 | Some project specifies optional dependencies as submodules. 150 | If you want to download some submodules but not the others, 151 | just add `-c|--confirm` to `git-gets` and you can 152 | interactively choose which dependency you want to install. 153 | 154 | ## Basic Usage 155 | 156 | The CLI is pretty self-explanatory: 157 | 158 | ```bash 159 | # There are multiple ways to specify what you want to download: 160 | := 161 | 162 | | / [|] 163 | | https://github.com/// 164 | | https://github.com///commit/ 165 | | https://github.com///tree/[/] 166 | | https://github.com///blob/[/] 167 | 168 | # Download a single repo (or part of): 169 | git-get [-v|--verbose|-q|--quiet] [-s|--ssh | -H|--https] [-X|-Y] 170 | [-o ] [-f|--force] [-F|--rm-rf] 171 | (-x [-B] [-T] | [-t|--tag] [-- []]) 172 | 173 | # Download a repo and its submodules: 174 | git gets [-v|--verbose|-q|--quiet] [-s|--ssh | -H|--https] [-X|-Y] 175 | [-P|--parallel] [-c|--confirm] [--no-recursive] 176 | [-o ] [-F|--rm-rf] 177 | (-x [-B] [-T] | [-t|--tag]) 178 | 179 | # Download submodules of an existing repo: 180 | git gets [-v|--verbose|-q|--quiet] [-s|--ssh | -H|--https] [-X|-Y] 181 | [-P|--parallel] [-c|--confirm] [--no-recursive] [--no-init] 182 | ``` 183 | 184 | Some comments: 185 | 186 | * `-X`=`-xuBTP` for keep repo and make changes; `-Y`=`-tP` for compiling. 187 | 188 | * `-s|--ssh` and `-H|--https`: 189 | Override using HTTPS or SSH when accesssing github.com and gist.github.com 190 | in the case when you don't have a ready-to-use SSH or HTTPS set-up, 191 | 192 | * `-f|--force` and `-F|--rm-rf`: 193 | Override existing file with `-f|--force`. 194 | Override existing directory with `-F|--rm-rf`. 195 | 196 | * For `git-get`, leaving an empty `--` at the end creates a 197 | [sparse checkout](https://git-scm.com/docs/git-sparse-checkout) 198 | repo, cone mode. 199 | 200 | * `-x`, `-B|--single-branch`, and `-T|--no-tags`: 201 | `-x` will keep the `.git` so you can make changes. 202 | The repository is NOT 100% the same as a regular `git-clone`'d one, 203 | as only commits are fetched but not file contents. 204 | You cannot use it together with `-t|--tag`. 205 | To take a deeper look at the difference, please read the following reference: 206 | [git partial clone](https://git-scm.com/docs/partial-clone). 207 | For repos with many branches / git tags, specifying `-B` and/or `-T` will 208 | remove unused branches / git tags. 209 | 210 | * `-t|--tag`: 211 | Instead of keeping a respository, generate a single file called `VERSION` 212 | that contains the SHA-1 of the commit you accessed. 213 | Put it along side with your downloaded file or inside your downloaded directory 214 | so you will know from where the file/dir is obtained. 215 | You cannot use it together with `-x`. 216 | 217 | Not all options are shown here. 218 | For additional ones, refer to `man git-get` and `man git-gets`. 219 | 220 | ## Install and Upgrade 221 | 222 | (The upgrading process and install process are identical.) 223 | 224 | - Arch Linux 225 | 226 | It's on [AUR](https://aur.archlinux.org/packages/git-get): 227 | ```bash 228 | yay install git-get 229 | rua install git-get 230 | ... 231 | ``` 232 | 233 | - Linux but not Arch Linux 234 | 235 | We recommend that you download the latest release and untar the files: 236 | ```bash 237 | # Install git-get(1) globally: 238 | curl -fsSL https://github.com/b1f6c1c4/git-get/releases/latest/download/git-get.tar.xz | sudo tar -C /usr -xJv 239 | # Or, locally: 240 | mkdir -p ~/.local/ 241 | curl -fsSL https://github.com/b1f6c1c4/git-get/releases/latest/download/git-get.tar.xz | tar -C ~/.local/ -xJv 242 | ``` 243 | 244 | - MacOS 245 | 246 | ```bash 247 | # Install dependencies, including realpath(1): 248 | brew install coreutils 249 | # Install git-get(1) globally: 250 | curl -fsSL https://github.com/b1f6c1c4/git-get/releases/latest/download/git-get.tar.xz | sudo tar -C /usr/local -xJv 251 | # Or, locally: 252 | mkdir -p ~/.local/bin/ 253 | curl -fsSL https://github.com/b1f6c1c4/git-get/releases/latest/download/git-get.tar.xz | tar -C ~/.local/ -xJv 254 | ``` 255 | 256 | - Windows 257 | 258 | Similar as above, but you need to manually download the two files [git-get](https://github.com/b1f6c1c4/git-get/blob/master/git-get) and [git-gets](https://github.com/b1f6c1c4/git-get/blob/master/git-gets) and put it in `PATH`. As for the documentation, you will need to browse it online. 259 | 260 | You DO NOT need to setup `git config alias.get '!git-get'`. 261 | In fact, git is so smart that, as long as `git-get` is in `PATH`, `git ` will be interpreted as `git-`. 262 | 263 | ## Requirements 264 | 265 | * `bash`, can be `GNU bash` on Linux / MacOS, or `Git bash` on Windows 266 | * `git` **2.20+**, the newer the better 267 | * `sed`, and `grep` 268 | * On Linux: You should already have them installed. 269 | * On MacOS: You should already have them installed. 270 | * On Windows: 271 | ```bash 272 | choco install grep sed 273 | ``` 274 | * (optional) `curl` for `-u|--upstream` functionality 275 | * (optional) `kcov` for checking coverage 276 | 277 | ## License 278 | 279 | MIT 280 | -------------------------------------------------------------------------------- /git-get: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | GIT_GET_VERSION= 4 | 5 | if [ -z "$GH_USE_HTTPS" ]; then 6 | GH_USE_HTTPS= 7 | else 8 | GH_USE_HTTPS="$GH_USE_HTTPS" 9 | fi 10 | if [ -z "$GH_USE_SSH" ]; then 11 | GH_USE_SSH= 12 | else 13 | GH_USE_SSH="$GH_USE_SSH" 14 | fi 15 | 16 | if [ -z "$PREV_TAGS" ]; then 17 | PREV_TAGS= 18 | else 19 | PREV_TAGS="$PREV_TAGS" 20 | fi 21 | 22 | if [ -z "$OCWD" ]; then 23 | OCWD="$PWD" 24 | else 25 | OCWD="$OCWD" 26 | fi 27 | 28 | set -euo pipefail 29 | 30 | usage() 31 | { 32 | exec man git-get 33 | } 34 | 35 | git_new() { 36 | V="$(git version)" 37 | [[ "$V" =~ ^git[[:space:]]version[[:space:]]2\..\. ]] && return 1 38 | [[ "$V" =~ ^git[[:space:]]version[[:space:]]2\.1.\. ]] && return 1 39 | return 0 40 | } 41 | 42 | fakerealpath() { 43 | if [[ "$1" =~ ^/ ]]; then 44 | printf '%s' "$1" 45 | else 46 | printf '%s/%s' "$PWD" "$1" 47 | fi 48 | } 49 | 50 | normalize() { 51 | X="$1" 52 | ODIR= 53 | while [ ! "$X" = "$ODIR" ]; do 54 | ODIR="$X" 55 | # shellcheck disable=SC2016 56 | X="$(sed -E 's_//_/_g; s_/\./_/_g; s_[^/]+/\.\./_/_g; s_/$__g; s_^/__g; s_/\.$__g; s_^\./__g' <<<"$X")" 57 | done 58 | printf '%s' "$X" 59 | } 60 | 61 | COLOR= 62 | [ -t 2 ] && COLOR=YES 63 | 64 | QUIET= 65 | VERBOSE= 66 | FORCE= 67 | FORCE_DIR= 68 | OUTPUT= 69 | PRESERVE= 70 | TAG= 71 | TAG_FILE= 72 | DIR= 73 | SPARSE= 74 | UPSTREAM= 75 | CL_BRANCHES= 76 | CL_TAGS= 77 | POSITIONAL=() 78 | while [ $# -gt 0 ]; do 79 | case "$1" in 80 | -X) 81 | shift 82 | set -- -x -u -B -T "$@" 83 | ;; 84 | -Y) 85 | shift 86 | set -- -t "$@" 87 | ;; 88 | -V|--version) 89 | echo "git-get(1) $GIT_GET_VERSION" 90 | exit 91 | ;; 92 | -h|--help) 93 | usage 94 | exit 95 | ;; 96 | -q|--quiet) 97 | QUIET=--quiet 98 | shift 99 | ;; 100 | -v|--verbose) 101 | VERBOSE=YES 102 | shift 103 | ;; 104 | --color=never|--colour=never) 105 | COLOR= 106 | shift 107 | ;; 108 | --color=always|--colour=always) 109 | COLOR=YES 110 | shift 111 | ;; 112 | --color=auto|--colour=auto|--color|--colour) 113 | COLOR= 114 | [ -t 2 ] && COLOR=YES 115 | shift 116 | ;; 117 | -s|--ssh) 118 | GH_USE_SSH=YES 119 | shift 120 | ;; 121 | -H|--https) 122 | GH_USE_HTTPS=YES 123 | shift 124 | ;; 125 | -f|--force) 126 | FORCE=YES 127 | shift 128 | ;; 129 | -F|--rm-rf) 130 | FORCE=YES 131 | FORCE_DIR=YES 132 | shift 133 | ;; 134 | -o|--output) 135 | OUTPUT="$2" 136 | shift 137 | shift 138 | ;; 139 | -x) 140 | if [ "$PRESERVE" = G ]; then 141 | echo "Error: Conflict: -x and -g|--preserve-git" >&2 142 | exit 1 143 | fi 144 | PRESERVE=X 145 | shift 146 | ;; 147 | -B|--single-branch) 148 | CL_BRANCHES=YES 149 | shift 150 | ;; 151 | -T|--no-tags) 152 | CL_TAGS=YES 153 | shift 154 | ;; 155 | -g|--preserve-git) 156 | if [ "$PRESERVE" = X ]; then 157 | echo "Error: Conflict: -x and -g|--preserve-git" >&2 158 | exit 1 159 | fi 160 | PRESERVE=G 161 | shift 162 | ;; 163 | -u|--upstream) 164 | UPSTREAM=YES 165 | shift 166 | ;; 167 | -t|--tag) 168 | TAG=YES 169 | shift 170 | ;; 171 | --tag-file) 172 | TAG=YES 173 | TAG_FILE="$2" 174 | shift 175 | shift 176 | ;; 177 | --) 178 | if [ "$#" -eq 2 ]; then 179 | DIR="$2" 180 | shift 181 | shift 182 | elif [ "$#" -eq 1 ]; then 183 | DIR= 184 | SPARSE=YES 185 | shift 186 | else 187 | echo "Error: Only one allowed after --, I saw $*" >&2 188 | exit 1 189 | fi 190 | break 191 | ;; 192 | *) 193 | if [[ "$1" =~ ^--tag-file= ]]; then 194 | TAG=YES 195 | TAG_FILE="${1#--tag-file=}" 196 | elif [[ "$1" =~ ^--output= ]]; then 197 | OUTPUT="${1#--output=}" 198 | elif [[ "$1" =~ ^-o= ]]; then 199 | OUTPUT="${1#-o=}" 200 | elif [[ "$1" =~ ^-o ]]; then 201 | OUTPUT="${1#-o}" 202 | elif [[ "$1" =~ ^-.. ]]; then 203 | T="$1" 204 | shift 205 | set -- '' "${T:0:2}" "-${T:2}" "$@" 206 | elif [[ "$1" =~ ^- ]]; then 207 | echo "Error: Unrecognized argument $1" >&2 208 | exit 1 209 | else 210 | POSITIONAL+=("$1") 211 | fi 212 | shift 213 | ;; 214 | esac 215 | done 216 | 217 | if [ -n "$COLOR" ]; then 218 | C_ERR=$'\e[37;41m' 219 | C_WARN=$'\e[37;33m' 220 | C_NOTICE=$'\e[35m' 221 | C_INFO=$'\e[34m' 222 | C_DBG=$'\e[36m' 223 | C_RST=$'\e[0m' 224 | else 225 | C_ERR= 226 | C_WARN= 227 | C_NOTICE= 228 | C_INFO= 229 | C_DBG= 230 | C_RST= 231 | fi 232 | 233 | if [ -n "$PRESERVE" ] && [ -n "$TAG" ]; then 234 | echo "${C_ERR}Error: Conflict: -x|-g|--preserve-git and -t|--tag|--tag-file${C_RST}" >&2 235 | exit 1 236 | fi 237 | if [ -n "$PRESERVE" ] && [ -n "$DIR" ]; then 238 | echo "${C_ERR}Error: Conflict: -x|-g|--preserve-git and -- ${C_RST}" >&2 239 | echo "${C_NOTICE}Hint: You may consider git-get the whole repo with -- option first:" >&2 240 | echo " git get [-x|-g] [] --" >&2 241 | echo " and then manually:" >&2 242 | echo " git sparse-checkout add $DIR${C_RST}" >&2 243 | exit 1 244 | fi 245 | if [ -z "$PRESERVE" ] && [ -n "$SPARSE" ]; then 246 | echo "${C_ERR}Error: Conflict: -- requires -x|-g|--preserve-git${C_RST}" >&2 247 | exit 1 248 | fi 249 | if [ -n "$GH_USE_HTTPS" ] && [ -n "$GH_USE_SSH" ]; then 250 | echo "${C_ERR}Error: Conflict: GH_USE_HTTPS and GH_USE_SSH${C_RST}" >&2 251 | exit 1 252 | fi 253 | if [ -n "$CL_BRANCHES" ] && [ "$PRESERVE" != X ]; then 254 | echo "${C_ERR}Error: Conflict: --single-branch requires -x${C_RST}" >&2 255 | exit 1 256 | fi 257 | if [ -n "$CL_TAGS" ] && [ "$PRESERVE" != X ]; then 258 | echo "${C_ERR}Error: Conflict: --no-tags requires -x${C_RST}" >&2 259 | exit 1 260 | fi 261 | if [ -n "$UPSTREAM" ] && [ -z "$PRESERVE" ]; then 262 | echo "${C_ERR}Error: Conflict: --upstream requires -x${C_RST}" >&2 263 | exit 1 264 | fi 265 | 266 | if [ "$#" -gt 0 ]; then 267 | echo "${C_ERR}Error: Only one path allowed!${C_RST}" >&2 268 | exit 1 269 | fi 270 | 271 | if [ "${#POSITIONAL[@]}" -eq 0 ]; then 272 | echo "${C_ERR}Error: Must specify or / (GitHub)${C_RST}" 273 | exit 1 274 | elif [ "${#POSITIONAL[@]}" -eq 1 ]; then 275 | BRANCH="HEAD" 276 | elif [ "${#POSITIONAL[@]}" -eq 2 ]; then 277 | BRANCH="${POSITIONAL[1]}" 278 | else 279 | echo "${C_ERR}Error: Too many positional arguments, maybe you forgot -- before ?${C_RST}" >&2 280 | exit 1 281 | fi 282 | 283 | resolve_gh_url() { 284 | GITHUB=REPO 285 | AMBI= 286 | if grep -qE '^[^/]+/[^/]+$' <<<"$1"; then 287 | GH_REPO="${1%.git}" 288 | elif grep -qE '^[^/]+/[^/]+/commit/[0-9a-f]{4,40}$' <<<"$1"; then 289 | if [ "${#POSITIONAL[@]}" -ne 1 ]; then 290 | echo "${C_ERR}Error: Commit is already specified in the URL${C_RST}" >&2 291 | exit 1 292 | fi 293 | GH_REPO="$(grep -Eo '^[^/]+/[^/]+/commit/' <<<"$1")" 294 | GH_REPO="${GH_REPO%/commit/}" 295 | BRANCH="$(sed -E 's_^[^/]+/[^/]+/commit/__' <<<"$1")" 296 | elif grep -qE '^[^/]+/[^/]+/tree/' <<<"$1"; then 297 | if [ "${#POSITIONAL[@]}" -ne 1 ]; then 298 | echo "${C_ERR}Error: Branch is already specified in the URL${C_RST}" >&2 299 | exit 1 300 | fi 301 | GH_REPO="$(grep -Eo '^[^/]+/[^/]+/tree/' <<<"$1")" 302 | GH_REPO="${GH_REPO%/tree/}" 303 | BRANCH="$(sed -E 's_^[^/]+/[^/]+/tree/__' <<<"$1")" 304 | AMBI=VERY_MUCH 305 | elif grep -qE '^[^/]+/[^/]+/blob/' <<<"$1"; then 306 | if [ -n "$PRESERVE" ]; then 307 | echo "${C_ERR}Error: Conflict: -x|-g|--preserve-git and -- (in the URL)${C_RST}" >&2 308 | exit 1 309 | fi 310 | if [ "${#POSITIONAL[@]}" -ne 1 ]; then 311 | echo "${C_ERR}Error: Branch is already specified in the URL${C_RST}" >&2 312 | exit 1 313 | fi 314 | GH_REPO="$(grep -Eo '^[^/]+/[^/]+/blob/' <<<"$1")" 315 | GH_REPO="${GH_REPO%/blob/}" 316 | BRANCH="$(sed -E 's_^[^/]+/[^/]+/blob/__' <<<"$1")" 317 | AMBI=YES 318 | else 319 | echo "${C_ERR}Error: GitHub URL format not supported, only repo/tree/blob/commit will work${C_RST}" >&2 320 | exit 1 321 | fi 322 | 323 | if [ -n "$GH_USE_HTTPS" ]; then 324 | REPO="https://github.com/$GH_REPO.git" 325 | else 326 | REPO="git@github.com:$GH_REPO.git" 327 | fi 328 | 329 | if [ -n "$AMBI" ]; then 330 | while [[ "$BRANCH" =~ / ]]; do 331 | if [ -n "$(git ls-remote "$REPO" "$BRANCH")" ]; then 332 | break 333 | fi 334 | DIR="$(basename "$BRANCH")/$DIR" 335 | BRANCH="$(dirname "$BRANCH")" 336 | done 337 | fi 338 | unset AMBI 339 | } 340 | 341 | resolve_gist_url() { 342 | GITHUB=GIST 343 | BRANCH=master 344 | DIR= 345 | if [[ "$1" =~ \#file- ]]; then 346 | DIR="${1#*#file-}" 347 | GH_REPO="${1%%#*}" 348 | else 349 | GH_REPO="$1" 350 | fi 351 | if [[ "$GH_REPO" =~ / ]]; then 352 | GH_REPO="${GH_REPO#*/}" 353 | fi 354 | if [[ "$GH_REPO" =~ / ]]; then 355 | echo "${C_ERR}Error: GitHub Gist URL format not supported${C_RST}" >&2 356 | exit 1 357 | fi 358 | 359 | if [ -n "$GH_USE_HTTPS" ]; then 360 | REPO="https://gist.github.com/$GH_REPO.git" 361 | else 362 | REPO="git@gist.github.com:$GH_REPO.git" 363 | fi 364 | } 365 | 366 | match_gh_url() { 367 | [[ ! "${POSITIONAL[0]}" =~ ^$1 ]] && return 1 368 | [ -n "$2" ] && [ -z "$QUIET" ] && echo "${C_WARN}Warning: $1 is an unencryped protocol${C_RST}" >&2 369 | if [ -n "$3" ]; then 370 | "$3" "${POSITIONAL[0]#${1}}" YES 371 | else 372 | GITHUB=REPO 373 | GH_REPO="${POSITIONAL[0]#${1}}" 374 | GH_REPO="${GH_REPO%/}" 375 | GH_REPO="${GH_REPO%.git}" 376 | if [ -n "$GH_USE_HTTPS" ]; then 377 | REPO="https://github.com/$GH_REPO.git" 378 | elif [ -n "$GH_USE_SSH" ]; then 379 | REPO="git@github.com:$GH_REPO.git" 380 | else 381 | REPO="$1$GH_REPO.git" 382 | fi 383 | fi 384 | } 385 | 386 | match_gist_url() { 387 | [[ ! "${POSITIONAL[0]}" =~ ^$1 ]] && return 1 388 | [ -n "$2" ] && [ -z "$QUIET" ] && echo "${C_WARN}Warning: $1 is an unencryped protocol${C_RST}" >&2 389 | if [ -n "$3" ]; then 390 | "$3" "${POSITIONAL[0]#${1}}" 391 | else 392 | GITHUB=GIST 393 | GH_REPO="${POSITIONAL[0]#${1}}" 394 | GH_REPO="${GH_REPO%/}" 395 | GH_REPO="${GH_REPO%.git}" 396 | if [ -n "$GH_USE_HTTPS" ]; then 397 | REPO="https://gist.github.com/$GH_REPO.git" 398 | elif [ -n "$GH_USE_SSH" ]; then 399 | REPO="git@gist.github.com:$GH_REPO.git" 400 | else 401 | REPO="$1$GH_REPO.git" 402 | fi 403 | fi 404 | } 405 | 406 | match_gh_url "https://github.com/" '' resolve_gh_url || 407 | match_gh_url "http://github.com/" YES resolve_gh_url || 408 | match_gh_url "git://github.com/" YES '' || 409 | match_gh_url "ssh://git@github.com/" '' '' || 410 | match_gh_url "git@github.com:" '' '' || 411 | match_gist_url "https://gist.github.com/" '' resolve_gist_url || 412 | match_gist_url "http://gist.github.com/" YES resolve_gist_url || 413 | match_gist_url "git://gist.github.com/" YES '' || 414 | match_gist_url "ssh://git@gist.github.com/" '' '' || 415 | match_gist_url "git@gist.github.com:" '' '' || 416 | if [[ "${POSITIONAL[0]}" =~ : ]] || [[ "${POSITIONAL[0]}" =~ ^\. ]]; then 417 | GITHUB= 418 | GH_REPO= 419 | REPO="${POSITIONAL[0]}" 420 | else 421 | resolve_gh_url "${POSITIONAL[0]}" '' 422 | fi 423 | 424 | if [ -n "$PRESERVE" ] && [ -n "$DIR" ]; then 425 | echo "${C_ERR}Error: Can't use an URL (of a folder or file) with -x|-g|--preserve-git${C_RST}" >&2 426 | echo "${C_NOTICE}Hint: You may consider git-get the whole repo with -- option first:" >&2 427 | echo " git get [-x|-g] [] --" >&2 428 | echo " and then manually:" >&2 429 | echo " git sparse-checkout add $DIR${C_RST}" >&2 430 | exit 1 431 | fi 432 | 433 | if [ -n "$UPSTREAM" ]; then 434 | if [ "$GITHUB" != REPO ]; then 435 | [ -z "$QUIET" ] && echo "${C_WARN}Warning: -u is ignored because of lack of support for $REPO.${C_RST}" >&2 436 | UPSTREAM= 437 | elif ! which curl >/dev/null 2>/dev/null; then 438 | [ -z "$QUIET" ] && echo "${C_WARN}Warning: -u is ignored because curl(1) is not found in PATH.${C_RST}" >&2 439 | UPSTREAM= 440 | else 441 | set +e 442 | UPSTREAM="$(curl -fsL -H "Accept: application/vnd.github+json" "https://api.github.com/repos/$GH_REPO" \ 443 | | sed -nE '/^ "full_name": /{ 444 | s/^ "full_name": "(.*)",$/\1/ 445 | p 446 | q 447 | }')" 448 | set -e 449 | if [ -z "$UPSTREAM" ]; then 450 | [ -z "$QUIET" ] && echo "${C_WARN}Warning: Failed to obtain the upstream of $REPO, maybe it's not a fork.${C_RST}" >&2 451 | elif [ "$UPSTREAM" = "$GH_REPO" ]; then 452 | [ -z "$QUIET" ] && echo "${C_WARN}Warning: -u is ignored because it .${C_RST}" >&2 453 | UPSTREAM= 454 | else 455 | UPSTREAM="${REPO/"$GH_REPO"/"$UPSTREAM"}" 456 | fi 457 | fi 458 | fi 459 | 460 | DIR="$(normalize "$DIR")" 461 | 462 | if [ -n "$DIR" ]; then 463 | BASENAME="$(basename "$DIR")" 464 | elif [ "$GITHUB" = GIST ]; then 465 | BASENAME="$GH_REPO" 466 | else 467 | BASENAME="$(basename "$REPO")" 468 | BASENAME="${BASENAME%.git}" 469 | fi 470 | if [ -z "$OUTPUT" ]; then 471 | OUTPUT="$BASENAME" 472 | DEF_OUTPUT=YES 473 | else 474 | DEF_OUTPUT= 475 | fi 476 | 477 | if [ -n "$TAG" ]; then 478 | if [ -z "$TAG_FILE" ]; then 479 | TAG_FILE="VERSION" 480 | fi 481 | else 482 | TAG_FILE= 483 | fi 484 | 485 | if ! which git >/dev/null; then 486 | echo "${C_ERR}Error: git(1) not found${C_RST}" 487 | exit 66 488 | fi 489 | 490 | git_new || ([ -z "$QUIET" ] && printf "${C_WARN}Warning: You should upgrade your git (currently %s)${C_RST}\n" "$(git version)" >&2) 491 | 492 | if [ "$BRANCH" = "HEAD" ]; then 493 | [ -n "$VERBOSE" ] && echo "${C_INFO}Resolving HEAD...${C_RST}" >&2 494 | BRANCH="$(git ls-remote --symref "$REPO" HEAD | { grep '^ref:' || true; } | cut -d $'\t' -f 1)" 495 | if [ -z "$BRANCH" ]; then 496 | [ -z "$QUIET" ] && echo "${C_WARN}Warning: Weird repo HEAD non-symbolic, still proceeding${C_RST}" >&2 497 | BRANCH=HEAD 498 | else 499 | BRANCH="${BRANCH#ref: }" 500 | if [ "${BRANCH#refs/heads/}" = "${BRANCH}" ]; then 501 | [ -z "$QUIET" ] && echo "${C_WARN}Warning: Weird repo HEAD symbolic, still proceeding${C_RST}" >&2 502 | else 503 | BRANCH="${BRANCH#refs/heads/}" 504 | fi 505 | fi 506 | fi 507 | 508 | if [ ! "$OUTPUT" = '-' ]; then 509 | OUTPUT="$(fakerealpath "$OUTPUT")" 510 | fi 511 | if [ -n "$VERBOSE" ]; then 512 | SHA1_SELF="$(git hash-object -t blob --no-filters "$0" || true)" 513 | printf "${C_DBG}GIT_GET_VERSION=%q${C_RST}\n" "$GIT_GET_VERSION" >&2 514 | printf "${C_DBG}SHA1_SELF=%q${C_RST}\n" "$SHA1_SELF" >&2 515 | printf "${C_DBG}OCWD=%q${C_RST}\n" "$OCWD" >&2 516 | printf "${C_DBG}FORCE=%q${C_RST}\n" "$FORCE" >&2 517 | printf "${C_DBG}FORCE_DIR=%q${C_RST}\n" "$FORCE_DIR" >&2 518 | printf "${C_DBG}OUTPUT=%q${C_RST}\n" "$OUTPUT" >&2 519 | printf "${C_DBG}DEF_OUTPUT=%q${C_RST}\n" "$DEF_OUTPUT" >&2 520 | printf "${C_DBG}PRESERVE=%q${C_RST}\n" "$PRESERVE" >&2 521 | printf "${C_DBG}TAG=%q${C_RST}\n" "$TAG" >&2 522 | printf "${C_DBG}TAG_FILE=%q${C_RST}\n" "$TAG_FILE" >&2 523 | printf "${C_DBG}GITHUB=%q${C_RST}\n" "$GITHUB" >&2 524 | printf "${C_DBG}GH_REPO=%q${C_RST}\n" "$GH_REPO" >&2 525 | printf "${C_DBG}REPO=%q${C_RST}\n" "$REPO" >&2 526 | printf "${C_DBG}BRANCH=%q${C_RST}\n" "$BRANCH" >&2 527 | printf "${C_DBG}DIR=%q${C_RST}\n" "$DIR" >&2 528 | printf "${C_DBG}SPARSE=%q${C_RST}\n" "$SPARSE" >&2 529 | printf "${C_DBG}UPSTREAM=%q${C_RST}\n" "$UPSTREAM" >&2 530 | printf "${C_DBG}BASENAME=%q${C_RST}\n" "$BASENAME" >&2 531 | printf "${C_DBG}PREV_TAGS=%q${C_RST}\n" "$PREV_TAGS" >&2 532 | fi 533 | 534 | if [ -n "$PRESERVE" ] || [ -z "$DIR" ]; then # must result in a dir 535 | if [ "$OUTPUT" = "-" ]; then 536 | true 537 | elif [ -d "$OUTPUT" ]; then 538 | if [ -z "$FORCE_DIR" ]; then 539 | printf "${C_ERR}Error: Directory %q exists${C_RST}\n" "$OUTPUT" >&2 540 | exit 1 541 | fi 542 | elif [ -f "$OUTPUT" ]; then 543 | if [ -z "$FORCE" ]; then 544 | printf "${C_ERR}Error: File %q exists${C_RST}\n" "$OUTPUT" >&2 545 | exit 1 546 | fi 547 | elif [ -e "$OUTPUT" ]; then 548 | printf "${C_ERR}Error: Weird file %q exists${C_RST}\n" "$OUTPUT" >&2 549 | exit 1 550 | fi 551 | fi 552 | 553 | WORK_DIR="$(realpath "$(mktemp -d)")" 554 | finish() { 555 | set +eu 556 | cd / 557 | if [ -n "$KEEP_WORK_DIR" ]; then 558 | printf "${C_WARN}Notice: WORK_DIR located at %s${C_RST}\n" "$WORK_DIR" 559 | else 560 | rm -rf "$WORK_DIR" 561 | fi 562 | } 563 | trap finish EXIT 564 | cd "$WORK_DIR" 565 | 566 | [ -n "$VERBOSE" ] && printf "${C_DBG}WORK_DIR=%q${C_RST}\n" "$WORK_DIR" >&2 567 | 568 | got_file() { 569 | set -e 570 | if [ "$OUTPUT" = "-" ]; then 571 | if [ "$3" = "LINK" ]; then 572 | readlink "$1" 573 | else 574 | cat "$1" 575 | fi 576 | elif [ -f "$OUTPUT" ]; then 577 | if [ -n "$FORCE" ]; then 578 | [ -z "$QUIET" ] && printf "${C_WARN}Warning: Overriding file %q${C_RST}\n" "$OUTPUT" >&2 579 | mv -f "$1" "$OUTPUT" 580 | else 581 | printf "${C_ERR}Error: File %q exists${C_RST}\n" "$OUTPUT" >&2 582 | exit 1 583 | fi 584 | elif [ -d "$OUTPUT" ]; then 585 | if [ -n "$DEF_OUTPUT" ]; then 586 | printf "${C_ERR}Error: There is a directory %q${C_RST}\n" "$OUTPUT" >&2 587 | exit 1 588 | else 589 | mv "$1" "$OUTPUT" 590 | fi 591 | elif [ -e "$OUTPUT" ]; then 592 | printf "${C_ERR}Error: Weird file %q exists${C_RST}\n" "$OUTPUT" >&2 593 | exit 1 594 | else 595 | mv "$1" "$OUTPUT" 596 | fi 597 | [ -n "$VERBOSE" ] && printf "${C_DBG}size used in /tmp = %s${C_RST}\n" "$(du -sh "$WORK_DIR")" >&2 598 | if [ -z "$PREV_TAGS" ]; then 599 | T="$2" 600 | else 601 | T="$(printf '%s\n%s' "$PREV_TAGS" "$2")" 602 | fi 603 | if [ -z "$TAG" ]; then 604 | [ -z "$QUIET" ] && printf "${C_NOTICE}tag = %q${C_RST}\n" "$T" >&2 605 | else 606 | if [[ "$TAG_FILE" =~ ^/ ]]; then 607 | TG="$TAG_FILE" 608 | else 609 | TG="$OCWD/$TAG_FILE" 610 | fi 611 | [ -z "$QUIET" ] && printf "${C_NOTICE}tag = %q -> %s${C_RST}\n" "$T" "$TG" >&2 612 | if [ -e "$TG" ]; then 613 | printf "${C_ERR}Error: Unable to create tag file %s because it exists; git-get continues.${C_RST}" "$TG" >&2 614 | else 615 | printf "%s\n" "$T" >"$TG" 616 | fi 617 | fi 618 | exit 0 619 | } 620 | 621 | got_dir() { 622 | set -e 623 | if [ "$OUTPUT" = "-" ]; then 624 | [ -n "$VERBOSE" ] && (cd "$(dirname "$1")" && ls -lhAR "$(basename "$1")" >&2) 625 | (cd "$(dirname "$1")" && tar c "$(basename "$1")") 626 | elif [ -d "$OUTPUT" ]; then 627 | if [ -n "$FORCE_DIR" ]; then 628 | [ -z "$QUIET" ] && printf "${C_WARN}Warning: Overriding directory %q${C_RST}\n" "$OUTPUT" >&2 629 | rm -rf "$OUTPUT" && mv "$1" "$OUTPUT" 630 | else 631 | printf "${C_ERR}Error: Directory %q exists${C_RST}\n" "$OUTPUT" >&2 632 | exit 1 633 | fi 634 | elif [ -f "$OUTPUT" ]; then 635 | if [ -n "$FORCE" ]; then 636 | [ -z "$QUIET" ] && printf "${C_WARN}Warning: Overriding file %q${C_RST}\n" "$OUTPUT" >&2 637 | rm -f "$OUTPUT" && mv "$1" "$OUTPUT" 638 | else 639 | printf "${C_ERR}Error: File %q exists${C_RST}\n" "$OUTPUT" >&2 640 | exit 1 641 | fi 642 | elif [ -e "$OUTPUT" ]; then 643 | printf "${C_ERR}Error: Weird file %q exists${C_RST}\n" "$OUTPUT" >&2 644 | exit 1 645 | else 646 | mv "$1" "$OUTPUT" 647 | fi 648 | [ -n "$VERBOSE" ] && printf "${C_DBG}size used in /tmp = %s${C_RST}\n" "$(du -sh "$WORK_DIR")" >&2 649 | if [ -z "$PREV_TAGS" ]; then 650 | T="$2" 651 | else 652 | T="$(printf '%s\n%s' "$PREV_TAGS" "$2")" 653 | fi 654 | if [ -z "$TAG" ]; then 655 | [ -z "$QUIET" ] && printf "${C_NOTICE}tag = %q${C_RST}\n" "$T" >&2 656 | else 657 | if [[ "$TAG_FILE" =~ ^/ ]]; then 658 | TG="$TAG_FILE" 659 | elif [ "$OUTPUT" = "-" ]; then 660 | TG="$OCWD/$TAG_FILE" 661 | else 662 | TG="$OUTPUT/$TAG_FILE" 663 | fi 664 | [ -z "$QUIET" ] && printf "${C_NOTICE}tag = %q -> %s${C_RST}\n" "$T" "$TG" >&2 665 | printf "${C_NOTICE}%s${C_RST}\n" "$T" >"$TG" 666 | fi 667 | exit 0 668 | } 669 | 670 | config_remotes() { 671 | if [ -z "$2" ]; then 672 | git config --unset "remote.origin.$1" || true 673 | [ -n "$UPSTREAM" ] && git config --unset "remote.upstream.$1" || true 674 | else 675 | git config "remote.origin.$1" "${2/_/origin}" 676 | [ -n "$UPSTREAM" ] && git config "remote.upstream.$1" "${2/_/upstream}" 677 | fi 678 | true 679 | } 680 | 681 | got_repo() { 682 | set -e 683 | git config --bool core.bare false 684 | git config core.repositoryformatversion 0 685 | 686 | if [ -z "$DIR" ]; then 687 | if [ "$PRESERVE" = X ]; then 688 | git config --unset remote.origin.mirror || true 689 | if [ -n "$UPSTREAM" ]; then 690 | git config remote.upstream.url "$UPSTREAM" 691 | git config remote.upstream.promisor true 692 | git config remote.upstream.partialclonefilter tree:0 693 | fi 694 | if [ -z "$CL_BRANCHES" ]; then 695 | config_remotes fetch '+refs/heads/*:refs/remotes/_/*' 696 | elif git show-ref --verify "refs/heads/$BRANCH" >/dev/null 2>/dev/null; then 697 | [ -n "$VERBOSE" ] && echo "${C_INFO}Set branch: refs/heads/$BRANCH${C_RST}" >&2 698 | config_remotes fetch "+refs/heads/$BRANCH:refs/remotes/_/$BRANCH" 699 | if [ -n "$UPSTREAM" ] && [ -z "$(git ls-remote "$UPSTREAM" "refs/heads/$BRANCH")" ]; then 700 | UBRANCH="$(git ls-remote --symref "$UPSTREAM" HEAD | { grep '^ref:' || true; } | cut -d $'\t' -f 1)" 701 | UBRANCH="${UBRANCH#ref: }" 702 | [ -z "$QUIET" ] && echo "${C_WARN}Warning: refs/heads/$BRANCH not found on upstream $UPSTREAM, using default $UBRANCH instead.${C_RST}" >&2 703 | git config remote.upstream.fetch "+$UBRANCH:refs/remotes/upstream/${UBRANCH#refs/heads/}" 704 | fi 705 | else 706 | [ -z "$QUIET" ] && echo "${C_WARN}Warning: $BRANCH is not a branch, so your clone will contain no branch.${C_RST}" >&2 707 | config_remotes fetch '' 708 | fi 709 | config_remotes tagOpt "$([ -n "$CL_TAGS" ] && echo '--no-tags')" 710 | [ -n "$VERBOSE" ] && (printf "${C_NOTICE}"; printf '%q ' git update-ref --stdin; printf "${C_RST}\n") >&2 711 | git for-each-ref refs/remotes/ --format='delete %(refname)' | git update-ref --stdin 712 | git for-each-ref --format='%(refname)' | \ 713 | while IFS= read -r line; do 714 | if [ "$line" = "refs/heads/$BRANCH" ]; then 715 | echo "create refs/remotes/origin/$BRANCH" "$line" 716 | elif [[ "$line" =~ ^refs/heads/ ]]; then 717 | [ -z "$CL_BRANCHES" ] && echo create "refs/remotes/origin/${line##refs/heads/}" "$line" 718 | echo "delete $line" 719 | elif [[ "$line" =~ ^refs/tags/ ]]; then 720 | [ -n "$CL_TAGS" ] && echo "delete $line" 721 | true 722 | else 723 | echo "delete $line" 724 | fi 725 | done | git update-ref --stdin 726 | if git show-ref --verify "refs/remotes/origin/$BRANCH" >/dev/null 2>/dev/null; then 727 | ARGS=(git branch -f "$BRANCH") 728 | ARGS+=("refs/remotes/origin/$BRANCH") 729 | [ -n "$QUIET" ] && ARGS+=(-q) 730 | [ -n "$VERBOSE" ] && (printf "${C_NOTICE}"; printf '%q ' "${ARGS[@]}"; printf "${C_RST}\n") >&2 731 | [ -z "$QUIET" ] && "${ARGS[@]}" >&2 732 | [ -n "$QUIET" ] && "${ARGS[@]}" 2>/dev/null >&2 733 | git symbolic-ref HEAD "refs/heads/$BRANCH" 734 | fi 735 | if [ -n "$UPSTREAM" ]; then 736 | # --porcelain is the dark magic, don't touch 737 | ARGS=(git fetch upstream --porcelain) 738 | [ -n "$QUIET" ] && ARGS+=(-q) 739 | [ -n "$VERBOSE" ] && (printf "${C_NOTICE}"; printf '%q ' "${ARGS[@]}"; printf "${C_RST}\n") >&2 740 | [ -z "$QUIET" ] && "${ARGS[@]}" >&2 741 | [ -n "$QUIET" ] && "${ARGS[@]}" 2>/dev/null >&2 742 | fi 743 | fi 744 | unset GIT_DIR 745 | if [ -n "$SPARSE" ]; then 746 | ARGS=(git sparse-checkout set --sparse-index --cone) 747 | [ -n "$QUIET" ] && ARGS+=(-q) 748 | [ -n "$VERBOSE" ] && (printf "${C_NOTICE}"; printf '%q ' "${ARGS[@]}"; printf "${C_RST}\n") >&2 749 | [ -z "$QUIET" ] && (cd "$1" && "${ARGS[@]}" >&2) 750 | [ -n "$QUIET" ] && (cd "$1" && "${ARGS[@]}" 2>/dev/null >&2) 751 | fi 752 | ARGS=(git reset --hard) 753 | [ -n "$QUIET" ] && ARGS+=(-q) 754 | [ -n "$VERBOSE" ] && (printf "${C_NOTICE}"; printf '%q ' "${ARGS[@]}"; printf "${C_RST}\n") >&2 755 | [ -z "$QUIET" ] && (cd "$1" && "${ARGS[@]}" >&2) 756 | [ -n "$QUIET" ] && (cd "$1" && "${ARGS[@]}" 2>/dev/null >&2) 757 | [ -z "$PRESERVE" ] && mv "$1/.git" ".git" 758 | got_dir "$1" "$2" && exit 0 759 | else 760 | # This workaround fixes #14 (https://github.com/b1f6c1c4/git-get/issues/14) 761 | # which is caused by https://github.com/git/git/commit/35a9f1e99c5d31635bb78a4f2d498e72c04fc471 762 | P="" 763 | while IFS= read -r -u 3 line; do 764 | TP="$(cut -d $'\t' -f 2 <<<"$line")" 765 | if [ "$TP" = "$DIR" ] || [ ! "${DIR#${TP}/}" = "$DIR" ]; then 766 | P="$TP" 767 | fi 768 | done 3< <(git ls-tree HEAD -r | grep '^160000 commit ') 769 | unset GIT_DIR 770 | if [ -n "$P" ]; then 771 | [ -n "$VERBOSE" ] && printf "${C_INFO}Checking %q -> %s (%q)${C_RST}\n" "$DIR" "commit" "$P" >&2 772 | 773 | # To support legacy git, use git checkout here 774 | # ARGS=(git restore --source=HEAD --staged --worktree) 775 | ARGS=(git checkout HEAD) 776 | [ -n "$QUIET" ] && ARGS+=(-q) 777 | ARGS+=(-- ".gitmodules" "$P") 778 | [ -n "$VERBOSE" ] && (printf "${C_NOTICE}"; printf '%q ' "${ARGS[@]}"; printf "${C_RST}\n") >&2 779 | [ -z "$QUIET" ] && (cd "$1" && "${ARGS[@]}" >&2) 780 | [ -n "$QUIET" ] && (cd "$1" && "${ARGS[@]}" 2>/dev/null >&2) 781 | 782 | ARGS=(git submodule) 783 | [ -n "$QUIET" ] && ARGS+=(--quiet) 784 | ARGS+=(init) 785 | [ -n "$VERBOSE" ] && (printf "${C_NOTICE}"; printf '%q ' "${ARGS[@]}"; printf "${C_RST}\n") >&2 786 | [ -z "$QUIET" ] && (cd "$1" && "${ARGS[@]}" >&2) 787 | [ -n "$QUIET" ] && (cd "$1" && "${ARGS[@]}" 2>/dev/null >&2) 788 | 789 | while IFS= read -r -u 3 line; do 790 | PA="$(git config --file "$1/.gitmodules" "submodule.$line.path")" 791 | URL="$(git config --file "$1/.git/config" "submodule.$line.url")" 792 | SSHA1="$(git --git-dir="$1/.git" ls-files -s "$PA" | cut -d ' ' -f2)" 793 | [ -n "$VERBOSE" ] && printf "${C_WARN}%s %s %s %s${C_RST}\n" "$line" "$PA" "$URL" "$SSHA1" >&2 794 | [ ! "$PA" = "$P" ] && continue 795 | ARGS=("$0") 796 | [ -n "$VERBOSE" ] && ARGS+=(--verbose) 797 | [ -n "$QUIET" ] && ARGS+=(--quiet) 798 | [ -n "$COLOR" ] && ARGS+=(--color=always) || ARGS+=(--color=never) 799 | [ -n "$GH_USE_HTTPS" ] && ARGS+=(--https) 800 | [ -n "$GH_USE_SSH" ] && ARGS+=(--ssh) 801 | [ -n "$CL_BRANCHES" ] && ARGS+=(--single-branch) 802 | [ -n "$CL_TAGS" ] && ARGS+=(--no-tags) 803 | ARGS+=("$URL" "$SSHA1") 804 | ARGS+=(-o "$OUTPUT") 805 | [ -n "$FORCE" ] && ARGS+=(--force) 806 | [ -n "$FORCE_DIR" ] && ARGS+=(--rm-rf) 807 | [ -n "$TAG_FILE" ] && ARGS+=(--tag-file "$TAG_FILE") 808 | [ ! "$P" = "$DIR" ] && ARGS+=(-- "${DIR#$P/}") 809 | [ -z "$QUIET" ] && printf "${C_NOTICE}+++ %s %s %s${C_RST}\n" "$PA" "$URL" "$SSHA1">&2 810 | [ -n "$VERBOSE" ] && (printf "${C_NOTICE}" >&2; printf '%q ' "${ARGS[@]}" >&2; printf "${C_RST}\n">&2) 811 | if [ -z "$PREV_TAGS" ]; then 812 | PREV_TAGS="$2" 813 | else 814 | PREV_TAGS="$(printf '%s\n%s' "$PREV_TAGS" "$2")" 815 | fi 816 | OCWD="$OCWD" PREV_TAGS="$PREV_TAGS" "${ARGS[@]}" 2>&1 | sed 's/^/ /' >&2 817 | exit "$?" 818 | done 3< <(sed -nE '/^\[submodule /{ 819 | s/^\[submodule "(.*)"\]$/\1/ 820 | p 821 | }' "$1/.git/config") 822 | fi 823 | 824 | # git restore --worktree issue fetch-pack one-by-another 825 | # which is super slow 826 | 827 | # This workaround fixes #8 (https://github.com/b1f6c1c4/git-get/issues/8) 828 | # which is caused by https://github.com/git/git/commit/95acf11a3dc3d18ec999f4913ec6c6a54545c6b7 829 | ARGS=(git diff-index HEAD --cached -p) 830 | ARGS+=(-- "$DIR") 831 | [ -n "$VERBOSE" ] && (printf "${C_NOTICE}"; printf '%q ' "${ARGS[@]}"; printf "${C_RST}\n") >&2 832 | [ -z "$QUIET" ] && (cd "$1" && "${ARGS[@]}" >/dev/null) 833 | [ -n "$QUIET" ] && (cd "$1" && "${ARGS[@]}" 2>/dev/null >/dev/null) 834 | 835 | ARGS=(git reset HEAD) 836 | [ -n "$QUIET" ] && ARGS+=(-q) 837 | ARGS+=(-- "$DIR") 838 | [ -n "$VERBOSE" ] && (printf "${C_NOTICE}"; printf '%q ' "${ARGS[@]}"; printf "${C_RST}\n") >&2 839 | [ -z "$QUIET" ] && (cd "$1" && "${ARGS[@]}" >&2) 840 | [ -n "$QUIET" ] && (cd "$1" && "${ARGS[@]}" 2>/dev/null >&2) 841 | 842 | # To support legacy git, use git checkout here 843 | # ARGS=(git restore --worktree) 844 | ARGS=(git checkout) 845 | [ -n "$QUIET" ] && ARGS+=(-q) 846 | ARGS+=(-- "$DIR") 847 | [ -n "$VERBOSE" ] && (printf "${C_NOTICE}" >&2; printf '%q ' "${ARGS[@]}" >&2; printf "${C_RST}\n">&2) 848 | [ -z "$QUIET" ] && (cd "$1" && "${ARGS[@]}" >&2) 849 | [ -n "$QUIET" ] && (cd "$1" && "${ARGS[@]}" 2>/dev/null >&2) 850 | [ -f "$1/$DIR" ] && got_file "$1/$DIR" "$2" 851 | [ -d "$1/$DIR" ] && got_dir "$1/$DIR" "$2" 852 | [ -L "$1/$DIR" ] && got_file "$1/$DIR" "$2" LINK 853 | echo "${C_ERR}Error: File type not supported.${C_RST}" >&2 854 | exit 2 855 | fi 856 | } 857 | 858 | # 0. git 2.20+ -> shallow + [filter] -> filter 859 | if git_new; then 860 | mkdir -p "$BASENAME" 861 | if [ ! "$PRESERVE" = X ] && [ -n "$(git ls-remote "$REPO" "$BRANCH")" ]; then 862 | ARGS=(git clone --bare) 863 | [ -n "$QUIET" ] && ARGS+=(-q) 864 | [ -z "$QUIET" ] && ARGS+=(--progress) 865 | [ ! "$BRANCH" = "HEAD" ] && ARGS+=(--branch "$BRANCH") 866 | ARGS+=(--depth 1 --no-tags) 867 | if [ -n "$DIR" ] || [ -n "$SPARSE" ]; then 868 | ARGS+=(--filter blob:none) 869 | fi 870 | ARGS+=("$REPO" "$BASENAME/.git") 871 | [ -n "$VERBOSE" ] && (printf "${C_NOTICE}"; printf '%q ' "${ARGS[@]}"; printf "${C_RST}\n") >&2 872 | set +e 873 | if "${ARGS[@]}"; then 874 | set -e 875 | export GIT_DIR="$(realpath "$BASENAME/.git")" 876 | got_repo "$BASENAME" "$(git rev-parse HEAD)" 877 | fi 878 | set -e 879 | [ -z "$QUIET" ] && echo "${C_WARN}Warning: Failed git clone, will attempt another method${C_RST}" 880 | fi 881 | if true; then 882 | ARGS=(git clone --mirror --filter tree:0) 883 | [ -n "$QUIET" ] && ARGS+=(-q) 884 | [ -z "$QUIET" ] && ARGS+=(--progress) 885 | ARGS+=("$REPO" "$BASENAME/.git") 886 | [ -n "$VERBOSE" ] && (printf "${C_NOTICE}"; printf '%q ' "${ARGS[@]}"; printf "${C_RST}\n") >&2 887 | set +e 888 | if "${ARGS[@]}"; then 889 | export GIT_DIR="$(realpath "$BASENAME/.git")" 890 | SHA1="$(git rev-parse "$BRANCH")" 891 | if [ -n "$SHA1" ]; then 892 | [ -z "$QUIET" ] && printf "${C_INFO}Got SHA1: %q${C_RST}\n" "$SHA1" >&2 893 | set -e 894 | NSHA1="$(git rev-parse "$SHA1^{commit}")" 895 | [ ! "$SHA1" = "$NSHA1" ] && printf "${C_INFO}Got actual SHA1: %q${C_RST}\n" "$NSHA1" >&2 896 | git update-ref --no-deref HEAD "$NSHA1" 897 | got_repo "$BASENAME" "$NSHA1" 898 | fi 899 | fi 900 | set -e 901 | fi 902 | rm -rf "$BASENAME" 903 | fi 904 | 905 | printf "${C_ERR}Error: No viable method.${C_RST}\n" >&2 906 | exit 3 907 | -------------------------------------------------------------------------------- /git-gets: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | GIT_GET_VERSION= 4 | 5 | if [ -z "$RAW" ]; then 6 | RAW= 7 | else 8 | RAW="$RAW" 9 | fi 10 | 11 | if [ -z "$GH_USE_HTTPS" ]; then 12 | GH_USE_HTTPS= 13 | else 14 | GH_USE_HTTPS="$GH_USE_HTTPS" 15 | fi 16 | if [ -z "$GH_USE_SSH" ]; then 17 | GH_USE_SSH= 18 | else 19 | GH_USE_SSH="$GH_USE_SSH" 20 | fi 21 | 22 | if [ -z "$GIT_DIR" ]; then 23 | GIT_DIR= 24 | else 25 | GIT_DIR="$GIT_DIR" 26 | fi 27 | 28 | if [ -z "$GIT_WORK_TREE" ]; then 29 | GIT_WORK_TREE= 30 | else 31 | GIT_WORK_TREE="$GIT_WORK_TREE" 32 | fi 33 | 34 | set -euo pipefail 35 | 36 | usage() 37 | { 38 | exec man git-gets 39 | } 40 | 41 | git_new() { 42 | V="$(git version)" 43 | [[ "$V" =~ ^git[[:space:]]version[[:space:]]2\..\. ]] && return 1 44 | [[ "$V" =~ ^git[[:space:]]version[[:space:]]2\.1.\. ]] && return 1 45 | return 0 46 | } 47 | 48 | fakerealpath() { 49 | if [[ "$1" =~ ^/ ]]; then 50 | printf '%s' "$1" 51 | else 52 | printf '%s/%s' "$PWD" "$1" 53 | fi 54 | } 55 | 56 | got_dir() { 57 | set -e 58 | if [ "$OUTPUT" = "-" ]; then 59 | [ -n "$VERBOSE" ] && (cd "$(dirname "$1")" && ls -lhAR "$(basename "$1")" >&2) 60 | (cd "$(dirname "$1")" && tar c "$(basename "$1")") 61 | elif [ -d "$OUTPUT" ]; then 62 | if [ -n "$FORCE_DIR" ]; then 63 | [ -z "$QUIET" ] && printf "${C_WARN}Warning: Overriding directory %q${C_RST}\n" "$OUTPUT" >&2 64 | rm -rf "$OUTPUT" && mv "$1" "$OUTPUT" 65 | else 66 | printf "${C_ERR}Error: Directory %q exists${C_RST}\n" "$OUTPUT" >&2 67 | exit 1 68 | fi 69 | elif [ -f "$OUTPUT" ]; then 70 | if [ -n "$FORCE_DIR" ]; then 71 | [ -z "$QUIET" ] && printf "${C_WARN}Warning: Overriding file %q${C_RST}\n" "$OUTPUT" >&2 72 | rm -f "$OUTPUT" && mv "$1" "$OUTPUT" 73 | else 74 | printf "${C_ERR}Error: File %q exists${C_RST}\n" "$OUTPUT" >&2 75 | exit 1 76 | fi 77 | elif [ -e "$OUTPUT" ]; then 78 | printf "${C_ERR}Error: Weird file %q exists${C_RST}\n" "$OUTPUT" >&2 79 | exit 1 80 | else 81 | mv "$1" "$OUTPUT" 82 | fi 83 | [ -n "$VERBOSE" ] && printf "${C_DBG}size used in /tmp = %s${C_RST}\n" "$(du -sh "$WORK_DIR")" >&2 84 | T="$2" 85 | if [ -z "$TAG_FILE" ]; then 86 | [ -z "$QUIET" ] && printf "${C_NOTICE}tag = %q${C_RST}\n" "$T" >&2 87 | else 88 | if [[ "$TAG_FILE" =~ ^/ ]]; then 89 | TG="$TAG_FILE" 90 | elif [ "$OUTPUT" = "-" ]; then 91 | TG="$OCWD/$TAG_FILE" 92 | else 93 | TG="$OUTPUT/$TAG_FILE" 94 | fi 95 | [ -z "$QUIET" ] && printf "${C_NOTICE}tag = %q -> %s${C_RST}\n" "$T" "$TG" >&2 96 | if [ -e "$TG" ]; then 97 | printf "${C_ERR}Error: Unable to create tag file %s because it exists; git-gets continues.${C_RST}" "$TG" >&2 98 | else 99 | printf "%s\n" "$T" >"$TG" 100 | fi 101 | fi 102 | exit 0 103 | } 104 | 105 | config_remotes() { 106 | if [ -z "$2" ]; then 107 | git config --unset "remote.origin.$1" || true 108 | [ -n "$UPSTREAM" ] && git config --unset "remote.upstream.$1" || true 109 | else 110 | git config "remote.origin.$1" "${2/_/origin}" 111 | [ -n "$UPSTREAM" ] && git config "remote.upstream.$1" "${2/_/upstream}" 112 | fi 113 | true 114 | } 115 | 116 | got_repo() { 117 | set -e 118 | git config core.repositoryformatversion 0 119 | if [ "$PRESERVE" = X ] && [ -z "$SUBMODULE_MODE" ]; then 120 | git config --unset remote.origin.mirror || true 121 | if [ -n "$UPSTREAM" ]; then 122 | git config remote.upstream.url "$UPSTREAM" 123 | git config remote.upstream.promisor true 124 | git config remote.upstream.partialclonefilter tree:0 125 | fi 126 | if [ -z "$CL_BRANCHES" ]; then 127 | config_remotes fetch '+refs/heads/*:refs/remotes/_/*' 128 | elif git show-ref --verify "refs/heads/$BRANCH" >/dev/null 2>/dev/null; then 129 | [ -n "$VERBOSE" ] && echo "${C_INFO}Set branch: refs/heads/$BRANCH${C_RST}" >&2 130 | config_remotes fetch "+refs/heads/$BRANCH:refs/remotes/_/$BRANCH" 131 | if [ -n "$UPSTREAM" ] && [ -z "$(git ls-remote "$UPSTREAM" "refs/heads/$BRANCH")" ]; then 132 | UBRANCH="$(git ls-remote --symref "$UPSTREAM" HEAD | { grep '^ref:' || true; } | cut -d $'\t' -f 1)" 133 | UBRANCH="${UBRANCH#ref: }" 134 | [ -z "$QUIET" ] && echo "${C_WARN}Warning: refs/heads/$BRANCH not found on upstream $UPSTREAM, using default $UBRANCH instead.${C_RST}" >&2 135 | git config remote.upstream.fetch "+$UBRANCH:refs/remotes/upstream/${UBRANCH#refs/heads/}" 136 | fi 137 | else 138 | [ -z "$RAW" ] && [ -z "$QUIET" ] && echo "${C_WARN}Warning: $BRANCH is not a branch, so your clone will contain no branch.${C_RST}" >&2 139 | config_remotes fetch '' 140 | fi 141 | config_remotes tagOpt "$([ -n "$CL_TAGS" ] && echo '--no-tags')" 142 | [ -n "$VERBOSE" ] && (printf "${C_NOTICE}"; printf '%q ' git update-ref --stdin; printf "${C_RST}\n") >&2 143 | git for-each-ref refs/remotes/ --format='delete %(refname)' | git update-ref --stdin 144 | git for-each-ref --format='%(refname)' | \ 145 | while IFS= read -r line; do 146 | if [ "$line" = "refs/heads/$BRANCH" ]; then 147 | echo "create refs/remotes/origin/$BRANCH" "$line" 148 | elif [[ "$line" =~ ^refs/heads/ ]]; then 149 | [ -z "$CL_BRANCHES" ] && echo create "refs/remotes/origin/${line##refs/heads/}" "$line" 150 | echo "delete $line" 151 | elif [[ "$line" =~ ^refs/tags/ ]]; then 152 | [ -n "$CL_TAGS" ] && echo "delete $line" 153 | true 154 | else 155 | echo "delete $line" 156 | fi 157 | done | git update-ref --stdin 158 | if git show-ref --verify "refs/remotes/origin/$BRANCH" >/dev/null 2>/dev/null; then 159 | ARGS=(git branch -f "$BRANCH") 160 | ARGS+=("refs/remotes/origin/$BRANCH") 161 | [ -n "$QUIET" ] && ARGS+=(-q) 162 | [ -n "$VERBOSE" ] && (printf "${C_NOTICE}"; printf '%q ' "${ARGS[@]}"; printf "${C_RST}\n") >&2 163 | [ -z "$QUIET" ] && "${ARGS[@]}" >&2 164 | [ -n "$QUIET" ] && "${ARGS[@]}" 2>/dev/null >&2 165 | git symbolic-ref HEAD "refs/heads/$BRANCH" 166 | fi 167 | if [ -n "$UPSTREAM" ]; then 168 | # --porcelain is the dark magic, don't touch 169 | ARGS=(git fetch upstream --porcelain) 170 | [ -n "$QUIET" ] && ARGS+=(-q) 171 | [ -n "$VERBOSE" ] && (printf "${C_NOTICE}"; printf '%q ' "${ARGS[@]}"; printf "${C_RST}\n") >&2 172 | [ -z "$QUIET" ] && "${ARGS[@]}" >&2 173 | [ -n "$QUIET" ] && "${ARGS[@]}" 2>/dev/null >&2 174 | fi 175 | fi 176 | 177 | ARGS=(git reset --hard) 178 | [ -n "$QUIET" ] && ARGS+=(-q) 179 | [ -n "$VERBOSE" ] && (printf "${C_NOTICE}"; printf '%q ' "${ARGS[@]}"; printf "${C_RST}\n") >&2 180 | [ -z "$QUIET" ] && "${ARGS[@]}" >&2 181 | [ -n "$QUIET" ] && "${ARGS[@]}" 2>/dev/null >&2 182 | [ -n "$VERBOSE" ] && (printf "${C_NOTICE}" >&2; printf '%q ' "${ARGS[@]}" >&2; printf "${C_RST}\n">&2) 183 | 184 | if [ -n "$RAW" ] && [ -n "$NO_RECURSIVE" ]; then 185 | if [ -z "$SUBMODULE_MODE" ]; then 186 | [ -z "$PRESERVE" ] && mv "$GIT_DIR" ".git" 187 | got_dir "$GIT_WORK_TREE" "$1" 188 | else 189 | exit 0 190 | fi 191 | fi 192 | 193 | if [ -z "$NO_INIT" ]; then 194 | ARGS=(git -C "$GIT_WORK_TREE" submodule) 195 | [ -n "$QUIET" ] && ARGS+=(--quiet) 196 | ARGS+=(init) 197 | [ -n "$VERBOSE" ] && (printf "${C_NOTICE}"; printf '%q ' "${ARGS[@]}"; printf "${C_RST}\n") >&2 198 | [ -z "$QUIET" ] && "${ARGS[@]}" >&2 199 | [ -n "$QUIET" ] && "${ARGS[@]}" 2>/dev/null >&2 200 | fi 201 | 202 | if [ -z "$RAW" ]; then 203 | exec 4>&2 204 | fi 205 | 206 | CONFIRM_GOING_STATUS= 207 | while IFS= read -r -u 3 line; do 208 | PA="$(git -C "$GIT_WORK_TREE" config --file ".gitmodules" "submodule.$line.path" || echo '')" 209 | if [ -z "$PA" ]; then 210 | [ -z "$QUIET" ] && printf "${C_WARN}Skipping %s because it does not appear in .gitmodules${C_RST}\n" "$PA" >&2 211 | continue 212 | fi 213 | URL="$(git config "submodule.$line.url")" 214 | if [ -z "$URL" ]; then 215 | [ -z "$QUIET" ] && printf "${C_WARN}Skipping %s because it has not been initialized${C_RST}\n" "$PA" >&2 216 | continue 217 | fi 218 | SSHA1="$(git ls-files -s "$PA" | cut -d ' ' -f2)" 219 | [ -n "$VERBOSE" ] && printf "${C_INFO}%s %s %s %s${C_RST}\n" "$line" "$PA" "$URL" "$SSHA1">&2 220 | if [ -n "$(find "$GIT_WORK_TREE/$PA" -maxdepth 0 -type d -empty 2>/dev/null)" ]; then 221 | true 222 | else 223 | [ -z "$QUIET" ] && printf "${C_WARN}Warning: Skipping %s because the folder is not empty${C_RST}\n" "$PA" >&2 224 | continue 225 | fi 226 | if [ "$CONFIRM_GOING_STATUS" = A ]; then 227 | GO=YES 228 | elif [ "$CONFIRM_GOING_STATUS" = D ]; then 229 | GO= 230 | elif [ -z "$CONFIRM" ]; then 231 | GO=YES 232 | else 233 | while true; do 234 | [ -z "$RAW" ] && printf "${C_WARN}On the toplevel:${C_RST}\n" >&2 235 | [ -n "$RAW" ] && printf "${C_WARN}Inside the submodule %s:${C_RST}\n" "$RAW" >&2 236 | printf "${C_WARN}Will clone %s from %s, proceed? (Y/n/r/p/s/q/a/d/?) ... ${C_RST}" "$PA" "$URL" >&2 237 | read -n 1 -r 238 | case "$REPLY" in 239 | "") 240 | GO=YES 241 | break 242 | ;; 243 | y) 244 | printf '\n' >&2 245 | GO=YES 246 | break 247 | ;; 248 | n) 249 | printf '\n' >&2 250 | GO= 251 | break 252 | ;; 253 | r) 254 | printf '\n' >&2 255 | GO=R 256 | break 257 | ;; 258 | p) 259 | printf '\n' >&2 260 | GO=P 261 | break 262 | ;; 263 | s) 264 | printf '\n' >&2 265 | GO=S 266 | break 267 | ;; 268 | q) 269 | printf '\n' >&2 270 | exit 5 271 | ;; 272 | a) 273 | printf '\n' >&2 274 | GO=YES 275 | CONFIRM_GOING_STATUS=A 276 | break 277 | ;; 278 | d) 279 | printf '\n' >&2 280 | GO= 281 | CONFIRM_GOING_STATUS=D 282 | break 283 | ;; 284 | ?) 285 | printf '\n' >&2 286 | echo "${C_DBG}y - clone it${C_RST}" >&2 287 | echo "${C_DBG}n - skip it${C_RST}" >&2 288 | echo "${C_DBG}r - clone it, and all its own submodules${C_RST}" >&2 289 | echo "${C_DBG}p - like r, but in parallel${C_RST}" >&2 290 | echo "${C_DBG}s - clone it, but not its own submodules${C_RST}" >&2 291 | echo "${C_DBG}q - quit git-gets immediately${C_RST}" >&2 292 | echo "${C_DBG}a - clone it and all other submodules${C_RST}" >&2 293 | echo "${C_DBG}d - skip it and all other submodules${C_RST}" >&2 294 | ;; 295 | *) 296 | printf '\n' >&2 297 | ;; 298 | esac 299 | done 300 | fi 301 | if [ -n "$GO" ]; then 302 | [ -z "$QUIET" ] && printf "${C_NOTICE}+++ %s %s %s${C_RST}\n" "$PA" "$URL" "$SSHA1">&2 303 | ARGS=("$0") 304 | [ -n "$VERBOSE" ] && ARGS+=(--verbose) 305 | [ -n "$QUIET" ] && ARGS+=(--quiet) 306 | [ -n "$COLOR" ] && ARGS+=(--color=always) || ARGS+=(--color=never) 307 | [ "$PRESERVE" = X ] && ARGS+=(-x) 308 | [ "$PRESERVE" = G ] && ARGS+=(-g) 309 | [ -n "$GH_USE_HTTPS" ] && ARGS+=(--https) 310 | [ -n "$GH_USE_SSH" ] && ARGS+=(--ssh) 311 | [ -n "$CL_BRANCHES" ] && ARGS+=(--single-branch) 312 | [ -n "$CL_TAGS" ] && ARGS+=(--no-tags) 313 | [ -n "$PARALLEL" ] && ARGS+=(--parallel) 314 | case "$GO" in 315 | R) 316 | # overrides --no-recursive 317 | # overrides --confirm 318 | ;; 319 | P) 320 | ARGS+=(--parallel) 321 | ;; 322 | S) 323 | ARGS+=(--no-recursive) 324 | # --confirm is unnecessary here 325 | ;; 326 | *) 327 | [ -n "$NO_RECURSIVE" ] && ARGS+=(--no-recursive) 328 | [ -z "$PARALLEL" ] && [ -n "$CONFIRM" ] && ARGS+=(--confirm) 329 | ;; 330 | esac 331 | ARGS+=(-o "$GIT_WORK_TREE/$PA" "$URL" "$SSHA1") 332 | [ -n "$VERBOSE" ] && (printf "${C_NOTICE}" >&2; printf '%q ' "${ARGS[@]}" >&2; printf "${C_RST}\n">&2) 333 | rmdir "$GIT_WORK_TREE/$PA" 334 | if [ -n "$PARALLEL" ]; then 335 | if [ -n "$CONFIRM" ]; then 336 | RAW="$RAW/$PA" "${ARGS[@]}" 2>&1 | sed 's/^/ /' >>"$TMP_LOG" & 337 | else 338 | RAW="$RAW/$PA" "${ARGS[@]}" 2>&1 | sed 's/^/ /' >&2 & 339 | fi 340 | else 341 | if [ -n "$CONFIRM" ]; then 342 | RAW="$RAW/$PA" "${ARGS[@]}" 343 | else 344 | RAW="$RAW/$PA" "${ARGS[@]}" 2>&1 | sed 's/^/ /' >&2 345 | fi 346 | fi 347 | else 348 | [ -z "$QUIET" ] && printf "${C_DBG}%s %s %s %s${C_RST}\n" '---' "$PA" "$URL" "$SSHA1">&2 349 | fi 350 | done 3< <(git config --local --get-regexp 'submodule.*.url' | cut -d '.' -f 2) 351 | 352 | [ -z "$RAW" ] && [ -n "$PARALLEL" ] && [ -n "$CONFIRM" ] && [ -z "$QUIET" ] && echo "${C_INFO}Waiting for sub-processes to finish, please be patient ...${C_RST}" >&2 353 | wait 354 | [ -z "$RAW" ] && [ -n "$PARALLEL" ] && [ -n "$CONFIRM" ] && cat "$TMP_LOG" >&2 355 | 356 | if [ -z "$RAW" ] && [ -n "$PRESERVE" ]; then 357 | ARGS=(git -C "$GIT_WORK_TREE" submodule) 358 | [ -n "$QUIET" ] && ARGS+=(--quiet) 359 | ARGS+=(absorbgitdirs) 360 | [ -n "$VERBOSE" ] && (printf "${C_NOTICE}"; printf '%q ' "${ARGS[@]}"; printf "${C_RST}\n") >&2 361 | [ -z "$QUIET" ] && "${ARGS[@]}" >&2 362 | [ -n "$QUIET" ] && "${ARGS[@]}" 2>/dev/null >&2 363 | fi 364 | if [ -z "$SUBMODULE_MODE" ]; then 365 | [ -z "$PRESERVE" ] && mv "$GIT_DIR" ".git" 366 | got_dir "$GIT_WORK_TREE" "$1" 367 | else 368 | exit 0 369 | fi 370 | } 371 | 372 | COLOR= 373 | [ -t 2 ] && COLOR=YES 374 | 375 | SUBMODULE_MODE= 376 | QUIET= 377 | VERBOSE= 378 | FORCE_DIR= 379 | OUTPUT= 380 | PRESERVE= 381 | TAG= 382 | TAG_FILE= 383 | PARALLEL= 384 | CONFIRM= 385 | NO_INIT= 386 | NO_RECURSIVE= 387 | UPSTREAM= 388 | CL_BRANCHES= 389 | CL_TAGS= 390 | POSITIONAL=() 391 | while [ $# -gt 0 ]; do 392 | case "$1" in 393 | -X) 394 | shift 395 | set -- -x -u -B -T -P "$@" 396 | ;; 397 | -Y) 398 | shift 399 | set -- -t -P "$@" 400 | ;; 401 | -V|--version) 402 | echo "git-gets(1) $GIT_GET_VERSION" 403 | exit 404 | ;; 405 | -h|--help) 406 | usage 407 | exit 408 | ;; 409 | -q|--quiet) 410 | QUIET=--quiet 411 | shift 412 | ;; 413 | -v|--verbose) 414 | VERBOSE=YES 415 | shift 416 | ;; 417 | --color=never|--colour=never) 418 | COLOR= 419 | shift 420 | ;; 421 | --color=always|--colour=always) 422 | COLOR=YES 423 | shift 424 | ;; 425 | --color=auto|--colour=auto|--color|--colour) 426 | COLOR= 427 | [ -t 2 ] && COLOR=YES 428 | shift 429 | ;; 430 | -s|--ssh) 431 | GH_USE_SSH=YES 432 | shift 433 | ;; 434 | -H|--https) 435 | GH_USE_HTTPS=YES 436 | shift 437 | ;; 438 | -F|--rm-rf) 439 | FORCE_DIR=YES 440 | shift 441 | ;; 442 | -o|--output) 443 | OUTPUT="$2" 444 | shift 445 | shift 446 | ;; 447 | -x) 448 | if [ "$PRESERVE" = G ]; then 449 | echo "Error: Conflict: -x and -g|--preserve-git" >&2 450 | exit 1 451 | fi 452 | PRESERVE=X 453 | shift 454 | ;; 455 | -B|--single-branch) 456 | CL_BRANCHES=YES 457 | shift 458 | ;; 459 | -T|--no-tags) 460 | CL_TAGS=YES 461 | shift 462 | ;; 463 | -g|--preserve-git) 464 | if [ "$PRESERVE" = X ]; then 465 | echo "Error: Conflict: -x and -g|--preserve-git" >&2 466 | exit 1 467 | fi 468 | PRESERVE=G 469 | shift 470 | ;; 471 | -u|--upstream) 472 | UPSTREAM=YES 473 | shift 474 | ;; 475 | -t|--tag) 476 | TAG=YES 477 | shift 478 | ;; 479 | --tag-file) 480 | TAG=YES 481 | TAG_FILE="$2" 482 | shift 483 | shift 484 | ;; 485 | -P|--parallel) 486 | PARALLEL=YES 487 | shift 488 | ;; 489 | -c|--confirm) 490 | CONFIRM=YES 491 | shift 492 | ;; 493 | --no-init) 494 | NO_INIT=YES 495 | shift 496 | ;; 497 | --no-recursive) 498 | NO_RECURSIVE=YES 499 | shift 500 | ;; 501 | --flat) 502 | echo "Error: --flat is no longer supported. Please see man git-gets for more information." >&2 503 | exit 1 504 | ;; 505 | *) 506 | if [[ "$1" =~ ^-j ]]; then 507 | PARALLEL="${1#-j}" 508 | elif [[ "$1" =~ ^--jobs= ]]; then 509 | PARALLEL="${1#--jobs=}" 510 | elif [[ "$1" =~ ^--tag-file= ]]; then 511 | TAG=YES 512 | TAG_FILE="${1#--tag-file=}" 513 | elif [[ "$1" =~ ^--output= ]]; then 514 | OUTPUT="${1#--output=}" 515 | elif [[ "$1" =~ ^-o= ]]; then 516 | OUTPUT="${1#-o=}" 517 | elif [[ "$1" =~ ^-o ]]; then 518 | OUTPUT="${1#-o}" 519 | elif [[ "$1" =~ ^-.. ]]; then 520 | T="$1" 521 | shift 522 | set -- '' "${T:0:2}" "-${T:2}" "$@" 523 | elif [[ "$1" =~ ^- ]]; then 524 | echo "Error: Unrecognized argument $1" >&2 525 | exit 1 526 | else 527 | POSITIONAL+=("$1") 528 | fi 529 | shift 530 | ;; 531 | esac 532 | done 533 | 534 | if [ -n "$COLOR" ]; then 535 | C_ERR=$'\e[37;41m' 536 | C_WARN=$'\e[37;33m' 537 | C_NOTICE=$'\e[35m' 538 | C_INFO=$'\e[34m' 539 | C_DBG=$'\e[36m' 540 | C_RST=$'\e[0m' 541 | else 542 | C_ERR= 543 | C_WARN= 544 | C_NOTICE= 545 | C_INFO= 546 | C_DBG= 547 | C_RST= 548 | fi 549 | 550 | if [ -n "$PRESERVE" ] && [ -n "$TAG" ]; then 551 | echo "${C_ERR}Error: Conflict: -x|-g|--preserve-git and -t|--tag|--tag-file${C_RST}" >&2 552 | exit 1 553 | fi 554 | 555 | if [ "${#POSITIONAL[@]}" -eq 0 ]; then 556 | if git rev-parse HEAD >/dev/null 2>&1; then 557 | SUBMODULE_MODE=YES 558 | else 559 | echo "${C_ERR}Error: Must specify (any git remote) or / (GitHub)${C_RST}" 560 | exit 1 561 | fi 562 | else 563 | if [ -n "$SUBMODULE_MODE" ]; then 564 | echo "${C_ERR}Error: Too many positional arguments.${C_RST}" >&2 565 | exit 1 566 | fi 567 | if [ "${#POSITIONAL[@]}" -eq 1 ]; then 568 | BRANCH="HEAD" 569 | elif [ "${#POSITIONAL[@]}" -eq 2 ]; then 570 | BRANCH="${POSITIONAL[1]}" 571 | elif [ "${#POSITIONAL[@]}" -eq 3 ]; then 572 | if [ -n "$OUTPUT" ]; then 573 | echo "${C_ERR}Error: Too many positional arguments.${C_RST}" >&2 574 | exit 1 575 | fi 576 | BRANCH="${POSITIONAL[1]}" 577 | OUTPUT="${POSITIONAL[2]}" 578 | else 579 | echo "${C_ERR}Error: Too many positional arguments.${C_RST}" >&2 580 | exit 1 581 | fi 582 | fi 583 | 584 | if [ -z "$SUBMODULE_MODE" ]; then 585 | if [ -n "$CL_BRANCHES" ] && [ "$PRESERVE" != X ]; then 586 | echo "${C_ERR}Error: Conflict: --single-branch requires -x${C_RST}" >&2 587 | exit 1 588 | fi 589 | if [ -n "$CL_TAGS" ] && [ "$PRESERVE" != X ]; then 590 | echo "${C_ERR}Error: Conflict: --no-tags requires -x${C_RST}" >&2 591 | exit 1 592 | fi 593 | if [ -n "$UPSTREAM" ] && [ -z "$PRESERVE" ]; then 594 | echo "${C_ERR}Error: Conflict: --upstream requires -x${C_RST}" >&2 595 | exit 1 596 | fi 597 | fi 598 | 599 | if [ -n "$PARALLEL" ] && [ -n "$CONFIRM" ]; then 600 | echo "${C_WARN}Warning: With --parallel, --confirm only works for first-level submodules.${C_RST}" >&2 601 | PMT="${C_WARN}Proceed? (y/n) ... ${C_RST}" 602 | while true; do 603 | read -p "$PMT" -n 1 -r <&2 604 | case "$REPLY" in 605 | "") 606 | ;; 607 | y|Y) 608 | printf '\n' >&2 609 | break 610 | ;; 611 | n|N) 612 | printf '\n' >&2 613 | exit 2 614 | ;; 615 | *) 616 | printf '\n' >&2 617 | ;; 618 | esac 619 | done 620 | fi 621 | 622 | if ! which git >/dev/null; then 623 | echo "${C_ERR}Error: git(1) not found${C_RST}" >&2 624 | exit 66 625 | fi 626 | 627 | git_new || ([ -z "$QUIET" ] && printf "${C_WARN}Warning: You should upgrade your git (currently %s)${C_RST}\n" "$(git version)" >&2) 628 | 629 | if [ -n "$TAG" ]; then 630 | if [ -z "$TAG_FILE" ]; then 631 | TAG_FILE="VERSION" 632 | fi 633 | else 634 | TAG_FILE= 635 | fi 636 | 637 | OCWD="$PWD" 638 | 639 | if [ -n "$SUBMODULE_MODE" ]; then 640 | if [ -n "$OUTPUT" ]; then 641 | echo "${C_ERR}Error: Conflict: --output cannot be used in submodule mode${C_RST}" >&2 642 | exit 1 643 | fi 644 | if [ -n "$FORCE_DIR" ]; then 645 | echo "${C_ERR}Error: Conflict: --rm-rf cannot be used in submodule mode${C_RST}" >&2 646 | exit 1 647 | fi 648 | if [ "$PRESERVE" = X ] && [ -z "$RAW" ]; then 649 | [ -z "$QUIET" ] && echo "${C_WARN}Warning: git-gets by default has -x enabled in submodule mode${C_RST}" >&2 650 | fi 651 | [ -z "$PRESERVE" ] && PRESERVE=X 652 | if [ -n "$GIT_WORK_TREE" ]; then 653 | GIT_WORK_TREE="$(realpath "$GIT_WORK_TREE")" 654 | else 655 | GIT_WORK_TREE="$(git -C "$GIT_WORK_TREE" rev-parse --show-toplevel)" 656 | fi 657 | if [ -n "$GIT_DIR" ]; then 658 | GIT_DIR="$(realpath "$GIT_DIR")" 659 | else 660 | GIT_DIR="$(realpath "$(git rev-parse --git-dir)")" 661 | fi 662 | export GIT_WORK_TREE 663 | export GIT_DIR 664 | 665 | if [ -n "$VERBOSE" ]; then 666 | printf "${C_DBG}RAW=%q${C_RST}\n" "$RAW" >&2 667 | printf "${C_DBG}PRESERVE=%q${C_RST}\n" "$PRESERVE" >&2 668 | printf "${C_DBG}TAG=%q${C_RST}\n" "$TAG" >&2 669 | printf "${C_DBG}TAG_FILE=%q${C_RST}\n" "$TAG_FILE" >&2 670 | printf "${C_DBG}PARALLEL=%q${C_RST}\n" "$PARALLEL" >&2 671 | printf "${C_DBG}CONFIRM=%q${C_RST}\n" "$CONFIRM" >&2 672 | printf "${C_DBG}NO_INIT=%q${C_RST}\n" "$NO_INIT" >&2 673 | printf "${C_DBG}NO_RECURSIVE=%q${C_RST}\n" "$NO_RECURSIVE" >&2 674 | printf "${C_DBG}GIT_DIR=%q${C_RST}\n" "$GIT_DIR" >&2 675 | printf "${C_DBG}GIT_WORK_TREE=%q${C_RST}\n" "$GIT_WORK_TREE" >&2 676 | fi 677 | TMP_LOG="$(realpath "$(mktemp)")" 678 | finish() { 679 | cd / 680 | rm -f "$TMP_LOG" 681 | } 682 | trap finish EXIT 683 | 684 | cd "$GIT_WORK_TREE" 685 | if [ -n "$(git status --porcelain --untracked-files=no --ignore-submodules=dirty --ignored=no)" ]; then 686 | echo "${C_ERR}Error: Your stage / worktree is NOT clean. Too dangerous to proceed.${C_RST}" >&2 687 | exit 1 688 | fi 689 | got_repo "$(git rev-parse HEAD)" 690 | 691 | exit 0 692 | fi 693 | 694 | if [ -n "$NO_INIT" ]; then 695 | echo "${C_ERR}Error: Conflict: --no-init cannot be used in regular mode, consider using git-get instead${C_RST}" >&2 696 | exit 1 697 | fi 698 | 699 | resolve_gh_url() { 700 | GITHUB=REPO 701 | AMBI= 702 | if grep -qE '^[^/]+/[^/]+$' <<<"$1"; then 703 | GH_REPO="${1%.git}" 704 | elif grep -qE '^[^/]+/[^/]+/commit/[0-9a-f]{4,40}$' <<<"$1"; then 705 | if [ "${#POSITIONAL[@]}" -ne 1 ]; then 706 | echo "${C_ERR}Error: Commit is already specified in the URL${C_RST}" >&2 707 | exit 1 708 | fi 709 | GH_REPO="$(grep -Eo '^[^/]+/[^/]+/commit/' <<<"$1")" 710 | GH_REPO="${GH_REPO%/commit/}" 711 | BRANCH="$(sed -E 's_^[^/]+/[^/]+/commit/__' <<<"$1")" 712 | elif grep -qE '^[^/]+/[^/]+/tree/' <<<"$1"; then 713 | if [ "${#POSITIONAL[@]}" -ne 1 ]; then 714 | echo "${C_ERR}Error: Branch is already specified in the URL${C_RST}" >&2 715 | exit 1 716 | fi 717 | GH_REPO="$(grep -Eo '^[^/]+/[^/]+/tree/' <<<"$1")" 718 | GH_REPO="${GH_REPO%/tree/}" 719 | BRANCH="$(sed -E 's_^[^/]+/[^/]+/tree/__' <<<"$1")" 720 | AMBI=VERY_MUCH 721 | elif grep -qE '^[^/]+/[^/]+/blob/' <<<"$1"; then 722 | if [ -n "$PRESERVE" ]; then 723 | echo "${C_ERR}Error: Conflict: -x|-g|--preserve-git and -- (in the URL)${C_RST}" >&2 724 | exit 1 725 | fi 726 | if [ "${#POSITIONAL[@]}" -ne 1 ]; then 727 | echo "${C_ERR}Error: Branch is already specified in the URL${C_RST}" >&2 728 | exit 1 729 | fi 730 | GH_REPO="$(grep -Eo '^[^/]+/[^/]+/blob/' <<<"$1")" 731 | GH_REPO="${GH_REPO%/blob/}" 732 | BRANCH="$(sed -E 's_^[^/]+/[^/]+/blob/__' <<<"$1")" 733 | AMBI=YES 734 | else 735 | echo "${C_ERR}Error: GitHub URL format not supported, only repo/tree/blob/commit will work${C_RST}" >&2 736 | exit 1 737 | fi 738 | 739 | if [ -n "$GH_USE_HTTPS" ]; then 740 | REPO="https://github.com/$GH_REPO.git" 741 | else 742 | REPO="git@github.com:$GH_REPO.git" 743 | fi 744 | 745 | if [ -n "$AMBI" ]; then 746 | if [ -z "$(git ls-remote "$REPO" "$BRANCH")" ]; then 747 | echo "${C_ERR}Error: git-gets only works on a whole repository, not a directory or file.${C_RST}" >&2 748 | exit 1 749 | fi 750 | fi 751 | unset AMBI 752 | } 753 | 754 | match_gh_url() { 755 | [[ ! "${POSITIONAL[0]}" =~ ^$1 ]] && return 1 756 | [ -n "$2" ] && [ -z "$QUIET" ] && echo "${C_WARN}Warning: $1 is an unencryped protocol${C_RST}" >&2 757 | if [ -n "$3" ]; then 758 | "$3" "${POSITIONAL[0]#${1}}" YES 759 | else 760 | GITHUB=REPO 761 | GH_REPO="${POSITIONAL[0]#${1}}" 762 | GH_REPO="${GH_REPO%/}" 763 | GH_REPO="${GH_REPO%.git}" 764 | if [ -n "$GH_USE_HTTPS" ]; then 765 | REPO="https://github.com/$GH_REPO.git" 766 | elif [ -n "$GH_USE_SSH" ]; then 767 | REPO="git@github.com:$GH_REPO.git" 768 | else 769 | REPO="$1$GH_REPO.git" 770 | fi 771 | fi 772 | } 773 | 774 | match_gh_url "https://github.com/" '' resolve_gh_url || 775 | match_gh_url "http://github.com/" YES resolve_gh_url || 776 | match_gh_url "git://github.com/" YES '' || 777 | match_gh_url "ssh://git@github.com/" '' '' || 778 | match_gh_url "git@github.com:" '' '' || 779 | if [[ "${POSITIONAL[0]}" =~ ^.*/.*/.*$ ]]; then 780 | GITHUB= 781 | GH_REPO= 782 | REPO="${POSITIONAL[0]}" 783 | else 784 | GITHUB=REPO 785 | GH_REPO="${POSITIONAL[0]}" 786 | if [ -n "$GH_USE_HTTPS" ]; then 787 | REPO="https://github.com/${POSITIONAL[0]}.git" 788 | else 789 | REPO="git@github.com:${POSITIONAL[0]}.git" 790 | fi 791 | fi 792 | 793 | if [ -n "$UPSTREAM" ]; then 794 | if [ "$GITHUB" != REPO ]; then 795 | [ -z "$QUIET" ] && echo "${C_WARN}Warning: -u is ignored because of lack of support for $REPO.${C_RST}" >&2 796 | UPSTREAM= 797 | elif ! which curl >/dev/null 2>/dev/null; then 798 | [ -z "$QUIET" ] && echo "${C_WARN}Warning: -u is ignored because curl(1) is not found in PATH.${C_RST}" >&2 799 | UPSTREAM= 800 | else 801 | set +e 802 | UPSTREAM="$(curl -fsL -H "Accept: application/vnd.github+json" "https://api.github.com/repos/$GH_REPO" \ 803 | | sed -nE '/^ "full_name": /{ 804 | s/^ "full_name": "(.*)",$/\1/ 805 | p 806 | q 807 | }')" 808 | set -e 809 | if [ -z "$UPSTREAM" ]; then 810 | [ -z "$QUIET" ] && echo "${C_WARN}Warning: Failed to obtain the upstream of $REPO, maybe it's not a fork.${C_RST}" >&2 811 | elif [ "$UPSTREAM" = "$GH_REPO" ]; then 812 | [ -z "$QUIET" ] && echo "${C_WARN}Warning: -u is ignored because it .${C_RST}" >&2 813 | UPSTREAM= 814 | else 815 | UPSTREAM="${REPO/"$GH_REPO"/"$UPSTREAM"}" 816 | fi 817 | fi 818 | fi 819 | 820 | BASENAME="$(basename "$REPO")" 821 | BASENAME="${BASENAME%.git}" 822 | if [ -z "$OUTPUT" ]; then 823 | OUTPUT="$BASENAME" 824 | fi 825 | 826 | if [ ! "$OUTPUT" = '-' ]; then 827 | OUTPUT="$(fakerealpath "$OUTPUT")" 828 | fi 829 | 830 | if [ "$BRANCH" = "HEAD" ]; then 831 | [ -n "$VERBOSE" ] && echo "${C_INFO}Resolving HEAD...${C_RST}" >&2 832 | BRANCH="$(git ls-remote --symref "$REPO" HEAD | { grep '^ref:' || true; } | cut -d $'\t' -f 1)" 833 | if [ -z "$BRANCH" ]; then 834 | [ -z "$QUIET" ] && echo "${C_WARN}Warning: Weird repo HEAD non-symbolic, still proceeding${C_RST}" >&2 835 | BRANCH=HEAD 836 | else 837 | BRANCH="${BRANCH#ref: }" 838 | if [ "${BRANCH#refs/heads/}" = "${BRANCH}" ]; then 839 | [ -z "$QUIET" ] && echo "${C_WARN}Warning: Weird repo HEAD symbolic, still proceeding${C_RST}" >&2 840 | else 841 | BRANCH="${BRANCH#refs/heads/}" 842 | fi 843 | fi 844 | fi 845 | 846 | if [ -n "$VERBOSE" ]; then 847 | SHA1_SELF="$(git hash-object -t blob --no-filters "$0" || true)" 848 | printf "${C_DBG}GIT_GET_VERSION=%q${C_RST}\n" "$GIT_GET_VERSION" >&2 849 | printf "${C_DBG}SHA1_SELF=%q${C_RST}\n" "$SHA1_SELF" >&2 850 | printf "${C_DBG}RAW=%q${C_RST}\n" "$RAW" >&2 851 | printf "${C_DBG}FORCE_DIR=%q${C_RST}\n" "$FORCE_DIR" >&2 852 | printf "${C_DBG}OUTPUT=%q${C_RST}\n" "$OUTPUT" >&2 853 | printf "${C_DBG}PRESERVE=%q${C_RST}\n" "$PRESERVE" >&2 854 | printf "${C_DBG}TAG=%q${C_RST}\n" "$TAG" >&2 855 | printf "${C_DBG}TAG_FILE=%q${C_RST}\n" "$TAG_FILE" >&2 856 | printf "${C_DBG}PARALLEL=%q${C_RST}\n" "$PARALLEL" >&2 857 | printf "${C_DBG}CONFIRM=%q${C_RST}\n" "$CONFIRM" >&2 858 | printf "${C_DBG}NO_RECURSIVE=%q${C_RST}\n" "$NO_RECURSIVE" >&2 859 | printf "${C_DBG}GITHUB=%q${C_RST}\n" "$GITHUB" >&2 860 | printf "${C_DBG}GH_REPO=%q${C_RST}\n" "$GH_REPO" >&2 861 | printf "${C_DBG}REPO=%q${C_RST}\n" "$REPO" >&2 862 | printf "${C_DBG}UPSTREAM=%q${C_RST}\n" "$UPSTREAM" >&2 863 | printf "${C_DBG}BRANCH=%q${C_RST}\n" "$BRANCH" >&2 864 | printf "${C_DBG}BASENAME=%q${C_RST}\n" "$BASENAME" >&2 865 | fi 866 | 867 | if [ "$OUTPUT" = "-" ]; then 868 | true 869 | elif [ -d "$OUTPUT" ]; then 870 | if [ -z "$FORCE_DIR" ]; then 871 | printf "${C_ERR}Error: Directory %q exists${C_RST}\n" "$OUTPUT" >&2 872 | exit 1 873 | fi 874 | elif [ -f "$OUTPUT" ]; then 875 | if [ -z "$FORCE" ]; then 876 | printf "${C_ERR}Error: File %q exists${C_RST}\n" "$OUTPUT" >&2 877 | exit 1 878 | fi 879 | elif [ -e "$OUTPUT" ]; then 880 | printf "${C_ERR}Error: Weird file %q exists${C_RST}\n" "$OUTPUT" >&2 881 | exit 1 882 | fi 883 | 884 | WORK_DIR="$(realpath "$(mktemp -d)")" 885 | finish() { 886 | set +eu 887 | cd / 888 | if [ -n "$KEEP_WORK_DIR" ]; then 889 | printf "${C_WARN}Notice: WORK_DIR located at %s${C_RST}\n" "$WORK_DIR" 890 | else 891 | rm -rf "$WORK_DIR" 892 | fi 893 | } 894 | trap finish EXIT 895 | cd "$WORK_DIR" 896 | TMP_LOG="$WORK_DIR/parallel.log" 897 | 898 | [ -n "$VERBOSE" ] && printf "${C_DBG}WORK_DIR=%q${C_RST}\n" "$WORK_DIR" >&2 899 | 900 | # 0. git 2.20+ -> shallow + [filter] -> filter 901 | if git_new; then 902 | mkdir -p "$BASENAME" 903 | if [ ! "$PRESERVE" = X ] && [ -n "$(git ls-remote "$REPO" "$BRANCH")" ]; then 904 | ARGS=(git clone --bare) 905 | [ -n "$QUIET" ] && ARGS+=(-q) 906 | [ -z "$QUIET" ] && ARGS+=(--progress) 907 | [ ! "$BRANCH" = "HEAD" ] && ARGS+=(--branch "$BRANCH") 908 | ARGS+=(--depth 1 --no-tags) 909 | ARGS+=(--filter blob:none) 910 | ARGS+=("$REPO" "$BASENAME/.git") 911 | [ -n "$VERBOSE" ] && (printf "${C_NOTICE}"; printf '%q ' "${ARGS[@]}"; printf "${C_RST}\n") >&2 912 | set +e 913 | if "${ARGS[@]}"; then 914 | set -e 915 | GIT_WORK_TREE="$(realpath "$BASENAME")" 916 | GIT_DIR="$(realpath "$BASENAME/.git")" 917 | export GIT_WORK_TREE 918 | export GIT_DIR 919 | git config --bool core.bare false 920 | got_repo "$(git rev-parse HEAD)" 921 | fi 922 | set -e 923 | [ -z "$QUIET" ] && echo "${C_WARN}Warning: Failed git clone, will attempt another method${C_RST}" 924 | fi 925 | if true; then 926 | ARGS=(git clone --mirror --filter tree:0) 927 | [ -n "$QUIET" ] && ARGS+=(-q) 928 | [ -z "$QUIET" ] && ARGS+=(--progress) 929 | ARGS+=("$REPO" "$BASENAME/.git") 930 | [ -n "$VERBOSE" ] && (printf "${C_NOTICE}"; printf '%q ' "${ARGS[@]}"; printf "${C_RST}\n") >&2 931 | set +e 932 | if "${ARGS[@]}"; then 933 | SHA1="$(git -C "$BASENAME" rev-parse "$BRANCH")" 934 | if [ -n "$SHA1" ]; then 935 | [ -z "$QUIET" ] && printf "${C_INFO}Got SHA1: %q${C_RST}\n" "$SHA1" >&2 936 | set -e 937 | NSHA1="$(git --git-dir="$BASENAME/.git" rev-parse "$SHA1^{commit}")" 938 | [ ! "$SHA1" = "$NSHA1" ] && printf "${C_INFO}Got actual SHA1: %q${C_RST}\n" "$NSHA1" >&2 939 | GIT_WORK_TREE="$(realpath "$BASENAME")" 940 | GIT_DIR="$(realpath "$BASENAME/.git")" 941 | export GIT_WORK_TREE 942 | export GIT_DIR 943 | git config --bool core.bare false 944 | git update-ref --no-deref HEAD "$NSHA1" 945 | got_repo "$NSHA1" 946 | fi 947 | fi 948 | set -e 949 | fi 950 | rm -rf "$BASENAME" 951 | fi 952 | 953 | printf "${C_ERR}Error: No viable method.${C_RST}\n" >&2 954 | exit 3 955 | --------------------------------------------------------------------------------