I'm new to git hooks. I'm not able to understand below pre-commit hook. Can anyone tell me how this works please.Here my doubt is how grep will be happened in committed files as we are not taking those files anywhere. Sorry if am asking wrong question but please help me in understanding git hooks..
#!/usr/bin/env ruby
if `grep -rls "require 'ruby-debug'; raise" *` != ""
puts "You twit, you've left a debugger in!"
exit(1)
end
You should rather grep on indexed (cached) files, instead of your working tree.
Otherwise, your grep could find debug instructions in files (or part of files) which aren't part of the next commit.
See "Git pre-commit hook : changed/added files":
git diff --cached --name-only --diff-filter=ACM
As explained in "Why You Need a Git Pre-Commit Hook and Why Most Are Wrong":
Most test against whatever files are currently on disk, not what is in the staging area (the files actually being committed).
The approach if that hook is a bit different: it stashes every work in progress before searching the files.
def main(all_files):
# Stash any changes to the working tree that are not going to be committed
subprocess.call(['git', 'stash', '-u', '--keep-index'], stdout=subprocess.PIPE)
Related
I'd like my commandline (PS1 variable) to display detached heads more elegantly, even if it's a little more ambiguous. The reason I want to do this is because while I never work on detached branches, I frequently encounter them due to our project setup, and want to know what branch they were from (or at least, a branch that they are on).
First of all, I believe I have a sound understanding of the difference between:
The head commit of master
A detached head, which happens to be the same as the head of master
That's the difference between these two commands:
git checkout master # Checkout the master branch
git checkout master~0 # Checkout the commit from the head of the master branch
Now onto the problem. At the moment, my PS1 contains $(__git_ps1) at the end, and commandline shows this as a result:
# git checkout master~1
addison:~/project ((111abcdef1...))$
# git checkout master~0
addison:~/project ((000abcdef0...))$
# git checkout master
addison:~/project (master)$
What I want to happen, is if I'm on a detached head, to be able to find a branch which has a matching commit hash (prefer master), and display the branchname, and how far behind HEAD the commit is, like this:
# git checkout master~1
addison:~/project (Detached(master~1))$
# git checkout master~0
addison:~/project (Detached(master))$
# git checkout master
addison:~/project (master)$
I understand that there may not be a utility that does this already, and I'm ready to accept that - If that is the case, I'd like to know how I can go about finding a branchname for a commit hash, and how far behind the branch's HEAD commit it is. I know that there may be multiple branches that have a commit with the same hash - I just want a 'best effort' solution. That might mean just choosing the most recent, or the closest to HEAD, etc.
Using this information, I can make my own script and embed it in my $PS1 variable, and format it exactly how I want.
UPDATE
I found out there is an option that can be set with $(__git_ps1), which can change the format of the output to be exactly how I want:
GIT_PS1_DESCRIBE_STYLE=contains # git describe --contains HEAD
GIT_PS1_DESCRIBE_STYLE=branch # git describe --contains --all HEAD
GIT_PS1_DESCRIBE_STYLE=tag # git describe --tags HEAD
GIT_PS1_DESCRIBE_STYLE=describe # git describe HEAD
GIT_PS1_DESCRIBE_STYLE=default # git describe --tags --exact-match HEAD
If I set the option to branch, then the output is much more readable.
As you've noted, there isn't a perfect solution. There are two approaches that Git itself uses. One is exemplified by git status: when you're on some branch, HEAD contains the branch name, and when you're detached, HEAD contains a hash ID, but the reflog for HEAD still has the branch name in it, and Git can scan that and pick out a recent branch and see if you're on that commit or one of its descendants and say detached at name or detached from name.1
In your case, though, you might want something more like what git describe does, only in the order that's not the default for git describe. In this case, what you want is more like what git describe --contains does. The --contains option implies the --tags option, which has git describe look at all tags, but not look at any branch names. Fortunately, you can add --all:
git describe --contains --all
which looks at tag and branch names—and other references too, including refs/stash, which may not be so great—and picks one of those to describe the current commit. So this may be the closest thing Git has built in to what you want.
1This feature was not in some very old versions of Git. I'm not sure when it first appeared, and the release notes only mention it in describing a fix to Git 2.4.0. Before 2.4.0, git branch and git status disagreed in when and how they said "detached at" vs "detached from". So it's in 2.4 and later, but earlier versions are less good at it, and at some point, the "detached at/from" stuff just isn't there at all.
I tend to stash changes without remembering why I stash them.
I do make it a point to git stash push -m most of the time, but if there's a fire drill or something else that knocks me out of flow, I may forget and lose time trying to recover.
Is there a way to imitate the behavior of git commit (minus the -m) for git stash where vim pops up and abandons the operation if the message is empty?
AFAIK there's no config option for this. You'll have to write an alias in your .gitconfig and train yourself to use it.
For example, I have two stash aliases git pop and git save. (You can see I didn't get the memo about git stash save being deprecated). These are both for convenience, and to change the default behavior to something I find more useful.
save = stash save -k -u
pop = stash pop
Unfortunately git stash push -m doesn't bring up an editor, if you need to write more than a few words to describe what you were doing consider a branch instead. We can fix this by writing a little shell function and passing the argument to -m using "$#" to ensure messages with spaces are a single argument.
savem = "!f() { git save -m \"$#\"; }; f"
Now you can write git savem 'remember to remember what this was'.
$ git savem 'remember to remember what this was'
Saved working directory and index state On issue/45: remember to remember what this was
And if you forget, you'll get the normal git-stash usage message. You can snazz up the alias to provide a custom usage message if you like.
$ git savem
usage: git stash list [<options>]
or: git stash show [<stash>]
...
To me it makes sense to consider using a branch for this. It seems like you want to keep the changes. Branches can be named so it’s easier to recall what was being worked on. These can be local or pushed to remote in case it wasn’t a drill.
$ git branch topic/wip
If you want continue work on master yo can do a
$ git checkout master
Not pretty but could be achieved using bash + vipe in moreutils
msg="$(< /dev/null vipe)";
[[ -z "$msg" ]] || git stash -m "$msg"
I'm using cygwin under Windows to do some command line stuff. One of the commands I use sometimes is git stash. Since few weeks I always get this error when I use it: Cannot save the current index state
I also tried it in other projects, so it is no project related issue. The history is not broken or something like that. I don't use it often so I don't know when the issue started.
The error is thrown on line 110 of the git-stash file. That's why I debugged the two lines before.
$(printf 'index on %s\n' "$msg" |
git commit-tree $i_tree -p $b_commit)
When I echo the first command it outputs my last commit. This seems ok. When I output both commands piped it is empty, so maybe something is wrong with "git commit-tree $i_tree -p $b_commit". I google a long time but was not able to find a solution to this issue.
Cygwin Git version: 2.14.1
Cygwin x64 version: 2.8.2(0.313/5/3)
First, check if the issue persists with bash (the bash packaged with Git). Make sure to set your PATH in order to:
no include cygwin
include git/bin, git/usr/bin, git/mingw64/bin: see this example.
Working with a simplified path (for testing purposes) is important to make sure there is no side-effect from any other software.
Second, try and add a git status in the git stash critical lines, to see if the Git repo status reveal anything suspicious.
my git repository is quite big and I would like to bring its size down by removing some big files, which I added in the past and already removed later on, but which are still in the git history. Now I found the git filter-branch --tree-filter command. So i tried this:
git filter-branch --tree-filter 'DEL /content/de/files/bigfile.zip' --all
(I'm on Windows).
But the result of invoking this command is:
fatal: ambiguous argument '/content/de/files/bigfile.zip'': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
I don't know, what to do. In the current working directory, the file is indeed not present. But it is still there in a couple of old commits in the history. My understanding was, that the command would remove the file from every commit.
So the actual mistake in my version was, that I used single quotes instead of double quotes. Seems like, at least on Windows, you have to use those.
That said, the comments from jthill and the answer from Roberto probably present better solutions to the task at hand.
You might want to consider the BFG, a faster and simpler alternative to git filter-branch. The equivalent command is :
$ bfg --delete-files bigfile.zip
https://rtyley.github.io/bfg-repo-cleaner/
Disclaimer : I am the author of the BFG
(Disclaimer: I posted a similar question earlier: In a ruby script, how to ask git to open its message editor. I decided to post this as a separate question because I think this question is more generic and thus possibly more applicable to other programmers. However, I kept the git-related question because I'm not sure if an answer here may apply there too. If there are rules against this, let me know)
I'm currently working on a command-line ruby gem that automates the "rebase + no-ff merging" workflow discussed at https://gist.github.com/jbenet/ee6c9ac48068889b0912. You can find the WIP code for this gem at https://github.com/gsmendoza/git_pretty_accept/tree/git_pretty_accept. The gem would do something like this:
`vi some_temp_file.txt`
`git co master`
`git pull`
`git co pull_request`
`git rebase master`
`git co master`
merge_message = File.read('some_temp_file.txt')
`git merge --message "#{merge_message}" --no-ff pull_request`
`git push`
`git branch -d pull_request`
`git push origin:pull_request`
When I try to run these git commands via ruby, vi some_temp_file.txt doesn't open the text editor like I hope it would. Instead, I see a warning "Vim: Warning: Output is not to a terminal" and the script just kind of hangs.
Any ideas?
To run a bash command from within a ruby script, you can use the system() command:
http://www.ruby-doc.org/core-2.0.0/Kernel.html#method-i-system
This should produce the desired behavior in your particular case:
#!/usr/bin/ruby
system('vim', 'some_temp_file.txt')
Running this script from the command line opens the given file in Vim.
system("#{ENV['EDITOR']} 'yourfile.txt")
Will use the editor defined by the user in the EDITOR environment variable.