commands/clone: install repo-level hooks after git lfs clone

This commit is contained in:
Taylor Blau 2017-03-23 10:54:52 -06:00
parent 6a609baef3
commit 589f04dd9f
4 changed files with 58 additions and 0 deletions

@ -6,6 +6,7 @@ import (
"path/filepath"
"strings"
"github.com/git-lfs/git-lfs/lfs"
"github.com/git-lfs/git-lfs/localstorage"
"github.com/git-lfs/git-lfs/subprocess"
@ -16,6 +17,8 @@ import (
var (
cloneFlags git.CloneFlags
cloneSkipRepoInstall bool
)
func cloneCommand(cmd *cobra.Command, args []string) {
@ -82,6 +85,15 @@ func cloneCommand(cmd *cobra.Command, args []string) {
Exit("Error performing 'git lfs pull' for submodules: %v", err)
}
}
if !cloneSkipRepoInstall {
// If --skip-repo wasn't given, install repo-level hooks while
// we're still in the checkout directory.
if err := lfs.InstallHooks(false); err != nil {
ExitWithError(err)
}
}
}
func postCloneSubmodules(args []string) error {
@ -139,5 +151,7 @@ func init() {
cmd.Flags().StringVarP(&includeArg, "include", "I", "", "Include a list of paths")
cmd.Flags().StringVarP(&excludeArg, "exclude", "X", "", "Exclude a list of paths")
cmd.Flags().BoolVar(&cloneSkipRepoInstall, "skip-repo", false, "Skip LFS repo setup")
})
}

@ -10,6 +10,10 @@ git-lfs-clone(1) -- Efficiently clone a LFS-enabled repository
Clone an LFS enabled Git repository more efficiently by disabling LFS during the
git clone, then performing a 'git lfs pull' directly afterwards.
'git lfs clone' also installs all of the repo-level hooks (.git/hooks) that LFS
requires to operate. If `--separate-git-dir` is given, the hooks will be
installed there.
This is faster than a regular 'git clone' because that will download LFS content
using the smudge filter, which is executed individually per file in the working
copy. This is relatively inefficient compared to the batch mode and parallel
@ -25,6 +29,10 @@ All options supported by 'git clone'
* `-X` <paths> `--exclude=`<paths>:
See [INCLUDE AND EXCLUDE]
* `--skip-repo`:
Skip installing repo-level hooks (.git/hooks) that LFS requires. Disabled by
default.
## INCLUDE AND EXCLUDE
You can configure Git LFS to only fetch objects to satisfy references in certain

@ -58,6 +58,7 @@ begin_test "clone"
[ $(wc -c < "file1.dat") -eq 110 ]
[ $(wc -c < "file2.dat") -eq 75 ]
[ $(wc -c < "file3.dat") -eq 66 ]
assert_hooks "$(dot_git_dir)"
[ ! -e "lfs" ]
popd
# Now check clone with implied dir
@ -74,6 +75,7 @@ begin_test "clone"
[ $(wc -c < "file1.dat") -eq 110 ]
[ $(wc -c < "file2.dat") -eq 75 ]
[ $(wc -c < "file3.dat") -eq 66 ]
assert_hooks "$(dot_git_dir)"
[ ! -e "lfs" ]
popd
@ -130,6 +132,7 @@ begin_test "cloneSSL"
[ $(wc -c < "file1.dat") -eq 100 ]
[ $(wc -c < "file2.dat") -eq 75 ]
[ $(wc -c < "file3.dat") -eq 30 ]
assert_hooks "$(dot_git_dir)"
popd
@ -188,6 +191,7 @@ begin_test "clone ClientCert"
[ $(wc -c < "file1.dat") -eq 100 ]
[ $(wc -c < "file2.dat") -eq 75 ]
[ $(wc -c < "file3.dat") -eq 30 ]
assert_hooks "$(dot_git_dir)"
popd
@ -257,6 +261,7 @@ begin_test "clone with flags"
[ -e "fileonbranch2.dat" ]
# confirm remote is called differentorigin
git remote get-url differentorigin
assert_hooks "$(dot_git_dir)"
popd
rm -rf "$newclonedir"
@ -269,6 +274,7 @@ begin_test "clone with flags"
fi
[ -e "$newclonedir/.git" ]
[ -d "$gitdir/objects" ]
assert_hooks "$gitdir"
rm -rf "$newclonedir"
rm -rf "$gitdir"
@ -329,6 +335,7 @@ begin_test "clone (with include/exclude args)"
[ "a" = "$(cat a-dupe.dat)" ]
[ "$(pointer $contents_a_oid 1)" = "$(cat dupe-a.dat)" ]
[ "$(pointer $contents_b_oid 1)" = "$(cat b.dat)" ]
assert_hooks "$(dot_git_dir)"
popd
local_reponame="clone_with_excludes"
@ -338,6 +345,7 @@ begin_test "clone (with include/exclude args)"
refute_local_object "$contents_a_oid"
[ "$(pointer $contents_a_oid 1)" = "$(cat a.dat)" ]
[ "b" = "$(cat b.dat)" ]
assert_hooks "$(dot_git_dir)"
popd
)
end_test
@ -401,6 +409,7 @@ begin_test "clone (with .lfsconfig)"
pushd "$local_reponame"
assert_local_object "$contents_a_oid" 1
refute_local_object "$contents_b_oid"
assert_hooks "$(dot_git_dir)"
popd
echo "test: clone with lfs.fetchinclude in .lfsconfig, and args"
@ -409,6 +418,7 @@ begin_test "clone (with .lfsconfig)"
pushd "$local_reponame"
refute_local_object "$contents_a_oid"
assert_local_object "$contents_b_oid" 1
assert_hooks "$(dot_git_dir)"
popd
popd
@ -431,6 +441,7 @@ begin_test "clone (with .lfsconfig)"
cat ".lfsconfig"
assert_local_object "$contents_b_oid" 1
refute_local_object "$contents_a_oid"
assert_hooks "$(dot_git_dir)"
popd
echo "test: clone with lfs.fetchexclude in .lfsconfig, and args"
@ -439,6 +450,7 @@ begin_test "clone (with .lfsconfig)"
pushd "$local_reponame"
assert_local_object "$contents_a_oid" 1
refute_local_object "$contents_b_oid"
assert_hooks "$(dot_git_dir)"
popd
popd
@ -506,6 +518,7 @@ begin_test "clone with submodules"
# check everything is where it should be
cd $local_reponame
assert_hooks "$(dot_git_dir)"
# check LFS store and working copy
assert_local_object "$contents_root_oid" "${#contents_root}"
[ $(wc -c < "root.dat") -eq ${#contents_root} ]
@ -557,6 +570,7 @@ begin_test "clone in current directory"
git lfs clone $GITSERVER/$reponame "." 2>&1 | grep "Git LFS"
assert_local_object "$contents_oid" 8
assert_hooks "$(dot_git_dir)"
[ ! -f ./lfs ]
popd
)

@ -194,6 +194,28 @@ refute_file_writable() {
ls -l "$1" | grep -e "^-r-"
}
git_root() {
git rev-parse --show-toplevel 2>/dev/null
}
dot_git_dir() {
echo "$(git_root)/.git"
}
assert_hooks() {
local git_root="$1"
if [ -z "$git_root" ]; then
echo >&2 "fatal: (assert_hooks) not in git repository"
exit 1
fi
[ -x "$git_root/hooks/post-checkout" ]
[ -x "$git_root/hooks/post-commit" ]
[ -x "$git_root/hooks/post-merge" ]
[ -x "$git_root/hooks/pre-push" ]
}
# pointer returns a string Git LFS pointer file.
#
# $ pointer abc-some-oid 123 <version>