I am trying to write a bash alias to wrap around a Git commit command.
Here is what my typical Git commit looks like.
git commit -am 'Comments in here'
Here is what I have attempted to write as an alias (which would go inside my .bashrc file), so I don't have to write out the whole command every time.
comm(){
git commit -am $1
}
Then I would call it like this: comm 'Comments in here'
However I keep getting this error: fatal: Paths with -a does not make sense.
Anything I'm missing here?
Use More Quotes™ - $1 is being split into words (which have a special meaning in *nix shell scripts). So any words except the first one in your commit message is treated as a filename, which indeed does not make sense with -a.
The -a (automatically add) option is causing the error. If you use it with a path on the git command, you get errors.
The -m option requires an argument, the message, so you either need to make your function manage two arguments or change how you use the function.
To provide a generic git-checkin-with-message function, I'd use something like this:
gcim() {
git commit -m "${1:?'Missing git commit message!'}"
}
Then use it just like git commit -m. For example:
gcim "My cool commit does really good stuff"
Adding files to the commit is almost always better done beforehand. git -a will happily add all files if you happen to use . as an argument. The only thing protecting git commit -a from inserting unwanted files is a properly constructed .gitignore file.
However, if you sometimes want to do a git -a -m "some msg" command, you can make another function:
gciam() {
local msg="${1:?Missing commit message!}"
shift
if (( $# > 0 )) ; then
git commit -m "$msg" $*
else
echo "Missing files to add!"
fi
}
Then, to use:
gciam "added new file" that_file.rb
Related
I am wanting to run a shell script when I invoke the command git worktree add. Reading the docs for post-checkout seems like it would run for git worktree add but it would also run for other commands which I don't want to use it for, such as git checkout.
Is there any other hook I could use? Or perhaps I could use post checkout but have the script setup so it exits if it isn't the git worktree add command?
The reason I want to do this is to run a set of commands to set up my directory that is required when I run git worktree add, but I wouldn't need to do this setup for a normal git repository that is just using git checkout commands.
I have come up with a solution, though I am not sure how rebust it is. I use the post-checkout hook as a bash script, and I have the following lines at the top.
if ! [[ "$0" =~ ".bare/hooks/post-checkout" ]] \
|| ! [[ "$1" == "0000000000000000000000000000000000000000" ]]; then
echo "WARNING: post-checkout hook running for reason otherwise than git worktree add, bailing";
exit 0;
fi
# Do something down here every time we run `git worktree add`
How this works: $0 is the path of the script and $1 is the reference of the previous head.
By convention I have been cloning my bare repository into a directory called .bare which is what the first statement is checking. The second statement is checking that the previous ref of HEAD is that string of 0s. This catches and exits if you are just using other checkout commands such as git checkout because in that case the previous HEAD is not the string of 0s because it was pointing to a commit. However, it seems that because I create a new HEAD every time we run git worktree add it sets the previous HEAD ref to that string of 0s, which allows me to assert on that condition.
This does work for my use case so I am not sure if there is a better way or not. If anyone has a better suggestion then let me know.
P.S. I can get the directory of the new branch simply using pwd in my post-checkout script, which is useful for the commands that I want to run in the hook.
I have this simple function in my bashrc file
function aupgrade {
cat ~/.bash_aliases > ~/bash/.bash_aliases
cd ~/bash
git add .
if [[ $1 == "" ]]; then
git commit -m "Update"
else
git commit -m "$1"
fi
git push origin master
cd - 1>/dev/null
}
This function has a purpose, this is the expected behavior:
First, replace the content of the .bash_aliases file in the bash repository with the stdout of cat ~/.bash_aliases
Second, go into the ~/bash directory which is a git respository
Third, stage all changes
Fourth, if when calling the aupgrade function the following argument is nothing, just commit with the "Update" message, but if the user wrote an argument, like aupgrade "New commit!", commit the changes with such argument as the message, git commit -m $1
Fifth, push the changes
Sixth, go back to the previous directory
BUT, it doesnt do that, instead it just does:
First, replace the content of the .bash_aliases file in the bash repository with the stdout of cat ~/.bash_aliases
Second, go into the ~/bash directory which is a git respository
Third, stage all changes
Fourth, commit with the "Update" message although there is an argument
Fifth, push the changes
Sixth, go back to the previous directory
This is weird. This looks product of the git push origin master line. It's not a conditional problem, because when I wrote another function like this but without the git push origin master line it worked as desired.
Why does this happen? Is there any solution?
This is what set -x shows to me, it's really weird
So I have tested your code, and the only problem I could find is that passing your first argument as a string with multiple exclamation marks inserts the same (or previous?) command unless you escape it:
It looks like this is exactly what happened for you, but you had "set -x" ran beforehand, thus it replaced the double exclamation marks with that command.
I'd also recommend storing function arguments in named local variables for cleaner code.
I wrote a custom shell script for myself to make it easier for me to commit code to Github.
Recently, I wanted to start using Github's ability to automatically close issues by including their number in the commit message:
# Would automatically close #1 on push
git add .
git commit -m "Closes issue #1 ..."
git push
However, the way my script is set up, it grabs all the parameters using $* but that automatically removes anything after the # symbol, because that's a comment in shell scripts.
commit() {
# Print out commands for user to see
echo "=> git add ."
echo "=> git commit -m '$*'"
echo "=> git push --set-upstream origin $current_branch"
# Actually execute commands
git add .
git commit -m "$*"
git push --set-upstream origin $current_branch
}
Now I CAN do commit 'Closes issue #1 ...' with the wrapping quotes, but that's slightly annoying...I specifically setup my script so I could easily write: commit Whatever message I want to put in here...
I've looked over the man pages and done some SO searching, but I can't find anything about the specific issue of escaping # symbols as a parameter.
Is this even possible?
Anything after the # is interpreted by the shell as a comment, so it will not passed to the function. This happens before the function is executed. There is nothing the function can do to prevent this.
There are two canonical ways of doing this:
Just require quoting. Every single Unix tool that accepts command line parameters requires this.
Have the program read the commit from stdin instead with read -r input. You can then run just commit and type in the message.
These are both good solutions because they're simple, familiar, transparent, robust, idiomatic Unix that is straight forward to reason about. It's always better to work with Unix than against it.
However, if you instead prefer a complex, unfamiliar, opaque, fragile special case, you can kludge it with magic aliases and history:
commit() {
echo "You wrote: $(HISTTIMEFORMAT= history 1 | cut -d ' ' -f 2-)"
}
alias commit="commit # "
Here's an example of this:
$ commit This is text with #comments and mismatched 'quotes and * and $(expansions)
You wrote: commit This is text with #comments and mismatched 'quotes and * and $(expansions)
just played a little with it
the script
commit() {
echo "$*"
}
script's usage and output
➜ ~ commit "whatever you want #1 for some reason"
whatever you want #1 for some reason
➜ ~ commit 'whatever you want #1 for some reason'
whatever you want #1 for some reason
➜ ~ commit whatever you want \#1 for some reason
whatever you want #1 for some reason
➜ ~ commit whatever you want #1 for some reason
whatever you want
➜ ~
so if you don't want to quote the message you need to escape the hash with a \ (backslash), that is actually a regular escape character
This question already has answers here:
Git Alias - Multiple Commands and Parameters
(11 answers)
Closed 9 years ago.
I generally use these commands on branch 'work' with git
git commit -a -m "blah! blah!"
git checkout master
git merge work
git checkout work
I have heard about git aliases. Is it possible to combine all these commands into one via aliases or something else.
As well as the answers to the duplicate question posted in the comments, you can also put an executable shell script called git-foo (for example) somewhere in your PATH and access it with git foo <args> as though it were a native Git command.
This could be useful if the logic for your alias is too lengthy for a single line in your config file.
For example:
$ cat > ~/bin/git-foo
#!/bin/bash
echo "Foo: $1"
^C
$ chmod +x ~/bin/git-foo
$ git foo test
Foo: test
As #Will-Vousden suggests, it would be possible to write a shell script to do this. For example:
#!/bin/bash
git commit -a -m "$1"
git checkout master
git merge work
git checkout work
which you would call like:
$ git-commit.sh "Commit message in quotes"
However, this approach (or your own alias) could easily fail if there is, for example, a merge conflict:
$ git-commit.sh "Commit message in quotes"
[work 1a6e17f] Commit message in quotes
1 file changed, 1 insertion(+), 1 deletion(-)
Switched to branch 'master'
Auto-merging file.txt
CONFLICT (content): Merge conflict in file.txt
Automatic merge failed; fix conflicts and then commit the result.
file.txt: needs merge
error: you need to resolve your current index first
leaving you in the master branch with an unresolved merge conflict.
You could probably add some logic into the script to detect -- and potentially work round -- such issues, but that sounds like much more work and effort than just running the four separate commands!
You could also add the following to your shell.rc file:
gmm merges all given branches with the one you are currently on
invoke: gmm branch1-to-be-merged branch2-to-be-merged ...
gmm () {
src=`git branch --no-color | grep "*" | cut -f 2`
for i in $#
do
git checkout $i
git merge $src
done
git checkout $src
}
I am trying to make a bash script which will:
Add all changes to git
Commit with a message I pass to the bash script
Push it to the repo
I am trying to do this with:
m=\"$*\"
git add -A
echo git commit -m $m
git push
However, I am getting errors saying error: pathspec 'Q2,' did not match any file(s) known to git. for everything word I pass to the script.
How can I see what bash it actually doing? When I put echo in front of the offending line (which I presume is the commit) I get a correctly form command. If I put it in to the terminal, I runs find.
To see what bash is doing, add -xv options to the shebang line:
#!/bin/bash -xv
The problem is probably the quoting. m=\"$*\" does not do what you want. $m is still split into several words if it contains whitespace, just the first word starts with a doublequote and the last word ends in a doublequote.
Rather, change the offending line to
git commit -m "$m"