git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Difficulty adding a symbolic link, part 3

From
Dale R. Worley <worley@alum.mit.edu>
Date
Jul 31, 2013, 20:29 UTC
Message-ID
<201307312029.r6VKT4vC023100@hobgoblin.ariadne.com>

I've run into a problem (with Git 1.8.3.3) where I cannot add a symbolic link (as such) to the repository *if* its path is given absolutely; instead Git adds the file the symbolic link points to. (If I give the path relatively, Git does what I expect, that is, adds the symbolic link.)

I've written a test script that shows the problem and included it below.

I would not expect *how* a path is presented to Git to change how Git processes the path. In the test case, I would expect "/bin/awk" and "../../bin/awk" to produce the same effect when used as arguments to "git add".

What is going on in the code is this: In "git add", all paths are normalized by the function prefix_path_gently() in abspath.c. That function removes symbolic links from the pathspec *only if* it is absolute, as shown in the first few lines of the function:

 static char *prefix_path_gently(const char *prefix, int len, const char *path)
 {
	 const char *orig = path;
	 char *sanitized;
	 if (is_absolute_path(orig)) {
-	         const char *temp = real_path(path);
+	         const char *temp = absolute_path(path);
		 sanitized = xmalloc(len + strlen(temp) + 1);
		 strcpy(sanitized, temp);
	 } else {

real_path() is specified to remove symbolic links. As shown, I've replaced real_path() with absolute_path(), based on the comment at the top of real_path():

/*
 * Return the real path (i.e., absolute path, with symlinks resolved
 * and extra slashes removed) equivalent to the specified path.  (If
 * you want an absolute path but don't mind links, use
 * absolute_path().)  The return value is a pointer to a static
 * buffer.
 *

If I replace real_path() with absolute_path() as shown, the problem I am testing for disappears.

With the above change, the test suite runs with zero failures, so it doesn't affect any common Git usage.

But I don't know enough about the internal architecture of Git to know that my change is correct in all cases. I'm almost certain that the normalization process for pathspecs should *not* normalize a final component that is a symbolic link. But I would expect it would be desirable to normalize non-final components that are symbolic links. On the other hand, that might not matter.

Can someone give me advice on what this code *should* do?

I believe I can prepare a proper test for the test suite for this, so once I know what the code change should be, I can prepare a proper patch for it.

Dale ---------------------------------------------------------------------- Here's a test case for adding a symbolic link. This test exploits the fact that on my system, /bin/awk is a symbolic link to "gawk". As you can see, the behavior of Git differs if the link's path is given to "git add" as an absolute path or a relative path.

Here is the test script: ---------------------------------------------------------------------- #! /bin/bash

# Illustrates a problem with applying "git add" to a symbolic link.
set -x

# To be run from a directory one step below the root directory. E.g., # "/tmp". # On this system, /bin/awk is a symbolic link to "gawk", which # means /tmp/gawk.

# Show the Git version. git version

# Make a test directory and cd to it. DIR=temp.$$ mkdir $DIR cd $DIR

# Create a Git repository. git init # Set the worktree to be / git config core.worktree / # Create an empty commit. git commit --allow-empty -m Empty.

# Add the symbolic link using its absolute name. ABSOLUTE=/bin/awk ls -l $ABSOLUTE git add $ABSOLUTE # Notice that the target of the link is added, not the link itself. git status -uno

# Reset the index. git reset

# Add the symbolic link using its relative name.
# Remember that we are two directory levels below the root directory now.
RELATIVE=../..$ABSOLUTE
ls -l $RELATIVE
git add $RELATIVE
# Notice that now the link itself is added.
git status -uno
----------------------------------------------------------------------
Here is sample output of the script:
----------------------------------------------------------------------
+ git version
git version 1.8.3.3.756.g07a2553.dirty
+ DIR=temp.22366
+ mkdir temp.22366
+ cd temp.22366
+ git init
Initialized empty Git repository in /git-add-link/temp.22366/.git/
+ git config core.worktree /
+ git commit --allow-empty -m Empty.
[master (root-commit) fb232e5] Empty.
+ ABSOLUTE=/bin/awk
+ ls -l /bin/awk
lrwxrwxrwx. 1 root root 4 Nov  2  2012 /bin/awk -> gawk
+ git add /bin/awk
+ git status -uno
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#	new file:   ../../bin/gawk
#
# Untracked files not listed (use -u option to show untracked files)
+ git reset
+ RELATIVE=../../bin/awk
+ ls -l ../../bin/awk
lrwxrwxrwx. 1 root root 4 Nov  2  2012 ../../bin/awk -> gawk
+ git add ../../bin/awk
+ git status -uno
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#	new file:   ../../bin/awk
#
# Untracked files not listed (use -u option to show untracked files)
----------------------------------------------------------------------
Dale
Next: Duy Nguyen
Message 1 of 5 in “Difficulty adding a symbolic link, part 3”
  1. Dale R. WorleyJul 31, 2013
  2. Duy NguyenAug 1, 2013
  3. Dale R. WorleyAug 1, 2013
  4. Dale R. WorleyAug 1, 2013
  5. Duy NguyenAug 2, 2013

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.