Web lists-archives.com

Re: [PATCH] Make git log work for git CWD outside of work tree

Danny Sauer <danny@xxxxxxxxxxxxxx> writes:

> That's feedback I was looking for - what's the "right" way to get the
> path to the file.

My knee-jerk reaction is that you SHOULDN'T have to do anything
special to "get the path".

I do not have the code in front of me (this is my "down" week after
all), so let me give the general outline of how to reason about
this, with the knowledge of code evolution of the system.

In the beginning, Git worked only from the top level of the working
tree.  If you have your project in ~/myproject with a file "f" in a
directory "d", that file is ~/myproject/d/f", and you would do

    $ cd ~/myproject
    $ git add d/f

to add it.  If Git wanted to access the index, it just accessed
".git/index" as a relative path.  If Git wanted to access a file at
the top of the working tree, say ".gitignore", it just accessed
".gitignore" as a relatlvei path.  Because it only worked from the

Then we added a support for running Git from a subdirectory, so that
you can say "cd ~/myproject/d && git add f".  In order to keep the
existing code that wants to access the index as ".git/index" and
wants to access the top-level ".gitignore" as ".gitignore" working,
the support to run Git from a subdirectory is designed this way:

    - Each main program of subcommand (e.g. cmd_log()) receives a
      parameter "prefix", which tells what subdirectory you were in
      when you started Git.

    - Before running the main program of subcommand, Git chdir(2)s
      up to the top level of the working tree.

    - The main program of subcommand receives the command line from
      the user intact.  It is responsible for prepending the prefix
      to the path the user gave it from the command line.

So if you did "cd ~/myproject/d && git add f", Git goes up to
"~/myproject", passes argv=("f", NULL) and prefix="d/" to cmd_add().

Adding to the index wants to read and update the index, which is
still done by opening ".git/index" (relative to the toplevel as
before), and inspecting the top-level .gitigore file is done by
opening ".gitignore" (relative to the toplevel as before).  And
the cmd_add() forms the path "d/f" by using the prefix "d/" and the
user-supplied pathname "f".

When we first added a support for having the (equivalent of) ".git/"
directory outside the working tree by setting GIT_DIR environment
variable, again, you can only use Git from the top-level of the
working tree.  Instead of "~/myproject/.git", you can keep your
repository metainformation in say "~/mypro.git/" and point at it
with GIT_DIR environment variable, and said

    $ export GIT_DIR=~/mypro.git
    $ cd ~/myproject
    $ git add d/f

Later we also added GIT_WORK_TREE environment variable to be used
together with GIT_DIR so that you can start from ~/myproject/d, very
similarly to how you worked from a subdirectory without these
environment variables, i.e.

    $ export GIT_DIR=~/mypro.git GIT_WORK_TREE=~/myproject
    $ cd ~/myproject/d
    $ git add f

The way this support was added was to go to the top-level of the
working tree (i.e. "~/myproject" in this example) and passing the
prefix (i.e. "d" in this example).

Notice that in all of the above configurations, if a Git command
knows a path to something that is relative to the top of the working
tree (e.g. ".git/index" in the ancient Git, ".gitignore" at the
top-level that governs the entire working tree, or ".mailmap"), it
should just be able to open that path without asking "where is the
top of the working tree?".

So if your directory arrangement is a variation of these basic
configurations supported, e.g. if your git directory is
~/myproject/.git and your working tree is ~/myproject, and you use
the GIT_DIR and GIT_WORK_TREE to point at them, regardless of which
subdirectory of $GIT_WORK_TREE you started with, Git should already
have done chdir(2) to ~/myproject/ before it starts cmd_log(), and
it should be able to just open and read ".mailmap" (of course, it
needs to limit itself to do so only when it is working with a
repository with a working tree).

If your arrangement is even more exotic, e.g. you have these two
variables set, and then are running from OUTSIDE the working tree,
my knee-jerk reaction is that you should get your head examined, as
it is totally unclear what "git add foo" would mean if you did this:

    $ export GIT_DIR=~/myproject/.git GIT_WORK_TREE=~/myproject
    $ cd ~/myproject/../somewhere/else
    $ git add foo

But it should still "work" in the sense that the above command
should notice that you are trying to add "../somewhere/else/foo" to
the index, which is obviously nonsense, and die with a message.

Similarly, if you replace "git add foo" with "git log", it still
should work in the above, i.e.

    $ export GIT_DIR=~/myproject/.git GIT_WORK_TREE=~/myproject
    $ cd ~/myproject/../somewhere/else
    $ git log

If Git is not chdir(2)ing to ~/myproject before calling cmd_log()
in the above (again, this is my down week so I didn't and will not
check with the code myself), we may want to call that a bug and fix
it, so that you do not have to do anything special to get to the
path of ".mailmap" that is at the top-level.