{"thread":{"id":"63500","subject":"[BUG] Hard links to large files cause unexpected refresh","startedAt":"2025-05-22T14:45:05Z","lastAt":"2025-05-22T16:44:59Z","messageCount":2,"participants":["Roel Sengers","Justin Tobler"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"518658","messageId":"195d93de-1d5d-40f3-8139-b73a447b356f@roelsengers.nl","threadId":"63500","inReplyTo":null,"subject":"[BUG] Hard links to large files cause unexpected refresh","fromName":"Roel Sengers","fromEmail":"roel@roelsengers.nl","sentAt":"2025-05-22T14:45:00Z","receivedAt":"2025-05-22T14:45:05Z","isPatch":false,"sender":{"key":"roel@roelsengers.nl","avatar":null},"body":"Thank you for filling out a Git bug report!\nPlease answer the following questions to help us understand your issue.\n\nWhat did you do before the bug happened? (Steps to reproduce your issue)\n\nIn my workflow there is a step which hard-links about 80GB of such files \nto locations where a 3rd party application can find them. However, after \nthis hard-linking step, git status (or other git commands) hang for a \nlong time. Note that making a copy of the file does not cause such \nslowdowns, which was surprising to me.\n\nI am using Git with git-lfs for these large files, however I was able to \nreproduce this issue without LFS enabled.\n\nThe script below reproduces the environment which triggers the issue:\n\nmkdir git-hardlink-test\ncd git-hardlink-test\n\ngit init\necho ignore.bin > .gitignore\ngit add .gitignore\ngit commit -m 'Initial commit'\n\ndd if=/dev/urandom of=file.bin bs=1M count=1000\ngit add file.bin\ngit commit -m 'Add file.bin'\n\n# $ cp file.bin ignore.bin; time git status\n# On branch main\n# nothing to commit, working tree clean\n#\n# real\t0m0,002s\n# user\t0m0,000s\n# sys\t0m0,002s\n\n# $ ln file.bin ignore.bin; time git status\n# Refresh index: 100% (2/2), done.\n# On branch main\n# nothing to commit, working tree clean\n#\n# real\t0m16,100s\n# user\t0m15,700s\n# sys\t0m0,255s\n\n\nWhat did you expect to happen? (Expected behavior)\n\nAfter creating a hard link to a checked-in object, I expected the final \ngit status to finish in a time that is barely noticeable.\n\nThe file itself is large, so having Git taking its time to refresh the \nstate of the working directory would not be suspicious were it not for \nthe fact that creating a copy of the same file does not suffer from the \nsame performance penalty.\n\nI expected Git to be as fast for both copied and hard-linked files.\n\n\nWhat happened instead? (Actual behavior)\n\ngit status takes an unusual amount of time to complete when an \nuncommitted hard link is created to a prior committed file.\n\nWhat's different between what you expected and what actually happened?\n\nTiming git status tells me that it took 2 milliseconds to complete after \na copy was made.\n\nRunning git status after creating a hard link took 16 seconds instead, I \nexpected these times to be similar as the file contents do not differ.\n\nThe target file is also listed in .gitignore, so I would not expect Git \nto read it at all.\n\n\nAnything else you want to add:\n\nMaking copies of these files instead is not desirable as this would \ndouble the storage capacity needed and copying itself would also take a \nlong time.\n\nPlease review the rest of the bug report below.\nYou can delete any lines you don't wish to share.\n\n\n[System Info]\ngit version:\ngit version 2.49.0\ncpu: x86_64\nno commit associated with this build\nsizeof-long: 8\nsizeof-size_t: 8\nshell-path: /nix/store/xy4jjgw87sbgwylm5kn047d9gkbhsr9x-bash-5.2p37/bin/bash\nlibcurl: 8.13.0\nOpenSSL: OpenSSL 3.4.1 11 Feb 2025\nzlib-ng: 2.2.4\nuname: Linux 6.12.28 #1-NixOS SMP PREEMPT_DYNAMIC Fri May  9 07:50:53 \nUTC 2025 x86_64\ncompiler info: gnuc: 14.2\nlibc info: glibc: 2.40\n$SHELL (typically, interactive shell): /run/current-system/sw/bin/bash\n\n\n[Enabled Hooks]\n\n\nWith kind regards,\nRoel Sengers\n"},{"id":"518670","messageId":"66wu7zyhsi5arpujp4mkidafzbu7fj6jfrqzv4e4smtjev6zd7@cmm3doo3w7ky","threadId":"63500","inReplyTo":"195d93de-1d5d-40f3-8139-b73a447b356f@roelsengers.nl","subject":"Re: [BUG] Hard links to large files cause unexpected refresh","fromName":"Justin Tobler","fromEmail":"jltobler@gmail.com","sentAt":"2025-05-22T16:40:18Z","receivedAt":"2025-05-22T16:44:59Z","isPatch":false,"sender":{"key":"jltobler@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53454972?v=4"},"body":"On 25/05/22 04:45PM, Roel Sengers wrote:\n> Thank you for filling out a Git bug report!\n> Please answer the following questions to help us understand your issue.\n> \n> What did you do before the bug happened? (Steps to reproduce your issue)\n> \n> In my workflow there is a step which hard-links about 80GB of such files to\n> locations where a 3rd party application can find them. However, after this\n> hard-linking step, git status (or other git commands) hang for a long time.\n> Note that making a copy of the file does not cause such slowdowns, which was\n> surprising to me.\n> \n> I am using Git with git-lfs for these large files, however I was able to\n> reproduce this issue without LFS enabled.\n> \n> The script below reproduces the environment which triggers the issue:\n> \n> mkdir git-hardlink-test\n> cd git-hardlink-test\n> \n> git init\n> echo ignore.bin > .gitignore\n> git add .gitignore\n> git commit -m 'Initial commit'\n> \n> dd if=/dev/urandom of=file.bin bs=1M count=1000\n> git add file.bin\n> git commit -m 'Add file.bin'\n> \n> # $ cp file.bin ignore.bin; time git status\n> # On branch main\n> # nothing to commit, working tree clean\n> #\n> # real\t0m0,002s\n> # user\t0m0,000s\n> # sys\t0m0,002s\n> \n> # $ ln file.bin ignore.bin; time git status\n> # Refresh index: 100% (2/2), done.\n> # On branch main\n> # nothing to commit, working tree clean\n> #\n> # real\t0m16,100s\n> # user\t0m15,700s\n> # sys\t0m0,255s\n> \n> \n> What did you expect to happen? (Expected behavior)\n> \n> After creating a hard link to a checked-in object, I expected the final git\n> status to finish in a time that is barely noticeable.\n> \n> The file itself is large, so having Git taking its time to refresh the state\n> of the working directory would not be suspicious were it not for the fact\n> that creating a copy of the same file does not suffer from the same\n> performance penalty.\n\nWhen git-status(1) is run, the index state is checked to see if any\nchanges have occurred. From the provided example, while the contents of\n\"file.bin\" remain unchanged, the act of creating the hardlink does\nupdate metadata such as the number of links and the file ctime. You can\nsee this when you stat(1) \"file.bin\" before and after creating\n\"ignore.bin\". \n\nGit sees these changes and then refreshes the index entry. When the file\nis copied, no such modification happens to \"file.bin\" and thus that\nentry does not need to be refreshed.\n\nTo workaround this problem, you could set `core.trustCTime=false` which\ntells Git to ignore ctime differences between the index and working\ntree.\n\n-Justin\n"}]}