I have a bare git repository running on a Windows machine, and I am trying to have it run a post-receive hook. I have the following in the hooks/post-receive file
cmd //c "activate <some-env> && do-something"
which works nicely if it is run manually from Git Bash. However, it doesn't run after a commit is pushed.
The file's permissions, as obtained from Git Bash by doing ls -lh, are 644. This may be the issue, but chmod +x <file> has no effect. Neither does git update-index --chmod=+x <file>, as suggested elsewhere - this results in fatal: this operation must be run in a work tree (I guess this is not meant for a bare repository). The permisions in the sample hooks are well set, but if I do echo <my-command> > some-hook.sample the execute permissions are lost. This is also the case if I modify the file using e.g. Notepad++.
How does one change the execute permissions in this case?
Thanks!
Related
So I am trying to change the Powershell Scripts as executable and commit them as such with an updated index. Is there a way I can do this?
I know in bash it's fairly easy:
sudo chmod +x some_file.sh
git update-index --chmod=+x some_file.sh
git add -A
git commit -a
git push
Any thoughts on how I can do this for Powershell Scripts within Windows Machines?
On Unix, you don't need any special command apart from git add, git can detect the executable bit from the worktree. git diff even lists mode changes.
On Windows, you can use git add --chmod +x file.
You can use git ls-files --stage to see which files are executable.
I use git in windows.
I know for set executeable file and commit it, can use this:
git update-index --chmod=+x <file>
But now, How can just set read and write permission (unix chmod 0777) to a folder and git commit it in windows?!
And also I try git config core.filemode true and chmod 077 <folder> in Cygwin but does not work.
Note that I am talking about folder and not file permissions.
You cannot. Git does not store the complete permissions for files, it only stores whether a file is executable or not. For folders, it stores no permissions at all.
Your umask will influence the permissions that are used when folders are created on your local machine, but this is not something that can be committed to the repository.
Since windows does not use the permissions bit(s) it has no effect under windows.
One way to "force" git to track those changes is to work with the git Bash which will cause git to work in a Unix like environment and due to that you will be able to track changes made to the file permissions.
Here is a working demo for you
I have the following code to checkout in a working directory in the hook post-receive:
#!/bin/sh
git --work-tree=d:/websites/__gitweb --git-dir=d:/_gitrepo.git/ checkout -f
Unfortunately it doesn't seem to work. However, the command does work when I enter just this in the windows command line (cms):
git --work-tree=d:/websites/__gitweb --git-dir=d:/_gitrepo.git/ checkout -f
I have checked the permissions and the executing attributes but nothing.
UPDATE:
I think I'm getting closer. Now I know what the problem is but I don't know why is this happening. The hook is actually being triggered but I receive this message:
remote: Starting copy from repository to work tree...
remote: fatal: Not a git repository: 'd:/_gitrepo.git/'
remote: Finished.
I have tried to change the path of d: to the whole network path but it still doesn't work. If I go to the remote repository and I do a git log, the changes are there and if I run the hook with sh, it works.
Why is it saying that it is not a git repository when clearly it is?
I finally got it working!
This is really weird. I had to type a pwd to see where actually is the batch being located and it showed the hook location on the server. However, in the next line I added a hostname and it showed me my local hostname.
Then I add the whole path just like:
#!/bin/sh
echo "Starting copy from repository to work tree..."
pwd
hostname
git --work-tree=//remotehost/d$/Webseiten/__gitweb --git-dir=//remotehost/d$/_gitr
epo.git checkout -f
echo "Finished."
I hope this solution works for someone
For a shell script (and those hook scripts will be executed as shell, even in Windows, through the msys layer of msysgit), you could use a different sort of path:
#!/bin/sh
git --work-tree=/d/websites/__gitweb --git-dir=/d/_gitrepo.git/ checkout -f
See also other possibilities with "Posix path conversion in MinGW"
I'm just starting to look into Git hooks, but I can't seem to get them to run.
I set up a local repository, so there is now a '.git' directory in my project folder. I have added a '.cmd' file into the C:/path/to/my/project/.git/hooks directory named 'pre-commit.cmd'. Here is the contents of this file:
echo "HOOK RUNNING"
echo. 2>C:/path/to/my/project/.git/hooks/EmptyFile.txt
This should echo the text "HOOK RUNNING" and create an empty text file in that directory. However, if I commit changes through my IDE (NetBeans) or use Git Bash to commit, neither of them seem to run my pre-commit hook, as no file is created.
My understanding is that all you have to do to get a hook to run is add an executable with the name of the hook (as I have done). Am I doing something wrong?
Note: This is on a Windows 7 PC.
Name your hook pre-commit (without any file extension).
And add #!/bin/sh on the first line or #!/bin/bash.
You probably don't have the permissions to run the pre-commit file
Run in your terminal:
chmod +x .git/hooks/pre-commit
Thanks to #vaughan for giving the idea
TL;DR
Git hooks work on Git for Windows by default assuming the Git hook script is simple.
Background of Git and Windows
Please Note: Git was made for shell interpretation; thus, using Git hooks on a Windows command prompt or Windows-made PowerShell will inherently have its flaws, and complete interoperability is not to be expected.
Using Git hooks on Windows is possible, but it has many drawbacks.
Git for Windows uses a shell emulator that makes Bash and shell commands possible. This means that when a Git hook is activated by Git, the Windows version will run the command using the shell emulator. Which in turn, will convert those shell commands to commands that the Windows operating system can understand. Meaning, simple shell scripts will work right off the bat. For example, the Git hook pre-commit that ships with an initialization of a Git repository can be run without any modification.
Example of default behavior
Initialize a Git repository with the command git init
Navigate to the Git hooks directory with the command cd .git\hooks
This directory holds all the Git hook scripts. Create a file named pre-commit. Note:
The name of the file is important
Replace the contents with the following shell script
#!/bin/sh
echo "Hello, World!"
Navigate back to your root directory of the project and create a file named test.txt using the command echo "something" > text.txt
Stage the file to commit using the command git add test.txt
Commit the change and watch the pre-commit hook activate using the command git commit -m "test commit"
Verify the output to look like the following
git commit -m "test commit"
Hello, World!
[master f00ccea] test commit
Example of bad behavior
When using a very advanced shell script to do things in Git hooks, Windows shell interpretation doesn't always stack up. For example, when using the Husky Git hook plugin for NPM, along with the Prettier formatter, the commands do not map 1-1. Meaning that your pre-commit Git hook will fail on Windows.
Answering user1578653's question
A Git hook is an executable script; however, you are using a command prompt script (.cmd) and not a shell script (.sh). If you would like this behavior you described on a Windows operating system then create the file named pre-commit and place it in the .git\hooks directory (relative to the project you are working on). Then place the following content in that file.
.git\hooks\pre-commit
#!/bin/sh
echo "HOOK RUNNING"
thisCausesError 2> .git/hooks/EmptyFile.txt
You will notice that the Git hook works and outputs the words HOOK RUNNING to the console, and the thisCauseError will print an error message to standard error that will be printed to the file EmptyFile.txt.
In my case, I had set core.hooksPath to the wrong directory.
Resetting it with git config --global core.hooksPath '~/.githooks' solved the issue :)
You can verify your hooks path using git config --get core.hooksPath
For me, I tried to run a .bat file.
I discovered that backslashes need to be escaped:
For example:
#!/bin/bash
C:\\somefolder\\somefile.bat
For me, none of the previous solutions worked. I moved the pre-commit file from hooks to some other location, effectively deleting the file from hooks.
That worked for me :D
In my case, where I did npm install and accidentally deleted the .git folder, npm install pre-commit --save worked.
If it helps anyone:
I was getting the following error:
error: cannot spawn .git/hooks/pre-commit: No error
It turned out that in my pre-commit file I did not have 'newline' character after last exit command:
#!/bin/sh
# From gist at https://gist.github.com/chadmaughan/5889802
# Stash any unstaged changes
git stash -q --keep-index
# Run the tests with the Gradle wrapper
./gradlew test --daemon
# Store the last exit code in a variable
RESULT=$?
# Unstash the unstashed changes
git stash pop -q
# Return the './gradlew test' exit code
exit $RESULT
# << must have a newline after the above command >>
I was running a Gradle project on Windows and Gradle commands in the Cmder shell and cmd.
I tried solutions suggested in other answers and it didn't help to fix this problem:
cannot spawn .git/hooks/pre-commit: No such file or directory
The solution, which worked for me, was to rename the file .git/pre-commit.sample to .git/pre-commit and insert the script for formatting changed files with Prettier. The file with the name 'pre-commit' which I have created manually must have had some problems (encoding or end-line symbols remains unclear).
I'm using git on windows with the git bash and every time I want to autocomplete a filename in a git command I get fatal: Not a git repository: '.git' posted between my already typed characters and the completed ones.
It looks like this:
$ git diff a
<using tab>
$ git diff afatal: Not a git repository: '.git'
pp.js
I can still make the command properly by just pressing enter as expected. But it really starts to get on my nerves.
Any suggestions?
The problem was an extra .git-folder in my src folder. The repository was initialized on the folder above (src/..) and this seemed to mess with git. After the removal of the extra .git folder the problem disappered.
I just discoverd the solution. I had an extra .git directory in my src-folder which seemed to mess with git (the repository was initialised on the folder above).
After I removed the extra .git folder the problem disappered.
It can depends on the msysgit version you are using:
I just tested a tab completion on a git diff on W7 64bits, with the latest msysgit1.8.3, and it worked just fine.
Don't forget that, in addition to the msysgit version, you will have issues with tab completion due to the old bash 3.1 included in mysysgit.
And the completion can be slow on Windows.
As the OP Zeeker mentions below, the completion git-completion.bash is based on a proper git repo path detection.
# __gitdir accepts 0 or 1 arguments (i.e., location)
# returns location of .git repo
__gitdir () {
...
}
And in Zeeker's case, an extra .git folder was in the src folder, which means any completion was based from the wrong folder, which, for git diff, proved fatal.
git add seems to work though.
git-bash completion for git commands is controlled by the /etc/git-completion.bash. To fix run git-bash as administrator, then:
cd /etc
mv /etc/git-completion.bash /etc/git-completion.bash.orig
Then create a new one from the contents of https://github.com/git/git/blob/master/contrib/completion/git-completion.bash