Batch vs Bash and the Pages branch
Unix shell scripts do the exact same thing. As a consequence the shell script can be changed on the fly. The reasoning I heard for this was that shell scripts are supposed to emulate commands typed in at a terminal, hence the care taken (if you process trace a shell and watch how it does file I/O) to line up the offset at the beginning of the next line.
The script was modified on disk while running, but it wasn't reread. Only if I run it a second time do I get a surprise. Have I misunderstood something?
I ran the experiment on my own machine and also ran an `strace` over `sed`, and as it turns out, it is not _quite_ editing the file in place, but is instead creating a new file (called `./seduuTNTQ`) and replacing the original file with it:
openat(AT_FDCWD, "testedit.sh", O_RDONLY) = 3
ioctl(3, TCGETS, 0x7ffca7a76510) = -1 ENOTTY (Inappropriate ioctl for device)
fstat(3, {st_mode=S_IFREG|0755, st_size=113, ...}) = 0
umask(077) = 022
getrandom("\xf8\x42\x97\x97\x3a\x55\x93\xa7", 8, GRND_NONBLOCK) = 8
openat(AT_FDCWD, "./seduuTNTQ", O_RDWR|O_CREAT|O_EXCL, 0600) = 4
umask(022) = 077
fcntl(4, F_GETFL) = 0x8002 (flags O_RDWR|O_LARGEFILE)
fstat(3, {st_mode=S_IFREG|0755, st_size=113, ...}) = 0
read(3, "#!/bin/sh\necho start\nstrace -o s"..., 4096) = 113
fstat(4, {st_mode=S_IFREG|0600, st_size=0, ...}) = 0
read(3, "", 4096) = 0
fchown(4, 1000, 100) = 0
fchmod(4, 0100755) = 0
close(3) = 0
write(4, "#!/bin/sh\necho start\nstrace -o s"..., 113) = 113
close(4) = 0
rename("./seduuTNTQ", "testedit.sh") = 0
close(1) = 0
exit_group(0) = ?
And this does not actually rewrite `testedit.sh` in place as far as executing the script is concerned, because on Unix systems, once you have opened the file, you have long forgotten about using the file's path and are instead referring to the file's inode - a structure on disk with a unique ID that points to the file's contents. The inode structures on Unix are reference counted with both the number of hard links in the filesystem to that file and the number of times that file is currently open, and it is only once both counts hit zero that the file is actually deleted from disk.
In sed's case, since it is creating a new file to write output to, it is creating a new inode that is separate from the one that the shell has open. Moving that file over the original file deletes the hard link to the original inode referenced by the shell, but leaves the inode itself untouched, for the shell to happily continue executing it (then allow the filesystem to delete it once it exits).
Windows systems do not handle files like this - I can't say I know exactly how this works, whether the path is involved and all that, but I do know that having a file open does not count as a reference count and instead Windows makes far more use of locks to manage file integrity. Unix, for instance, allows an executable to be deleted while running, while Windows will prevent you from either writing to or deleting the executable while it is being used by another process.
As for the original problem ...
To regenerate the content of the pages branch and push the changes is a bit of a faff, so I scripted it up and added the script to the main branch. While the script is running, it checks out the pages branch which means that the script no longer exists. ... On my laptop, it's Windows, and while I could have run the same shell script in Cygwin, instead I tried writing it as a batch file. It seemed do-able because it's just calling some external commands and checking if they worked. Easy. But when I run it and it checks out the pages branch, that's when things get tricky. The batch file no longer exists.
Creating a batch file in a temp directory is a good option. What I'd personally be inclined to do, and what I actually do for a CI script we have at work, is create a copy of the entire `.git` folder to a new directory and switch to the `pages` branch from there:
# %MY_TEMP_DIR% should be empty beforehand cp .git %MY_TEMP_DIR%/.git pushd %MY_TEMP_DIR% git reset pages # optional - rehydrate working copy from repository git checkout -- . popd
This way you have both your normal repository and a copy of your pages repository available. A lot of modern Linux filesystems have copy-on-write facilities to make this repository copy cheap and not take up disk space, so this would be safe to do on a space-constrained server as well.