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" "path/filepath"
"strings" "strings"
"github.com/git-lfs/git-lfs/lfs"
"github.com/git-lfs/git-lfs/localstorage" "github.com/git-lfs/git-lfs/localstorage"
"github.com/git-lfs/git-lfs/subprocess" "github.com/git-lfs/git-lfs/subprocess"
@ -16,6 +17,8 @@ import (
var ( var (
cloneFlags git.CloneFlags cloneFlags git.CloneFlags
cloneSkipRepoInstall bool
) )
func cloneCommand(cmd *cobra.Command, args []string) { 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) 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 { 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(&includeArg, "include", "I", "", "Include a list of paths")
cmd.Flags().StringVarP(&excludeArg, "exclude", "X", "", "Exclude 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 Clone an LFS enabled Git repository more efficiently by disabling LFS during the
git clone, then performing a 'git lfs pull' directly afterwards. 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 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 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 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>: * `-X` <paths> `--exclude=`<paths>:
See [INCLUDE AND EXCLUDE] See [INCLUDE AND EXCLUDE]
* `--skip-repo`:
Skip installing repo-level hooks (.git/hooks) that LFS requires. Disabled by
default.
## INCLUDE AND EXCLUDE ## INCLUDE AND EXCLUDE
You can configure Git LFS to only fetch objects to satisfy references in certain 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 < "file1.dat") -eq 110 ]
[ $(wc -c < "file2.dat") -eq 75 ] [ $(wc -c < "file2.dat") -eq 75 ]
[ $(wc -c < "file3.dat") -eq 66 ] [ $(wc -c < "file3.dat") -eq 66 ]
assert_hooks "$(dot_git_dir)"
[ ! -e "lfs" ] [ ! -e "lfs" ]
popd popd
# Now check clone with implied dir # Now check clone with implied dir
@ -74,6 +75,7 @@ begin_test "clone"
[ $(wc -c < "file1.dat") -eq 110 ] [ $(wc -c < "file1.dat") -eq 110 ]
[ $(wc -c < "file2.dat") -eq 75 ] [ $(wc -c < "file2.dat") -eq 75 ]
[ $(wc -c < "file3.dat") -eq 66 ] [ $(wc -c < "file3.dat") -eq 66 ]
assert_hooks "$(dot_git_dir)"
[ ! -e "lfs" ] [ ! -e "lfs" ]
popd popd
@ -130,6 +132,7 @@ begin_test "cloneSSL"
[ $(wc -c < "file1.dat") -eq 100 ] [ $(wc -c < "file1.dat") -eq 100 ]
[ $(wc -c < "file2.dat") -eq 75 ] [ $(wc -c < "file2.dat") -eq 75 ]
[ $(wc -c < "file3.dat") -eq 30 ] [ $(wc -c < "file3.dat") -eq 30 ]
assert_hooks "$(dot_git_dir)"
popd popd
@ -188,6 +191,7 @@ begin_test "clone ClientCert"
[ $(wc -c < "file1.dat") -eq 100 ] [ $(wc -c < "file1.dat") -eq 100 ]
[ $(wc -c < "file2.dat") -eq 75 ] [ $(wc -c < "file2.dat") -eq 75 ]
[ $(wc -c < "file3.dat") -eq 30 ] [ $(wc -c < "file3.dat") -eq 30 ]
assert_hooks "$(dot_git_dir)"
popd popd
@ -257,6 +261,7 @@ begin_test "clone with flags"
[ -e "fileonbranch2.dat" ] [ -e "fileonbranch2.dat" ]
# confirm remote is called differentorigin # confirm remote is called differentorigin
git remote get-url differentorigin git remote get-url differentorigin
assert_hooks "$(dot_git_dir)"
popd popd
rm -rf "$newclonedir" rm -rf "$newclonedir"
@ -269,6 +274,7 @@ begin_test "clone with flags"
fi fi
[ -e "$newclonedir/.git" ] [ -e "$newclonedir/.git" ]
[ -d "$gitdir/objects" ] [ -d "$gitdir/objects" ]
assert_hooks "$gitdir"
rm -rf "$newclonedir" rm -rf "$newclonedir"
rm -rf "$gitdir" rm -rf "$gitdir"
@ -329,6 +335,7 @@ begin_test "clone (with include/exclude args)"
[ "a" = "$(cat a-dupe.dat)" ] [ "a" = "$(cat a-dupe.dat)" ]
[ "$(pointer $contents_a_oid 1)" = "$(cat dupe-a.dat)" ] [ "$(pointer $contents_a_oid 1)" = "$(cat dupe-a.dat)" ]
[ "$(pointer $contents_b_oid 1)" = "$(cat b.dat)" ] [ "$(pointer $contents_b_oid 1)" = "$(cat b.dat)" ]
assert_hooks "$(dot_git_dir)"
popd popd
local_reponame="clone_with_excludes" local_reponame="clone_with_excludes"
@ -338,6 +345,7 @@ begin_test "clone (with include/exclude args)"
refute_local_object "$contents_a_oid" refute_local_object "$contents_a_oid"
[ "$(pointer $contents_a_oid 1)" = "$(cat a.dat)" ] [ "$(pointer $contents_a_oid 1)" = "$(cat a.dat)" ]
[ "b" = "$(cat b.dat)" ] [ "b" = "$(cat b.dat)" ]
assert_hooks "$(dot_git_dir)"
popd popd
) )
end_test end_test
@ -401,6 +409,7 @@ begin_test "clone (with .lfsconfig)"
pushd "$local_reponame" pushd "$local_reponame"
assert_local_object "$contents_a_oid" 1 assert_local_object "$contents_a_oid" 1
refute_local_object "$contents_b_oid" refute_local_object "$contents_b_oid"
assert_hooks "$(dot_git_dir)"
popd popd
echo "test: clone with lfs.fetchinclude in .lfsconfig, and args" echo "test: clone with lfs.fetchinclude in .lfsconfig, and args"
@ -409,6 +418,7 @@ begin_test "clone (with .lfsconfig)"
pushd "$local_reponame" pushd "$local_reponame"
refute_local_object "$contents_a_oid" refute_local_object "$contents_a_oid"
assert_local_object "$contents_b_oid" 1 assert_local_object "$contents_b_oid" 1
assert_hooks "$(dot_git_dir)"
popd popd
popd popd
@ -431,6 +441,7 @@ begin_test "clone (with .lfsconfig)"
cat ".lfsconfig" cat ".lfsconfig"
assert_local_object "$contents_b_oid" 1 assert_local_object "$contents_b_oid" 1
refute_local_object "$contents_a_oid" refute_local_object "$contents_a_oid"
assert_hooks "$(dot_git_dir)"
popd popd
echo "test: clone with lfs.fetchexclude in .lfsconfig, and args" echo "test: clone with lfs.fetchexclude in .lfsconfig, and args"
@ -439,6 +450,7 @@ begin_test "clone (with .lfsconfig)"
pushd "$local_reponame" pushd "$local_reponame"
assert_local_object "$contents_a_oid" 1 assert_local_object "$contents_a_oid" 1
refute_local_object "$contents_b_oid" refute_local_object "$contents_b_oid"
assert_hooks "$(dot_git_dir)"
popd popd
popd popd
@ -506,6 +518,7 @@ begin_test "clone with submodules"
# check everything is where it should be # check everything is where it should be
cd $local_reponame cd $local_reponame
assert_hooks "$(dot_git_dir)"
# check LFS store and working copy # check LFS store and working copy
assert_local_object "$contents_root_oid" "${#contents_root}" assert_local_object "$contents_root_oid" "${#contents_root}"
[ $(wc -c < "root.dat") -eq ${#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" git lfs clone $GITSERVER/$reponame "." 2>&1 | grep "Git LFS"
assert_local_object "$contents_oid" 8 assert_local_object "$contents_oid" 8
assert_hooks "$(dot_git_dir)"
[ ! -f ./lfs ] [ ! -f ./lfs ]
popd popd
) )

@ -194,6 +194,28 @@ refute_file_writable() {
ls -l "$1" | grep -e "^-r-" 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 returns a string Git LFS pointer file.
# #
# $ pointer abc-some-oid 123 <version> # $ pointer abc-some-oid 123 <version>