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

[PATCH/RFC] Emulating symlinks on Windows with file copies

From
PHPatrick Higgins <patrick.higgins@cexp.com>
Date
Jun 30, 2008, 23:54 UTC
Message-ID
<1214870053-11537-1-git-send-email-patrick.higgins@cexp.com>
Signed-off-by: Patrick Higgins <patrick.higgins@cexp.com>
---

This is a very basic script to test out the idea of using copies to emulate symlinks on Windows. I don't track any changes in the index yet which seems necessary as a next step.

Symlinks get deleted and replaced with copies. Existing unchanged copies are ignored. Copies that have been modified get merged into the target of the link.

This might have some messy cases that I haven't considered yet, but it seems like a fairly straightforward way to make a repository containing file symlinks useful on Windows.

I have not yet started on directories. This technique would probably get messy with directories. Perhaps junction (reparse) points would be better for directories?

 git-sync-symlinks.perl |   44 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 44 insertions(+), 0 deletions(-)
 create mode 100755 git-sync-symlinks.perl
diff --git a/git-sync-symlinks.perl b/git-sync-symlinks.perl
new file mode 100755
index 0000000..223ae83
--- /dev/null
+++ b/git-sync-symlinks.perl
@@ -0,0 +1,44 @@
+#!/usr/bin/perl -w
+
+use strict;
+use File::Copy;
+use Fcntl ':mode';
+
+my $filepipe = open(FILELIST, '-|', 'git', 'ls-tree', '-z', '-r', 'HEAD')
+    or die("Cannot call git ls-tree : $!");
+
+local $/ = "\0";
+
+while ( <FILELIST> ) {
+    chomp;
+    if (/^120000 blob ([0-9a-f]{40})\t(.*)$/) {
+        my ($id, $path) = ($1, $2);
+        my $target = `git cat-file blob $id`;
+        chomp($target);
+        my @path_stat = lstat($path);
+        my @target_stat = stat($target);
+        
+        if (S_ISLNK($path_stat[2])) {
+            printf("Copying '%s' to '%s'\n", $target, $path);
+            unlink($path);
+            copy($target, $path);
+        }
+        elsif ($path_stat[7] != $target_stat[7] ||
+               `git hash-object $path` ne `git hash-object $target`)
+        {
+            printf("Merging '%s' to '%s'\n", $path, $target);
+            my @target_parts = split(/\s+/, `git ls-tree HEAD $target`);
+            my $target_id = $target_parts[2];
+            my $original = $target . ".BASE";
+            open(ORIGINAL, '-|', 'git', 'cat-file', 'blob', $target_id);
+            open(ORIGINAL_OUT, '>', $original);
+            while ( <ORIGINAL> ) {
+                print ORIGINAL_OUT $_;
+            }
+            close ORIGINAL_OUT;
+            close ORIGINAL;
+            system('git', 'merge-file', $target, $original, $path);
+        }
+    }
+}
+close FILELIST;
-- 
1.5.6.dirty
Message 1 of 1 in “Emulating symlinks on Windows with file copies”
  1. Emulating symlinks on Windows with file copiesPatrick Higgins, Jun 30, 2008

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.