threads / patch / 639

patch, 2 partsIntroduce git-run-with-user-path helper program.

Subject: [PATCH 1/2] Introduce git-run-with-user-path helper program.

## tl;dr

15 messages between May 16, 2005 and May 19, 2005. Diffs are folded; open one to read it.

replies: 14people: 5as markdown or json

Junio C Hamano· May 16, 2005, 06:05 UTC · lore
Introduce git-run-with-user-path helper program.

A new command git-run-with-user-path takes a command and paths that are filesystem paths (either relative to the cwd or absolute pathname). It canonicalizes these paths to be usable by the core GIT commands, filters using the ignore pattern rule, chdir(2)'s to the top level of the tree and runs the given command with these canonicalizd paths as its arguments.

This version contains necessary hooks to implement the ignore pattern rule, but it does not implement any ignore pattern rules, waiting for more mailing list discussions.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

Documentation/git-run-with-user-path.txt | 79 ++++++++++++ Makefile | 7 - paths.c | 199 +++++++++++++++++++++++++++++++ paths.h | 14 ++ run-with-user-path.c | 61 +++++++++ t/README | 1 t/t7000-git-run-with-user-path-basic.sh | 66 ++++++++++ update-cache.c | 29 ---- 8 files changed, 427 insertions(+), 29 deletions(-) Documentation/git-run-with-user-path.txt (. --> 100644) paths.c (. --> 100644) paths.h (. --> 100644) run-with-user-path.c (. --> 100644) t/t7000-git-run-with-user-path-basic.sh (. --> 100755)

Show changes to 8 files +427 −29

Documentation/git-run-with-user-path.txt, Makefile, paths.c, paths.h, run-with-user-path.c, t/README, t/t7000-git-run-with-user-path-basic.sh, update-cache.c

--- a/Documentation/git-run-with-user-path.txt
+++ b/Documentation/git-run-with-user-path.txt
@@ -0,0 +1,79 @@
+git-run-with-user-path(1)
+=========================
+v0.1, May 2005
+
+NAME
+----
+git-run-with-user-path - Run command from the top after canonicalizing paths.
+
+
+SYNOPSIS
+--------
+'git-run-with-user-path' [options] <command> <argument>... '--' <path>...
+
+DESCRIPTION
+-----------
+This command takes a <command>, zero or more <argument> and zero
+or more <path> arguments.  <path> arguments name objects on the
+filesystem, <command> is typically a core GIT command, and
+<argument> are the initial arguments to the <command>.
+
+It first finds the project top directory (the directory that corresponds
+to the top of the tree structure GIT_INDEX_FILE describes).  When the
+environment variable GIT_PROJECT_TOP is set, the value of the variable
+is used.  Then the <path> parameters are canonicalized to be relative to
+the project top.  It then chdir(2)'s to the project top directory and
+runs the given <command>, with <argument> and these canonicalized <path>
+arguments.
+
+This is useful for the Porcelain layer to run core GIT commands from
+subdirectories.  For example, if linux-2.6.git tree is checked out in
+/usr/src/linux, you can do:
+
+    $ cd /usr/src/linux/fs
+    $ ... work in fs directory making changes ...
+    $ git-run-with-user-path git-diff-tree -r HEAD -- ext? ../include/linux
+    $ find ext? ../include/linux ! -type d -print0 |
+      xargs -0 git-run-with-user-path git-update-cache --add -- --
+
+The above is roughly equivalent to:
+
+    $ cd /usr/src/linux
+    $ git-diff-tree -r HEAD fs/ext? include/linux
+    $ find fs/ext? include/linux ! -type d -print0 |
+      xargs git-update-cache --add --
+
+
+OPTIONS
+-------
+--no-ignore::
+
+	By default, the path arguments are filtered with the
+	same ignore rules Porcelain layers use.  With
+	--no-ignore flag, there is no such filtering done.
+
+
+ENVIRONMENT VARIABLES
+---------------------
+
+'GIT_PROJECT_TOP'::
+	If the 'GIT_PROJECT_TOP' environment variable is set
+	then it specifies the directory that corresponds to the
+	top level of the tree structure GIT_INDEX_FILE describes.
+	When this environment variable is not defined, the
+	closest parent directory that has .git/ subdirectory in
+	it is looked for and used.
+
+
+Author
+------
+Written by Junio C Hamano <junkio@cox.net>
+
+Documentation
+--------------
+Documentation by Junio C Hamano.
+
+GIT
+---
+Part of the link:git.html[git] suite
+
--- a/Makefile
+++ b/Makefile
@@ -28,7 +28,7 @@
 	git-unpack-file git-export git-diff-cache git-convert-cache \
 	git-http-pull git-rpush git-rpull git-rev-list git-mktag \
 	git-diff-helper git-tar-tree git-local-pull git-write-blob \
-	git-get-tar-commit-id
+	git-get-tar-commit-id git-run-with-user-path
 
 all: $(PROG)
 
@@ -46,6 +46,9 @@
 LIB_H += diff.h
 LIB_OBJS += diff.o
 
+LIB_H += paths.h
+LIB_OBJS += paths.o
+
 LIB_OBJS += gitenv.o
 
 LIBS = $(LIB_FILE)
@@ -100,6 +103,7 @@
 git-rpush: rsh.c
 git-rpull: rsh.c pull.c
 git-rev-list: rev-list.c
+git-run-with-user-path: run-with-user-path.c 
 git-mktag: mktag.c
 git-diff-helper: diff-helper.c
 git-tar-tree: tar-tree.c
@@ -117,6 +121,7 @@
 sha1_file.o: $(LIB_H)
 usage.o: $(LIB_H)
 diff.o: $(LIB_H)
+paths.o: $(LIB_H)
 strbuf.o: $(LIB_H)
 gitenv.o: $(LIB_H)
 
--- a/paths.c
+++ b/paths.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2005 Junio C Hamano
+ */
+#include <string.h>
+#include "cache.h"
+#include "paths.h"
+
+/****************************************************************/
+
+/* Ignore list handling part */
+
+/*
+ * We fundamentally don't like some paths: we don't want
+ * dot or dot-dot anywhere, and in fact, we don't even want
+ * any other dot-files (.git or anything else). They
+ * are hidden, for chist sake.
+ *
+ * Also, we don't want double slashes or slashes at the
+ * end that can make pathnames ambiguous.
+ */
+int verify_path(const char *path)
+{
+	char c;
+
+	goto inside;
+	for (;;) {
+		if (!c)
+			return 1;
+		if (c == '/') {
+inside:
+			c = *path++;
+			if (c != '/' && c != '.' && c != '\0')
+				continue;
+			return 0;
+		}
+		c = *path++;
+	}
+}
+
+static int initialize_ignore_list(void)
+{
+	/* Put the Porcelain layer ignore logic initialization here.
+	 * Return non-zero after issuing appropriate error message
+	 * if initialization fails.
+	 */
+	return 0;
+}
+
+int path_ignored(const char *path)
+{
+	if (!verify_path(path))
+		return 1;
+
+	/* Put the Porcelain layer ignore logic here.
+	 * Return non-zero if path is to be ignored.
+	 */
+	return 0;
+}
+
+
+/****************************************************************/
+
+/* Path canonicalization part */
+
+char *git_project_top = NULL;
+static char git_cwd[PATH_MAX];
+
+static int find_project_top(void)
+{
+	char path[PATH_MAX];
+	int dir_length;
+
+	if (!getcwd(git_cwd, sizeof(git_cwd)))
+		return error("cannot get cwd to find GIT_PROJECT_TOP");
+
+	git_project_top = gitenv("GIT_PROJECT_TOP");
+	if (git_project_top)
+		return 0;
+
+	strcpy(path, git_cwd);
+	while (path[0] && strcmp(path, "/") && !git_project_top) {
+		char *cp;
+		struct stat st;
+		dir_length = strlen(path);
+		path[dir_length] = '/';
+
+		strcpy(path + dir_length + 1, ".git");
+		if (stat(path, &st) < 0) {
+			if (errno != ENOENT)
+				return error("%s: %s", path, strerror(errno));
+			/* notfound */
+		}
+		else if (S_ISDIR(st.st_mode)) {
+			path[dir_length] = 0;
+			git_project_top = strdup(path);
+			break;
+		}
+		else
+			return error("%s: not a directory", path);
+		path[dir_length] = 0;
+		cp = strrchr(path, '/');
+		if (cp)
+			*cp = 0;
+	}
+	if (!git_project_top)
+		return error("cannot find GIT_PROJECT_TOP");
+
+	return 0;
+}
+
+char *canon_path(const char *path)
+{
+	/* path is either absolute path from root fs or
+	 * relative to the git_cwd.  What is the relative path
+	 * for that thing, viewed from GIT_PROJECT_TOP?
+	 */
+	char *cp, *op, *endp, *result = NULL;
+	char *work = xmalloc(strlen(git_cwd) + strlen(path) + 2);
+	int pfxlen = strlen(git_project_top);
+
+	if (path[0] == '/')
+		strcpy(work, path);
+	else
+		sprintf(work, "%s/%s", git_cwd, path);
+	/* We will copy to *op starting from *cp while removing
+	 * nonsense.  Initially op and cp are both set to one
+	 * past the root-level '/'.
+	 */
+	op = cp = work + 1;
+	endp = cp + strlen(cp);
+	while (cp < endp) {
+		char *ep = strchr(cp, '/');
+		if (!ep)
+			ep = endp; /* at terminating NUL */
+		/* Now look at what is between cp and ep. */
+		if (ep == cp) {
+			/* Remove double slashes.
+			 * "/xxx//foo" ==> "/xxx//foo"
+			 *    cp^              cp^
+			 */
+			cp++;
+			continue;
+		}
+		if (*cp == '.') {
+			/* dot something.  What is it? */
+			if (cp[1] == 0 || cp[1] == '/') {
+				/* Remove trailing dot.
+				 * "/xxx/." ==> "/xxx/."
+				 *     cp^           cp^
+				 * "/xxx/./foo" ==> "/xxx/./foo"
+				 *     cp^               cp^
+				 */
+				cp = ep;
+				continue;
+			}
+			if (cp[1] == '.' && (cp[2] == 0 || cp[2] == '/')) {
+				/* Uplevel.
+				 * "/xxx/../foo" ==> "/xxx/../foo"
+				 *     cp^                  cp^
+				 * while backspacing "xxx" in the op
+				 */
+				cp = cp + 3;
+				op -= 2;
+				if (op < work)
+					op = work + 1;
+				while (*op != '/' && work < op)
+					op--;
+				op++;
+				continue;
+			}
+		}
+		/* otherwise there is no funnies */
+		while (cp <= ep && *cp)
+			*op++ = *cp++;
+	}
+	*op = 0;
+	if (op[-1] == '/' && op != work)
+		op[-1] = 0;
+
+	if (!strncmp(git_project_top, work, pfxlen) &&
+	    (work[pfxlen] == '/' || work[pfxlen] == 0))
+		result = strdup(work + pfxlen + 1);
+	/* otherwise, path is outside of git-project-top and we ignore it. */
+
+	free(work);
+	return result;
+}
+
+/****************************************************************/
+
+int setup_paths(void)
+{
+	if (find_project_top())
+		return -1;
+	if (initialize_ignore_list())
+		return -1;
+	return 0;
+}
+
--- a/paths.h
+++ b/paths.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2005 Junio C Hamano
+ */
+#ifndef _PATHS_H_
+#define _PATHS_H_
+
+int setup_paths(void);
+extern char *git_project_top;
+
+char *canon_path(const char *);
+int path_ignored(const char *);
+int verify_path(const char *);
+
+#endif
--- a/run-with-user-path.c
+++ b/run-with-user-path.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2005 Junio C Hamano
+ */
+#include <unistd.h>
+#include "cache.h"
+#include "paths.h"
+
+static int no_ignore = 0;
+
+static const char *usage_rwup = 
+"git-run-with-user-path [ --no-ignore ] <command> <argument>... -- <path>...";
+
+static int prepare_path_args(char **exec_param, char **path)
+{
+	int i, cnt;
+	char *canon;
+
+	for (i = cnt = 0; path[i]; i++) {
+		canon = canon_path(path[i]);
+		if (no_ignore || !path_ignored(canon))
+			exec_param[cnt++] = canon;
+	}
+	return cnt;
+}
+
+int main(int ac, char **av)
+{
+	char **exec_param;
+	int i, command_end, cnt_path;
+
+	if (setup_paths())
+		exit(1);
+
+	while (1 < ac && av[1][0] == '-') {
+		if (!strcmp(av[1], "--no-ignore"))
+			no_ignore = 1;
+		else
+			break;
+		ac--; av++;
+	}
+	for (i = 1; i < ac; i++)
+		if (!strcmp(av[i], "--"))
+			break;
+	if (ac <= i)
+		die(usage_rwup); /* no -- to start path */
+
+	command_end = i; /* pointing at -- */
+
+	/* command command arg1 arg2 ... path1 path2 ... NULL */
+	exec_param = xcalloc(ac, sizeof(char *));
+	exec_param[ac - 1] = 0;
+	for (i = 1; i < command_end; i++)
+		exec_param[i - 1] = av[i];
+	cnt_path = prepare_path_args(exec_param + command_end - 1,
+				     av + command_end + 1);
+
+	chdir(git_project_top);
+	execvp(exec_param[0], exec_param);
+
+	exit(0);
+}
--- a/t/README
+++ b/t/README
@@ -73,6 +73,7 @@
 	4 - the diff commands
 	5 - the pull and exporting commands
 	6 - the revision tree commands (even e.g. merge-base)
+	7 - the non-core commands and helpers
 
 Second digit tells the particular command we are testing.
 
--- a/t/t7000-git-run-with-user-path-basic.sh
+++ b/t/t7000-git-run-with-user-path-basic.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+#
+# Copyright (c) 2005, Junio C Hamano
+#
+
+test_description='git-run-with-user-path basic test.
+
+The command is used to help running core GIT commands that always
+expect to be run from the top level directory (i.e. the directory
+that corresponds to the top of tree GIT_INDEX_FILE describes).
+'
+
+. ./test-lib.sh
+
+LF='
+'
+HERE=$(pwd)
+
+test_expect_success \
+setup '
+mkdir path0 path1 path1/path2
+for p in path0/file0 path1/file1 path1/path2/file2
+do
+    echo hello >$p
+    git-update-cache --add -- $p
+done
+'
+
+test_expect_success \
+'finding paths from a subdirectory' '
+    case "$(cd path0 &&
+            git-run-with-user-path --no-ignore cat -- \
+	    file0 ../path1/path2/file2)" in
+    "hello${LF}hello") : ;;
+    *) (exit 1) ;;
+    esac
+'
+
+test_expect_success \
+'feeding find output via xargs from a subdirectory' '
+    case "$(cd path0 &&
+	    find . ../path1 -type f -print0 |
+	    xargs -r -0 git-run-with-user-path --no-ignore cat --)" in
+    "hello${LF}hello${LF}hello") : ;;
+    *) (exit 1) ;;
+    esac
+'
+
+cd $HERE
+mv .git .svn
+GIT_DIR=$(pwd)/.svn
+GIT_PROJECT_TOP=$(pwd)
+export GIT_DIR GIT_PROJECT_TOP
+
+test_expect_success \
+'feeding find output via xargs from a subdirectory (with GIT_PROJECT_TOP)' '
+    case "$(cd path0 &&
+            find . ../path1 -type f -print0 |
+	    xargs -r -0 git-run-with-user-path --no-ignore cat --)" in
+    "hello${LF}hello${LF}hello") : ;;
+    *) (exit 1) ;;
+    esac
+    cd ..
+'
+
+test_done
--- a/update-cache.c
+++ b/update-cache.c
@@ -5,6 +5,7 @@
  */
 #include <signal.h>
 #include "cache.h"
+#include "paths.h"
 
 /*
  * Default to not allowing changes to the list of files. The
@@ -257,34 +258,6 @@
 	return has_errors;
 }
 
-/*
- * We fundamentally don't like some paths: we don't want
- * dot or dot-dot anywhere, and in fact, we don't even want
- * any other dot-files (.git or anything else). They
- * are hidden, for chist sake.
- *
- * Also, we don't want double slashes or slashes at the
- * end that can make pathnames ambiguous.
- */
-static int verify_path(char *path)
-{
-	char c;
-
-	goto inside;
-	for (;;) {
-		if (!c)
-			return 1;
-		if (c == '/') {
-inside:
-			c = *path++;
-			if (c != '/' && c != '.' && c != '\0')
-				continue;
-			return 0;
-		}
-		c = *path++;
-	}
-}
-
 static int add_cacheinfo(char *arg1, char *arg2, char *arg3)
 {
 	int size, len, option;
------------------------------------------------
Petr Baudis· May 17, 2005, 19:03 UTC · re: Junio C Hamano · lore

Re: [PATCH 1/2] Introduce git-run-with-user-path helper program.

Dear diary, on Mon, May 16, 2005 at 08:05:19AM CEST, I got a letter where Junio C Hamano <junkio@cox.net> told me that...

Show 22 quoted lines
> --- a/paths.c
> +++ b/paths.c
> @@ -0,0 +1,199 @@
> +static int initialize_ignore_list(void)
> +{
> +	/* Put the Porcelain layer ignore logic initialization here.
> +	 * Return non-zero after issuing appropriate error message
> +	 * if initialization fails.
> +	 */
> +	return 0;
> +}
> +
> +int path_ignored(const char *path)
> +{
> +	if (!verify_path(path))
> +		return 1;
> +
> +	/* Put the Porcelain layer ignore logic here.
> +	 * Return non-zero if path is to be ignored.
> +	 */
> +	return 0;
> +}

I actually think you shouldn't. All the Porcelain layers should hopefully use the same git toolkit layer, not each one shipping own due to differences in things like this.

If we don't agree on something common (implemented in a way to be still circumventable by a porcelain layer if desired), I wouldn't put the ignore logic inside at all.

> +/****************************************************************/
> +
> +/* Path canonicalization part */
And why is this in the library?
-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
C++: an octopus made by nailing extra legs onto a dog. -- Steve Taylor
Junio C Hamano· May 17, 2005, 19:27 UTC · re: Petr Baudis · lore

Re: [PATCH 1/2] Introduce git-run-with-user-path helper program.

>>>>> "PB" == Petr Baudis <pasky@ucw.cz> writes:
Show 10 quoted lines
>> +int path_ignored(const char *path)
>> +{
>> +	if (!verify_path(path))
>> +		return 1;
>> +
>> +	/* Put the Porcelain layer ignore logic here.
>> +	 * Return non-zero if path is to be ignored.
>> +	 */
>> +	return 0;
>> +}

PB> I actually think you shouldn't. All the Porcelain layers should PB> hopefully use the same git toolkit layer, not each one shipping own due PB> to differences in things like this.

What you said above _is_ exactly my intention. I phrased that comment very badly. It should have said:

    /* We _will_ put the "ignore logic Porcelain layers agree upon"
     * here, once we have a concensus.
     *
     * The code should return non-zero if path is to be ignored.
     */

I did not put any implementation there because I do not think we have agreed upon anything yet. This patch is to establish the framework.

The second patch is separate, because it is _my_ version of the ignore logic proposal, to serve as a sample. Whatever ignore logic is agreed upon, that _will_ be in the place you pointed out and there will be no choice. Everybody _will_ use the ignore logic.

>> +/****************************************************************/
>> +
>> +/* Path canonicalization part */
PB> And why is this in the library?

Why not? It is something other programs would eventually find useful.

Also the second patch, a sample implementation of ignore logic I proposed, wants to know GIT_PROJECT_TOP to figure out the file pointed at by GIT_DIR/.git/info/ignore-file.

Also it would not hurt if you are always running from the project top and give only verify_path() approved paths. Then canon_path would become identity function.

git-run-with-user-path is useful both in implementing porcelain-add if the porcelain's policy is to take filesystem paths not GIT paths, like this:

    #!/bin/sh
    # porcelain-add
    exec git-run-with-user-path git-update-cache --add -- -- "$@"

Also if the porcelain's policy is to take GIT paths not filesystem paths, then users can say:

    $ find . ! -type d -print0 |
      xargs -0 git-run-with-user-path cg-add --
You cannot use both for obvious reasons.
Petr Baudis· May 17, 2005, 20:35 UTC · re: Junio C Hamano · lore

Re: [PATCH 1/2] Introduce git-run-with-user-path helper program.

Dear diary, on Tue, May 17, 2005 at 09:27:03PM CEST, I got a letter where Junio C Hamano <junkio@cox.net> told me that...

Show 29 quoted lines
> >>>>> "PB" == Petr Baudis <pasky@ucw.cz> writes:
> 
> >> +int path_ignored(const char *path)
> >> +{
> >> +	if (!verify_path(path))
> >> +		return 1;
> >> +
> >> +	/* Put the Porcelain layer ignore logic here.
> >> +	 * Return non-zero if path is to be ignored.
> >> +	 */
> >> +	return 0;
> >> +}
> 
> PB> I actually think you shouldn't. All the Porcelain layers should
> PB> hopefully use the same git toolkit layer, not each one shipping own due
> PB> to differences in things like this.
> 
> What you said above _is_ exactly my intention.  I phrased that
> comment very badly.  It should have said:
> 
>     /* We _will_ put the "ignore logic Porcelain layers agree upon"
>      * here, once we have a concensus.
>      *
>      * The code should return non-zero if path is to be ignored.
>      */
> 
> I did not put any implementation there because I do not think we
> have agreed upon anything yet.  This patch is to establish
> the framework.  
Ok, so this just bad comment. :-) No problem then.

Regarding having the code in the library, well, I'm thinking about why not to just put this logic into all the git commands. Unfortunately I can't find the email with Linus' argumentation against that right now. :-(

> git-run-with-user-path is useful both in implementing
> porcelain-add if the porcelain's policy is to take filesystem
> paths not GIT paths, like this:

Actually, my doubts about general usefulness of this wrapper are growing. Cogito is unlikely to ever make use of it since it has to figure out the .git location anyway for own use (it keeps plenty of own files there). But that's likely what any other porcelain layer would have to do as well, isn't it? The wrapper could still be useful for the standalone users, though.

Another thing is, I don't think git-run-with-user-path is the right name. I think it doesn't make much sense on its own, and the wrapper is actually doing more anyway, applying the ignore rules. What about calling it just git-run-wrapper?

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
C++: an octopus made by nailing extra legs onto a dog. -- Steve Taylor
Junio C Hamano· May 17, 2005, 21:18 UTC · re: Petr Baudis · lore

Re: [PATCH 1/2] Introduce git-run-with-user-path helper program.

>>>>> "PB" == Petr Baudis <pasky@ucw.cz> writes:

PB> Actually, my doubts about general usefulness of this wrapper are PB> growing. Cogito is unlikely to ever make use of it since it has to PB> figure out the .git location anyway for own use (it keeps plenty of own PB> files there).

I think "having to figure out .git anyway" is backwards, if your plan is to make Cogito take filesystem paths as opposed to GIT paths. If the plan for Cogito is to take always GIT paths, which is a sensible way as well, then it is irrelevant for the implementation of Cogito, but then it becomes useful for users of Cogito).

If your plan is to make Cogito take filesystem paths, then you can move bulk of the code currently in cg-blah, except the part that picks up non-path parameters, to cg-Xblah, and reduce cg-blah implementation down to just:

    ... parse options by shifting "$@" out.
    ... then
    git-run-with-user-path cg-Xblah $non-path-opts -- "$@"

and you can rip "the code to figure out .git" out from cg-Xblah. There is nothing to figure out at that point; it always is ${GIT_DIR-.git}/.

Petr Baudis· May 17, 2005, 21:37 UTC · re: Junio C Hamano · lore

Re: [PATCH 1/2] Introduce git-run-with-user-path helper program.

Dear diary, on Tue, May 17, 2005 at 11:18:18PM CEST, I got a letter where Junio C Hamano <junio@siamese.dyndns.org> told me that...

> If your plan is to make Cogito take filesystem paths, then you
Yes, that's my plan.
Show 11 quoted lines
> can move bulk of the code currently in cg-blah, except the part
> that picks up non-path parameters, to cg-Xblah, and reduce
> cg-blah implementation down to just:
> 
>     ... parse options by shifting "$@" out.
>     ... then
>     git-run-with-user-path cg-Xblah $non-path-opts -- "$@"
> 
> and you can rip "the code to figure out .git" out from cg-Xblah.
> There is nothing to figure out at that point; it always is
> ${GIT_DIR-.git}/.

But that won't work good enough for me. E.g. when committing in a subdirectory, I want to commit only changes made in the subdirectory, etc.

Not even talking about much uglier implementation (that could be remedied by calling myself recursively with some special argument).

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
C++: an octopus made by nailing extra legs onto a dog. -- Steve Taylor
Junio C Hamano· May 17, 2005, 22:13 UTC · re: Petr Baudis · lore

Re: [PATCH 1/2] Introduce git-run-with-user-path helper program.

>>>>> "PB" == Petr Baudis <pasky@ucw.cz> writes:

PB> But that won't work good enough for me. E.g. when committing in a PB> subdirectory, I want to commit only changes made in the subdirectory, PB> etc.

Assuming that you have something that lets you commit selected files when you are at the top level (say cg-commit), and further assuming that today it only works from the toplevel, that is:

    $ pwd
    /usr/src/linux
    $ cg-commit fs/ext?/Makefile
works today, what I am saying is:
    $ pwd
    /usr/src/linux/fs
    $ git-run-with-user-path cg-commit -- ext?/Makefile
would work.

Usually the command like cg-commit would take non-path parameters, so if this works today:

    $ pwd
    /usr/src/linux
    $ cg-commit -m 'Changed Makefile' fs/ext?/Makefile
then:
    $ pwd
    /usr/src/linux/fs
    $ git-run-with-user-path cg-commit -m 'Changed Makefile' -- ext?/Makefile
would work.

Once you have a core that works well but only at the top directory level, then you can make a thin wrapper using git-run-with-user-path to make that work equally well with the filesystem path from subdirectories. And the core-ish thing that only works at the top directory level does not need to worry about finding .git/ anymore, which is the whole point of what this helper is giving you.

BTW, I am wondering if your choice of cg-commit as an example (as opposed to something else like diff or add) is a flamebait or just an innocent random example ;-)?

Petr Baudis· May 18, 2005, 21:33 UTC · re: Junio C Hamano · lore

Re: [PATCH 1/2] Introduce git-run-with-user-path helper program.

Dear diary, on Wed, May 18, 2005 at 12:13:32AM CEST, I got a letter where Junio C Hamano <junkio@cox.net> told me that...

Show 21 quoted lines
> >>>>> "PB" == Petr Baudis <pasky@ucw.cz> writes:
> 
> PB> But that won't work good enough for me. E.g. when committing in a
> PB> subdirectory, I want to commit only changes made in the subdirectory,
> PB> etc.
> 
> Assuming that you have something that lets you commit selected
> files when you are at the top level (say cg-commit), and further
> assuming that today it only works from the toplevel, that is:
> 
>     $ pwd
>     /usr/src/linux
>     $ cg-commit fs/ext?/Makefile
> 
> works today, what I am saying is:
> 
>     $ pwd
>     /usr/src/linux/fs
>     $ git-run-with-user-path cg-commit -- ext?/Makefile
> 
> would work.

Yes. But if you do just cg-commit in the subdirectory, it won't work. You could pass the original directory in some environment variable or whatever, but I think that's just not worth the trouble for Cogito - it's much easier for it when you just stay in the directory you are in and instead set the environment variables so that the git toolkit DTRT. (I like this acronym. :-)

> BTW, I am wondering if your choice of cg-commit as an example
> (as opposed to something else like diff or add) is a flamebait
> or just an innocent random example ;-)?
It was completely innocent. :-) How would it be a flamebait?
-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
C++: an octopus made by nailing extra legs onto a dog. -- Steve Taylor
Junio C Hamano· May 18, 2005, 22:41 UTC · re: Petr Baudis · lore

Re: [PATCH 1/2] Introduce git-run-with-user-path helper program.

>>>>> "PB" == Petr Baudis <pasky@ucw.cz> writes:
Show 5 quoted lines
>> $ pwd
>> /usr/src/linux/fs
>> $ git-run-with-user-path cg-commit -- ext?/Makefile
>> 
>> would work.
PB> Yes. But if you do just cg-commit in the subdirectory, it won't work.

The point of git-run-with-user-path is that it canonicalizes and filters the paths, chdir(2)'s to GIT_PROJECT_TOP before running cg-commit. So when cg-commit starts in the above example,

    (1) its $cwd is /usr/src/linux and your .git subdirectory is
        right there in ./.git/
    (2) it gets fs/ext2/Makefile and fs/ext3/Makefile as arguments.
>> BTW, I am wondering if your choice of cg-commit as an example
>> (as opposed to something else like diff or add) is a flamebait
>> or just an innocent random example ;-)?
PB> It was completely innocent. :-) How would it be a flamebait?
<http://members.cox.net/junkio/per-file-commit.txt> ;-).
Petr Baudis· May 18, 2005, 23:24 UTC · re: Junio C Hamano · lore

Re: [PATCH 1/2] Introduce git-run-with-user-path helper program.

Dear diary, on Thu, May 19, 2005 at 12:41:38AM CEST, I got a letter where Junio C Hamano <junkio@cox.net> told me that...

Show 17 quoted lines
> >>>>> "PB" == Petr Baudis <pasky@ucw.cz> writes:
> 
> >> $ pwd
> >> /usr/src/linux/fs
> >> $ git-run-with-user-path cg-commit -- ext?/Makefile
> >> 
> >> would work.
> 
> PB> Yes. But if you do just cg-commit in the subdirectory, it won't work.
> 
> The point of git-run-with-user-path is that it canonicalizes and
> filters the paths, chdir(2)'s to GIT_PROJECT_TOP before running
> cg-commit.  So when cg-commit starts in the above example,
> 
>     (1) its $cwd is /usr/src/linux and your .git subdirectory is
>         right there in ./.git/
>     (2) it gets fs/ext2/Makefile and fs/ext3/Makefile as arguments.

Yes. My point is that sometimes the Cogito commands have directory-specific functionality even when called without any arguments.

$ pwd /usr/src/linux $ date >>README $ cd fs $ date >>Makefile $ cg-commit

will commit only the fs/Makefile change.
Show 7 quoted lines
> >> BTW, I am wondering if your choice of cg-commit as an example
> >> (as opposed to something else like diff or add) is a flamebait
> >> or just an innocent random example ;-)?
> 
> PB> It was completely innocent. :-) How would it be a flamebait?
> 
> <http://members.cox.net/junkio/per-file-commit.txt> ;-).
JIT's snapshotting makes up for it, I think. It has some beauty. :-)
-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
C++: an octopus made by nailing extra legs onto a dog. -- Steve Taylor
Junio C Hamano· May 18, 2005, 23:56 UTC · re: Petr Baudis · lore

Re: [PATCH 1/2] Introduce git-run-with-user-path helper program.

>>>>> "PB" == Petr Baudis <pasky@ucw.cz> writes:

PB> Yes. My point is that sometimes the Cogito commands have PB> directory-specific functionality even when called without any arguments.

PB> $ pwd PB> /usr/src/linux PB> $ date >>README PB> $ cd fs PB> $ date >>Makefile PB> $ cg-commit

PB> will commit only the fs/Makefile change.
Ah, thanks.  That what I missed.
Linus Torvalds· May 19, 2005, 00:34 UTC · re: Junio C Hamano · lore

Re: [PATCH 1/2] Introduce git-run-with-user-path helper program.

On Wed, 18 May 2005, Junio C Hamano wrote:
Show 14 quoted lines
> 
> PB> Yes. My point is that sometimes the Cogito commands have
> PB> directory-specific functionality even when called without any arguments.
> 
> PB> $ pwd
> PB> /usr/src/linux
> PB> $ date >>README
> PB> $ cd fs
> PB> $ date >>Makefile
> PB> $ cg-commit
> 
> PB> will commit only the fs/Makefile change.
> 
> Ah, thanks.  That what I missed.

Note that if git-run-with-user-path just has some way to tell what the relative pathname of the original program was (say $DEF_SUBDIRECTORY), this could still fairly easily be handled: having the cg-Xcommit program say "if there are no arguments, we default to $DEF_SUBDIRECTORY" rather than "with no arguments, default to '.'".

I don't personally much care, since this is all porcelain, but basically I don't think these things are in any way mutually incompatible, and I do believe that git-run-with-user-path _could_ be a good way to abstract out the "where the heck in the tree am I?" issues.

		Linus
Junio C Hamano· May 19, 2005, 20:35 UTC · re: Linus Torvalds · lore

Re: [PATCH 1/2] Introduce git-run-with-user-path helper program.

>>>>> "LT" == Linus Torvalds <torvalds@osdl.org> writes:

LT> ... I do believe that git-run-with-user-path _could_ be a LT> good way to abstract out the "where the heck in the tree am LT> I?" issues.

Yes, I am still in search of a good way to abstract that issue out and I myself is not yet convinced that the command in its current form _is_ a good enough way yet.

What I am most unhappy about with it lies elsewhere, though. There needs to be a better way to tell it how the underlying command handles non-paths arguments, so that I can just say

    git-run-with-user-path <some option spec for the command> \
        command arg1 arg2 arg3 ...

and if arg1 through argO is non-path options then have it canonicalize and filter only starting from argO+1. That would alleviate one issue I have with the current implementation.

Thomas Glanzmann· May 19, 2005, 07:40 UTC · re: Petr Baudis · lore

Re: [PATCH 1/2] Introduce git-run-with-user-path helper program.

Hello,
> > <http://members.cox.net/junkio/per-file-commit.txt> ;-).
> I think the workflow that involves per-file commit is
> fundamentally broken at two levels.

I disagree here. We at FAUmachine often have FLAGS to turn on specific features or debugging output by tweaking a headerfile. However we commit often and work in small steps (at the moment using CVS because every developer has write access). And we definitely don't want to tweak the header file every time we commit, so I often do a:

cvs diff > diff vim diff lsdiff diff cvs commit <interesting files here>

	Thomas
Junio C Hamano· May 19, 2005, 08:23 UTC · re: Thomas Glanzmann · lore

Re: [PATCH 1/2] Introduce git-run-with-user-path helper program.

>>>>> "TG" == Thomas Glanzmann <sithglan@stud.uni-erlangen.de> writes:
TG> Hello,
>> > <http://members.cox.net/junkio/per-file-commit.txt> ;-).
>> I think the workflow that involves per-file commit is
>> fundamentally broken at two levels.

TG> I disagree here. We at FAUmachine often have FLAGS to turn on specific TG> features or debugging output by tweaking a headerfile.

So what? I would understand that in your workflow, the nature of that never-committed headerfile (the fact it only has debugging tweaks and contains nothing substantially risky) practically minimizes the risk to the level everybody in the group feels acceptable.

That does not, however, change what I stated in the document: what you have in the repository is something that never existed in a work tree as a consistent whole and tested.

You are only saying is that it does not practically matter in your workflow, only because what is floating (not checked in) are things you feel safe to drift. I would not dare say that is a wrong way to work.

However, I feel fairly strong about this after being burned many times by careless coleagues who forgot to check in either newly created files or locally modified files and finding problems only after customer installation happened.

← back to recent threads