From: Stefan Hagen Subject: got: don't search through ignored paths/files on commit To: gameoftrees@openbsd.org Date: Fri, 2 Sep 2022 17:15:19 +0200 Hi, I'm using my home directory as worktree checkout (for dotfile management). This leads to a super slow "got status" because it walks through my whole home directory to show unversioned files. I fixed this by creating a .gitignore file with "**" and I add files with got add -I. This works great and "got status" is fast again. Then I noticed that "got commit" is still very slow and walking through all files. I don't think this is necessary, because the commit is only interested in files that have been added to the worktree already. And it checks the tree first before it looks through the file system. With his patch, got commit behaves like got status and won't look at files that are ignored. Actually, I don't really see a point why it should ever look at files not added to the worktree before. So we can probably be more drastic here and disable the file system traversal for commit completely? Well, this patch makes got nicer for me. And there's a small regress test that works with and without the change to show that there's no difference in behavior. Best Regards, Stefan diff /home/sdk/code/got commit - 1d09d7aab4ab3e72f40b6ea6a78164bf6e6f5477 path + /home/sdk/code/got blob - f82a9689259ee66048cc0d9c503e6eb31568215b file + lib/worktree.c --- lib/worktree.c +++ lib/worktree.c @@ -5921,7 +5921,7 @@ got_worktree_commit(struct got_object_id **new_commit_ cc_arg.allow_bad_symlinks = allow_bad_symlinks; TAILQ_FOREACH(pe, paths, entry) { err = worktree_status(worktree, pe->path, fileindex, repo, - collect_commitables, &cc_arg, NULL, NULL, 1, 0); + collect_commitables, &cc_arg, NULL, NULL, 0, 0); if (err) goto done; } blob - 98c2c07a14f46473a38a3a8a4e3118a018b05d80 file + regress/cmdline/commit.sh --- regress/cmdline/commit.sh +++ regress/cmdline/commit.sh @@ -1619,7 +1619,68 @@ test_commit_large_file() { } +test_commit_gitignore() { + local testroot=`test_init commit_gitignores` + got checkout $testroot/repo $testroot/wt > /dev/null + ret=$? + if [ $ret -ne 0 ]; then + test_done "$testroot" "$ret" + return 1 + fi + + mkdir -p $testroot/wt/tree1/foo + mkdir -p $testroot/wt/tree2/foo + echo "tree1/**" > $testroot/wt/.gitignore + echo "tree2/**" >> $testroot/wt/.gitignore + echo -n > $testroot/wt/tree1/bar + echo -n > $testroot/wt/tree1/foo/baz + echo -n > $testroot/wt/tree2/bar + echo -n > $testroot/wt/tree2/foo/baz + echo -n > $testroot/wt/epsilon/zeta1 + echo -n > $testroot/wt/epsilon/zeta2 + + (cd $testroot/wt && got add -I -R tree1 > /dev/null) + (cd $testroot/wt && got add -I tree2/foo/baz > /dev/null) + (cd $testroot/wt && got commit -m "gitignore add" > /dev/null) + (cd $testroot/wt && got log -P -l 1 | egrep '^ .' > $testroot/stdout) + + echo ' gitignore add' > $testroot/stdout.expected + echo ' A tree1/bar' >> $testroot/stdout.expected + echo ' A tree1/foo/baz' >> $testroot/stdout.expected + echo ' A tree2/foo/baz' >> $testroot/stdout.expected + + cmp -s $testroot/stdout.expected $testroot/stdout + ret=$? + if [ $ret -ne 0 ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 + fi + + echo touch > $testroot/wt/tree1/bar + echo touch > $testroot/wt/tree1/foo/baz + echo touch > $testroot/wt/epsilon/zeta1 + + (cd $testroot/wt && got commit -m "gitignore change" > /dev/null) + (cd $testroot/wt && got log -P -l 1 | egrep '^ .' > $testroot/stdout) + + echo ' gitignore change' > $testroot/stdout.expected + echo ' M tree1/bar' >> $testroot/stdout.expected + echo ' M tree1/foo/baz' >> $testroot/stdout.expected + + cmp -s $testroot/stdout.expected $testroot/stdout + ret=$? + if [ $ret -ne 0 ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 + fi + + test_done "$testroot" "$ret" +} + + test_parseargs "$@" run_test test_commit_basic run_test test_commit_new_subdir @@ -1648,3 +1709,4 @@ run_test test_commit_symlink run_test test_commit_fix_bad_symlink run_test test_commit_prepared_logmsg run_test test_commit_large_file +run_test test_commit_gitignore