Reputation: 9442
I have a script test.sh
#!/bin/bash
echo start old file
sleep 20
echo end old file
in the repository which I do execute, and in the mean time I git merge other-branch
changes like
#!/bin/bash
echo start new file
sleep 20
echo end new file
into the current branch.
It seems that git on Unix (?) does not directly overwrite the existing file node (?) and does instead rm test.sh
and creates the new file.
In that way its guaranteed that the script execution will always read the initial file test.sh
and terminate with echo end old file
.
Note: On my system (Ubuntu 20.04), while executing the script and directy overtwriting the content in an editor, results in executing the new code, which is bad...
Is that correct and is it also correct on Windows with git-for-windows?
Upvotes: 1
Views: 224
Reputation: 9442
On Windows with git-for-windows I see the same behavior:
$ mklink /H test.sh.bak
$ fsutil hardlink list test.sh.bak
test.sh.bak
test.sh
$ git merge test
$ fsutil hardlink list test.sh.bak
test.sh.bak
Meaning the hard link did not get preserved, meanin a new file has been created.
Upvotes: 0
Reputation: 13079
I can't answer regarding Windows, but on Ubuntu 18.04 I can confirm that a git checkout
or git merge
will delete and recreate a changed file, rather than editing it in place. This can be seen in strace
output, for example:
unlink("test.sh") = 0
followed later by
openat(AT_FDCWD, "test.sh", O_WRONLY|O_CREAT|O_EXCL, 0666) = 4
It can also be seen if you create a hard link to the file before the git
command and then look again afterwards, you will see that you have two different inodes, with different contents. This is to be expected following deletion and recreation, whereas an in-place edit would have preserved the hard linking.
$ ls -l test.sh
-rw-r--r-- 1 myuser mygroup 59 Jun 5 17:04 test.sh
$ ln test.sh test.sh.bak
$ ls -li test.sh*
262203 -rw-r--r-- 2 myuser mygroup 59 Jun 5 17:04 test.sh
262203 -rw-r--r-- 2 myuser mygroup 59 Jun 5 17:04 test.sh.bak
$ git merge mybranch
Updating 009b964..d57f33a
Fast-forward
test.sh | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
$ ls -li test.sh*
262219 -rw-r--r-- 1 myuser mygroup 70 Jun 5 17:05 test.sh
262203 -rw-r--r-- 1 myuser mygroup 59 Jun 5 17:04 test.sh.bak
You mentioned in a comment attached to the question that it is related to Overwrite executing bash script files. Although it would seem not to be the best idea to run a git command affecting a script which is currently still being executed, in fact the delete and recreate behaviour should mean that the existing execution will be unaffected. Even if the bash
interpreter has not yet read the whole file into memory, it will have an open filehandle on the existing inode and can continue to access its contents even though that inode is no longer accessible via the filename that it had. See for example What happens to an open file handle on Linux if the pointed file gets moved or deleted
Upvotes: 4