threads / patch / 7242

patchMake gc a builtin.

Subject: [PATCH] Make gc a builtin.

## tl;dr

10 messages between Mar 14, 2007 and Mar 14, 2007. Diffs are folded; open one to read it.

replies: 9people: 7as markdown or json

James Bowes· Mar 14, 2007, 01:58 UTC · lore
Signed-off-by: James Bowes <jbowes@dangerouslyinc.com>
---
On 3/13/07, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
> If you say "return error(...);", there is _no_ way that multiple error
> messages are printed out.

Yeah, I wasn't testing well enough. If you pass the name of a non-existant command to run_command, then it will print out a message about not being able to exec. That's not going to help when the command runs but does something bad. So here's the patch with error().

-James
 Makefile     |    3 +-
 builtin-gc.c |   78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 builtin.h    |    1 +
 git-gc.sh    |   37 ---------------------------
 git.c        |    1 +
 5 files changed, 82 insertions(+), 38 deletions(-)
 create mode 100644 builtin-gc.c
 delete mode 100755 git-gc.sh
Show changes to 5 files +82 −38

Makefile, builtin-gc.c, builtin.h, git-gc.sh, git.c

diff --git a/Makefile b/Makefile
index 9b31565..1ccd52f 100644
--- a/Makefile
+++ b/Makefile
@@ -177,7 +177,7 @@ BASIC_LDFLAGS =
 SCRIPT_SH = \
 	git-bisect.sh git-checkout.sh \
 	git-clean.sh git-clone.sh git-commit.sh \
-	git-fetch.sh git-gc.sh \
+	git-fetch.sh \
 	git-ls-remote.sh \
 	git-merge-one-file.sh git-parse-remote.sh \
 	git-pull.sh git-rebase.sh \
@@ -297,6 +297,7 @@ BUILTIN_OBJS = \
 	builtin-fmt-merge-msg.o \
 	builtin-for-each-ref.o \
 	builtin-fsck.o \
+	builtin-gc.o \
 	builtin-grep.o \
 	builtin-init-db.o \
 	builtin-log.o \
diff --git a/builtin-gc.c b/builtin-gc.c
new file mode 100644
index 0000000..3b1f8c2
--- /dev/null
+++ b/builtin-gc.c
@@ -0,0 +1,78 @@
+/*
+ * git gc builtin command
+ *
+ * Cleanup unreachable files and optimize the repository.
+ *
+ * Copyright (c) 2007 James Bowes
+ *
+ * Based on git-gc.sh, which is
+ *
+ * Copyright (c) 2006 Shawn O. Pearce
+ */
+
+#include "cache.h"
+#include "run-command.h"
+
+#define FAILED_RUN "failed to run %s"
+
+static const char builtin_gc_usage[] = "git-gc [--prune]";
+
+static int pack_refs = -1;
+
+static const char *argv_pack_refs[] = {"pack-refs", "--prune", NULL};
+static const char *argv_reflog[] = {"reflog", "expire", "--all", NULL};
+static const char *argv_repack[] = {"repack", "-a", "-d", "-l", NULL};
+static const char *argv_prune[] = {"prune", NULL};
+static const char *argv_rerere[] = {"rerere", "gc", NULL};
+
+static int gc_config(const char *var, const char *value)
+{
+	if (!strcmp(var, "gc.packrefs")) {
+		if (!strcmp(value, "notbare"))
+			pack_refs = -1;
+		else
+			pack_refs = git_config_bool(var, value);
+		return 0;
+	}
+	return git_default_config(var, value);
+}
+
+int cmd_gc(int argc, const char **argv, const char *prefix)
+{
+	int i;
+	int prune = 0;
+
+	git_config(gc_config);
+
+	if (pack_refs < 0)
+		pack_refs = !is_bare_repository();
+
+	for (i = 1; i < argc; i++) {
+		const char *arg = argv[i];
+		if (!strcmp(arg, "--prune")) {
+			prune = 1;
+			continue;
+		}
+		/* perhaps other parameters later... */
+		break;
+	}
+	if (i != argc)
+		usage(builtin_gc_usage);
+
+	if (pack_refs && run_command_v_opt(argv_pack_refs, RUN_GIT_CMD))
+		return error(FAILED_RUN, argv_pack_refs[0]);
+
+	if (run_command_v_opt(argv_reflog, RUN_GIT_CMD))
+		return error(FAILED_RUN, argv_reflog[0]);
+
+	if (run_command_v_opt(argv_repack, RUN_GIT_CMD))
+		return error(FAILED_RUN, argv_repack[0]);
+
+	if (prune && run_command_v_opt(argv_prune, RUN_GIT_CMD))
+		return error(FAILED_RUN, argv_prune[0]);
+
+	if (run_command_v_opt(argv_rerere, RUN_GIT_CMD))
+		return error(FAILED_RUN, argv_rerere[0]);
+
+	return 0;
+}
diff --git a/builtin.h b/builtin.h
index 1cb64b7..af203e9 100644
--- a/builtin.h
+++ b/builtin.h
@@ -37,6 +37,7 @@ extern int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix);
 extern int cmd_for_each_ref(int argc, const char **argv, const char *prefix);
 extern int cmd_format_patch(int argc, const char **argv, const char *prefix);
 extern int cmd_fsck(int argc, const char **argv, const char *prefix);
+extern int cmd_gc(int argc, const char **argv, const char *prefix);
 extern int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix);
 extern int cmd_grep(int argc, const char **argv, const char *prefix);
 extern int cmd_help(int argc, const char **argv, const char *prefix);
diff --git a/git-gc.sh b/git-gc.sh
deleted file mode 100755
index 436d7ca..0000000
--- a/git-gc.sh
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2006, Shawn O. Pearce
-#
-# Cleanup unreachable files and optimize the repository.
-
-USAGE='[--prune]'
-SUBDIRECTORY_OK=Yes
-. git-sh-setup
-
-no_prune=:
-while case $# in 0) break ;; esac
-do
-	case "$1" in
-	--prune)
-		no_prune=
-		;;
-	--)
-		usage
-		;;
-	esac
-	shift
-done
-
-case "$(git config --get gc.packrefs)" in
-notbare|"")
-	test $(is_bare_repository) = true || pack_refs=true;;
-*)
-	pack_refs=$(git config --bool --get gc.packrefs)
-esac
-
-test "true" != "$pack_refs" ||
-git-pack-refs --prune &&
-git-reflog expire --all &&
-git-repack -a -d -l &&
-$no_prune git-prune &&
-git-rerere gc || exit
diff --git a/git.c b/git.c
index dde4d07..ed1c65e 100644
--- a/git.c
+++ b/git.c
@@ -249,6 +249,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
 		{ "format-patch", cmd_format_patch, RUN_SETUP },
 		{ "fsck", cmd_fsck, RUN_SETUP },
 		{ "fsck-objects", cmd_fsck, RUN_SETUP },
+		{ "gc", cmd_gc, RUN_SETUP },
 		{ "get-tar-commit-id", cmd_get_tar_commit_id },
 		{ "grep", cmd_grep, RUN_SETUP | USE_PAGER },
 		{ "help", cmd_help },
-- 
1.5.0.2
Shawn O. Pearce· Mar 14, 2007, 06:07 UTC · re: James Bowes · lore

Re: [PATCH] Make gc a builtin.

James Bowes <jbowes@dangerouslyinc.com> wrote:
> Signed-off-by: James Bowes <jbowes@dangerouslyinc.com>
ACK.  Very nicely done.
...
Show 14 quoted lines
> +	if (pack_refs && run_command_v_opt(argv_pack_refs, RUN_GIT_CMD))
> +		return error(FAILED_RUN, argv_pack_refs[0]);
> +
> +	if (run_command_v_opt(argv_reflog, RUN_GIT_CMD))
> +		return error(FAILED_RUN, argv_reflog[0]);
> +
> +	if (run_command_v_opt(argv_repack, RUN_GIT_CMD))
> +		return error(FAILED_RUN, argv_repack[0]);
> +
> +	if (prune && run_command_v_opt(argv_prune, RUN_GIT_CMD))
> +		return error(FAILED_RUN, argv_prune[0]);
> +
> +	if (run_command_v_opt(argv_rerere, RUN_GIT_CMD))
> +		return error(FAILED_RUN, argv_rerere[0]);
And isn't the above so much more readable than this mess?
Show 6 quoted lines
> -test "true" != "$pack_refs" ||
> -git-pack-refs --prune &&
> -git-reflog expire --all &&
> -git-repack -a -d -l &&
> -$no_prune git-prune &&
> -git-rerere gc || exit
Which is why I like builtins, and why I think Dscho does too.
-- 
Shawn.
Junio C Hamano· Mar 14, 2007, 07:19 UTC · re: Shawn O. Pearce · lore

Re: [PATCH] Make gc a builtin.

"Shawn O. Pearce" <spearce@spearce.org> writes:
> James Bowes <jbowes@dangerouslyinc.com> wrote:
>> Signed-off-by: James Bowes <jbowes@dangerouslyinc.com>
>
> ACK.  Very nicely done.

Perhaps. But we lost another sample script which made an entry barrier higher to a new person.

Show 10 quoted lines
>> +	if (run_command_v_opt(argv_rerere, RUN_GIT_CMD))
>> +		return error(FAILED_RUN, argv_rerere[0]);
>
> And isn't the above so much more readable than this mess?
>
>> -test "true" != "$pack_refs" ||
>> -git-pack-refs --prune &&
>> -git-reflog expire --all &&
>> -git-repack -a -d -l &&
>> ...

I do not necessarily think so. This is not even a performance critical part of the system, so if there _were_ no other constraints, I would rather keep scripts like this as scripts.

For things like this, scripts are much easier to read, understand and futz with, and command lists chained with && in shell scripts are very nice and compact way to express what is going on.

This is especially true if you have some specialized needs, if you do not expect you need to keep that change forever, and if you are lazy. For example, if you have a repository that you for some reason need to keep available to older dumb transport clients for now, you would disable "git-pack-refs --prune" line from your copy of the script version. No need to recompile.

Another example is git-repack script. When you have a specialized repacking needs (say, repack from a specific revision to make a .keep pack to avoid future excessive repacking), being able to check how the plumbing is used in git-repack script and run customized version of it is very handy. Once you rewrite it to sequence of

	if (run_command_v_opt(blech, RUN_GIT_CMD))
        	...

it becomes much harder to learn what the shell command equivalent that would suit your needs would be, and we would lose another command that would serve as a good example.

We are doing built-in _only_ because people on some platforms cannot sanely use POSIX shell scripts. I do not reject these "make X built-in" patches (when X is perfectly fine as a shell script) because I sympathize with people stuck on Windows, not because I think built-in is easier to read nor work with than scripts. There is a downside.

Theodore Tso· Mar 14, 2007, 07:44 UTC · re: Junio C Hamano · lore

Re: [PATCH] Make gc a builtin.

On Wed, Mar 14, 2007 at 12:19:07AM -0700, Junio C Hamano wrote:
Show 9 quoted lines
> >> -test "true" != "$pack_refs" ||
> >> -git-pack-refs --prune &&
> >> -git-reflog expire --all &&
> >> -git-repack -a -d -l &&
> >> ...
> 
> I do not necessarily think so.  This is not even a performance
> critical part of the system, so if there _were_ no other
> constraints, I would rather keep scripts like this as scripts.

I agree with Junio; I think the scripts are much more readable and easier to understand; In fact, it would be nice if the script were preserved somewhere, perhaps as comments in the .c file.

						- Ted
Santi Béjar· Mar 14, 2007, 07:55 UTC · re: Theodore Tso · lore

Re: [PATCH] Make gc a builtin.

On 3/14/07, Theodore Tso <tytso@mit.edu> wrote:
Show 15 quoted lines
> On Wed, Mar 14, 2007 at 12:19:07AM -0700, Junio C Hamano wrote:
> > >> -test "true" != "$pack_refs" ||
> > >> -git-pack-refs --prune &&
> > >> -git-reflog expire --all &&
> > >> -git-repack -a -d -l &&
> > >> ...
> >
> > I do not necessarily think so.  This is not even a performance
> > critical part of the system, so if there _were_ no other
> > constraints, I would rather keep scripts like this as scripts.
>
> I agree with Junio; I think the scripts are much more readable and
> easier to understand; In fact, it would be nice if the script were
> preserved somewhere, perhaps as comments in the .c file.
>
Or move them to contrib/examples, as was done with git-resolve.sh.
Santi
Junio C Hamano· Mar 14, 2007, 09:29 UTC · re: Santi Béjar · lore

Re: [PATCH] Make gc a builtin.

"Santi Béjar" <sbejar@gmail.com> writes:
Show 20 quoted lines
> On 3/14/07, Theodore Tso <tytso@mit.edu> wrote:
>> On Wed, Mar 14, 2007 at 12:19:07AM -0700, Junio C Hamano wrote:
>> > >> -test "true" != "$pack_refs" ||
>> > >> -git-pack-refs --prune &&
>> > >> -git-reflog expire --all &&
>> > >> -git-repack -a -d -l &&
>> > >> ...
>> >
>> > I do not necessarily think so.  This is not even a performance
>> > critical part of the system, so if there _were_ no other
>> > constraints, I would rather keep scripts like this as scripts.
>>
>> I agree with Junio; I think the scripts are much more readable and
>> easier to understand; In fact, it would be nice if the script were
>> preserved somewhere, perhaps as comments in the .c file.
>>
>
> Or move them to contrib/examples, as was done with git-resolve.sh.
>
> Santi
That probably is a sensible thing to do.  I'll amend the patch.
Andy Parkins· Mar 14, 2007, 10:45 UTC · re: Theodore Tso · lore

Re: [PATCH] Make gc a builtin.

On Wednesday 2007 March 14 07:44, Theodore Tso wrote:
> I agree with Junio; I think the scripts are much more readable and
> easier to understand; In fact, it would be nice if the script were
> preserved somewhere, perhaps as comments in the .c file.

If only there were some tool that would keep collections of files as a snapshotted whole and allow us to browse the history of those snapshots in some sort of connected graph, with each snapshot being given some sort of unique ID. Then we could simply refer to that unique ID when we wanted to tell someone about a particular historical instance.

:-)
Andy
-- 
Dr Andy Parkins, M Eng (hons), MIET
andyparkins@gmail.com
Junio C Hamano· Mar 14, 2007, 11:12 UTC · re: Andy Parkins · lore

Re: [PATCH] Make gc a builtin.

Andy Parkins <andyparkins@gmail.com> writes:
Show 13 quoted lines
> On Wednesday 2007 March 14 07:44, Theodore Tso wrote:
>
>> I agree with Junio; I think the scripts are much more readable and
>> easier to understand; In fact, it would be nice if the script were
>> preserved somewhere, perhaps as comments in the .c file.
>
> If only there were some tool that would keep collections of files as a 
> snapshotted whole and allow us to browse the history of those snapshots in 
> some sort of connected graph, with each snapshot being given some sort of 
> unique ID.  Then we could simply refer to that unique ID when we wanted to 
> tell someone about a particular historical instance.
>
> :-)

There is a difference between having a readily greppable and lessable copy handy to study at your own initiative, and being able to retrieve to review only after being told.

You could argue that we can all do that with git-grep and git-less ;-).

Andy Parkins· Mar 14, 2007, 11:48 UTC · re: Junio C Hamano · lore

Re: [PATCH] Make gc a builtin.

On Wednesday 2007 March 14 11:12, Junio C Hamano wrote:
> There is a difference between having a readily greppable and
> lessable copy handy to study at your own initiative, and being
> able to retrieve to review only after being told.
Well I was only joking really.
> You could argue that we can all do that with git-grep and
> git-less ;-).

Definitely. git is so good at this sort of stuff that encouraging the retention of commented out code is just filling up source files with junk.

In the old days, before version control, I would often have files with

#if 0 // This is how I used to do it // ... #endif

These days I comment it out, then after a few successful commits it gets removed from the source file. Git makes my code cleaner and clearer as it's not filled with obsolete junk. I am always secure in the knowledge that I can go back and look if I want. The same is true, I think, for shell script replaced with C code.

What will you do if in the future the C gets a feature that wasn't in the shell code - should the shell code be updated? If you don't then the comment is a lie, if you do then it's a maintenance nightmare.

Chuck it and be happy it's chucked. A rule for life. I should write fortune cookies.

Andy
-- 
Dr Andy Parkins, M Eng (hons), MIET
andyparkins@gmail.com
Johannes Schindelin· Mar 14, 2007, 12:19 UTC · re: Junio C Hamano · lore

Re: [PATCH] Make gc a builtin.

Hi,
On Wed, 14 Mar 2007, Junio C Hamano wrote:
Show 22 quoted lines
> Andy Parkins <andyparkins@gmail.com> writes:
> 
> > On Wednesday 2007 March 14 07:44, Theodore Tso wrote:
> >
> >> I agree with Junio; I think the scripts are much more readable and
> >> easier to understand; In fact, it would be nice if the script were
> >> preserved somewhere, perhaps as comments in the .c file.
> >
> > If only there were some tool that would keep collections of files as a 
> > snapshotted whole and allow us to browse the history of those snapshots in 
> > some sort of connected graph, with each snapshot being given some sort of 
> > unique ID.  Then we could simply refer to that unique ID when we wanted to 
> > tell someone about a particular historical instance.
> >
> > :-)
> 
> There is a difference between having a readily greppable and
> lessable copy handy to study at your own initiative, and being
> able to retrieve to review only after being told.
> 
> You could argue that we can all do that with git-grep and
> git-less ;-).
Not to forget git-checkout.

But I like the idea of contrib/examples/. Why not put more stuff there, instead of clinging onto scripts for core-git? The purpose of contrib/examples/ is to provide easy samples, and the purpose of core-git is _not_ to provide easy examples, but a consistent and portable set of programs.

Als, when reading Git's scripts, I often think
- wow, what a different style from my one, and
- would locking not be a nice thing?

But I guess that now that the King Penguin spoke, I no longer have to argue for more builtins, even if they are trivial. (Who knows, maybe we can ship _one_ program, which is then hard linked to git-*, soon?)

Ciao, Dscho

← back to recent threads