bash, script to git add one file and commit - bash

I'm trying to create a script to do this:
git add "file"
git commit -m "Comment"
My idea is to run:
gac "file" "Comment"
I know I can do something similar but for all files, with:
echo 'alias gac="/path/to/gitaddcommit.sh"' >> ~/.bash_profile
And the .sh would be:
!/bin/bash
git add .
echo “Enter commit message: “
git commit -am “$commitMessage”

Well you need two things :
A bin folder where you can put every sh script you want to use everywhere.
More knowledge about shell scripting and how you can get argv (in your ex: 'file' 'Comment')
So first go to your /home/<username> then mkdir bin && cd bin && pwd
then copy the pwd and add it into your PATH env variable inside your .bashrc
path example: PATH='/bin/:/sbin/:/home//bin
Then source ~/.bashrc you can now use every sh script inside you bin folder everywhere.
Cool so first problem done !
you don't have to do echo alias gac="/path/to/gitaddcommit.sh"' >> ~/.bash_profile anymore.
Now second problem here a post that can help you post
And let me show you for your example :
cd ~/bin && vi gac.sh
Now the script :
#!/bin/sh
if [ "$#" -ne 2 ]; then
echo "Usage: ./gac FILENAME COMMIT_MESSAGE" >&2
exit 1
fi
git add "$1"
git commit -am "$2"
First we check the number or arg then git add and commit.
Simple and fast maybe checking if arg one is a file might be a good idea too.
PS: i'm going to re write my post ahah

Here's what I have in my .bashrc:
ga ()
{
if test "$1" != "-f" && git rev-parse HEAD > /dev/null 2>&1 && ! git diff-index --quiet HEAD; then
echo 'Repo is dirty. -f to force' 1>&2;
return 1;
fi;
git add "$#";
list=$(git diff --name-only --cached | tr \\n \ );
git commit -m "Add $list"
}
The commit message is autogenerated, but you could easily modify it to prompt the user or take it from somewhere else.

Related

Bash Script - Determine whether to add file to Git commit [duplicate]

This question already has answers here:
How do I set a variable to the output of a command in Bash?
(15 answers)
Closed 5 months ago.
This is probably a simple one for a bash scripter, which I am not.
I'm running a cron job that downloads some data, and then depending on that data, may or may not modify a second file. After the job, I want to git commit one or both files. For the conditional commit, I tried this in a .sh script:
# attempt to capture whether MyNotes.txt was changed
# by counting lines in git status output
mywc=(git status -s MyNotes.txt | wc -l)
echo $mywc found!
if [ $mywc = 1 ]; then
echo Add file for commit
else
echo Nothing to add
fi
I'm pretty much getting nowhere; this thing seems to fail on the first line with syntax error near unexpected token '|'. If I run git status -s MyNotes.txt | wc -l on the command line, I get the numeric output I expect.
What am I doing wrong and how can I make this work?
If there's a more elegant way to determine whether a file changed, feel free to share.
Also, for my edification, how could I get this to work without the interim mywc variable? I.e., if I wanted to just do the command within the if, something like this:
if [[ $(git status -s MyNotes.txt | wc -l) = 1 ]]; then
...
Thanks!
What am I doing wrong and how can I make this work?
put a dollar before parenthesis.
foo=$(command)
The thing you are using looks like a bash array
declare -a letters=(a b c d)
If there's a more elegant way to determine whether a file changed, feel free to share.
Consider this:
$ git diff -s --exit-code README.md || echo has changed
has changed
$ git checkout README.md
Updated 1 path from the index
$ git diff -s --exit-code README.md || echo has changed
The OR (||) runs if the first command exits with a non-zero code.
Same thing essentially:
$ false || echo false exits with 1
false exits with 1
$ true || echo will not trigger
An aspect of bash that people overlook is that [[, ]], [ and ] are separate commands. They have return codes too. With this knowledge, you can leverage the return codes with if and any other command.
$ if true; then echo yes; else echo no; fi
yes
$ if false; then echo yes; else echo no; fi
no
So for detecting changes in a tracked file:
$ if git diff -s --exit-code README.md; then echo same as in index; else echo changed; fi
same as in index
$ echo 123 >> README.md
$ if git diff -s --exit-code README.md; then echo same as in index; else echo changed; fi
changed
With all of that said...
Just add the file. You don't need to check anything. If it hasn't changed, nothing will happen.
$ echo foo >> myfile
$ git add myfile
$ git commit -m 'maybe changed' myfile
[master b561cc1] maybe changed
1 file changed, 1 insertion(+), 1 deletion(-)
$ git add myfile
$ git commit -m 'maybe changed' myfile
no changes added to commit (use "git add" and/or "git commit -a")
if you need to avoid a non-zero exit code (such as with set -e), just put a || true after the command that you want to ignore the exit status of:
$ cat foo.sh
#!/bin/basho
set -e
echo foo >> myfile
git add myfile
git commit -m 'maybe changed' myfile
git add myfile
git commit -m 'maybe changed' myfile > /dev/null || true
echo no error here. it\'s fine..
false
echo fill never reach this.
Try running that script and see what happens
I search for a way for checking if file changed.
git diff --exit-code -s <path>
Now the bash scripter knows that every command returns a status code which can be checked with $?. In case everything went smoothly, 0 is returned. In that case we get 0 if file is not changed.
Every bash scripter knows too that you can use that with && and || operators (because of lazy evaluation) to write such construct:
git diff --exit-code -s <path> && echo "should add file"
About your edification, what you wrote is perfectly fine!
As CryptoFool pointed out in a comment, I failed to include a $ in my variable assignment. Simple fix in the first line of my script:
mywc=$(git status -s MyNotes.txt | wc -l)
As matt pointed out in a subsequent comment, doing a git add on a file that hasn't changed has no effect. It won't stage the file for commit. So instead of doing conditional logic to determine whether to git add myfile.txt, I'll just blindly execute git add myfile.txt, which will either stage the file if there are changes, or do nothing if there are no changes. Therefore, my entire script can be replaced with one line:
git add MyNotes.txt

Iterating over subdirectories: How do I recover if a command in one fails?

I have this for loop
for repository in ./*/; do
echo $repository && cd $repository && git checkout -b prod && cd - >/dev/null;
done
But if branch prod already exists it prints a message and exit the loop.
How can ignore this error and just go to the next directory ?
Thanks
So the problem is that git checkout -b prod returns failure to the shell if the branch already exists. Since it's connected to the next command (cd -) with the conditional operator &&, that next command only runs if git succeeds. So when git fails, the cd doesn't run, and your shell is left in the wrong directory to continue its loop.
In general, when you want your code to continue even if a command fails, separate the commands with ; or newlines instead of &&.
But a better solution in this case is to just do the cd in a subshell so that it doesn't affect the outer loop's working directory and you don't have to cd - at all:
for repository in ./*/; do
echo "$repository" && (
cd "$repository" && git checkout -b prod
)
done
That will work fine even if the branch creation fails. It will still print out the error message; if you don't want to see those, add the redirect:
for repository in ./*/; do
echo "$repository" && (
cd "$repository" && git checkout -b prod
) 2>/dev/null
done
I've also quoted the expansion of $repository in the commands, which you should almost always do in shell scripts. With the unquoted version, you would get an error if any of the repo directory names had spaces in them, for instance.
Also, that "no side effects in a subshell" thing is great for doing part of your work in a different directory, but it applies more widely. If you had a more complicated loop that set any shell variables or anything while it was in the subdir, those would also be lost. Just something to keep in mind.
Like this
home=$PWD
for repository in "$home"/*/; do
basename "$repository" # to 'echo' $repository
cd "$repository" && git checkout -b prod
done
Better use pushd and popd and additionally it is saver to use find:
while read -r repository; do
pushd "${repository}"
if git checkout -b prod; then
echo "git checkout success"
else
echo "git chechout error"
fi
popd
done < <( find . -mindepth 1 -maxdepth 1 -type d -print )

how to run a shell script as an alias?

I wanna alias a script to my zsh. Aliasing a script in zshrc does not work, the output of the script in nothing
There are no syntax errors in my script. i have tried running
"sh ./script.sh" in the script containing folder which does fetches the desired result but alias something="sh ~/script.sh" does not work
even alias something="source ~/script.sh" does not work
the script creates a local project and a github repo
contents of the script:
#!/bin/bash
function create () {
read -p 'Repository Name: ' uservar
projects_directory = ~/Downloads/Projects/ #change this path to the directory where you want to store you files
mkdir $projects_directory/$uservar
cd $projects_directory/$uservar
git init
touch README.md
echo -e "#$uservar" >> $projects_directory/$uservar/README.md
# this is where we make a github repo from cli
repo_name=$uservar
test -z $repo_name && echo "Repo name required." 1>&2 && exit 1
curl -u 'thisisshub' https://api.github.com/user/repos -d "{\"name\":\"$repo_name\"}" #change thisisshub to your <username>
#making a git repo from cli ends
git add .
git commit -m "Initial Commit"
git push -u origin master
code .
}
expected result: successful aliasing of a script
actual result: no output

How can I get git's `.git` path from git itself?

I am trying to write a shell script that needs to be able to find the .git folder for the current directory, correctly handling all of the following possibilities:
I might be in a bare repo, in which case the .git folder is either . or .. or ../.. or so on.
I might be in a submodule (in which I'll find a .git file that contains the path to the git folder)
$GIT_DIR might be set.
I might not be in a git repo at all
I have this:
seemsToBeGitdir() {
# Nothing special about "config --local -l" here, it's just a git
# command that errors out if the `--git-dir` argument is wrong.
git --git-dir "$1" config --local -l >/dev/null 2>/dev/null
return $?
}
gitdir() {
local cursor relpath
if [ "$GIT_DIR" ]; then
echo "$GIT_DIR"
return 0
fi
cursor="$(pwd)"
while [ -e "$cursor" ] && ! seemsToBeGitdir "$cursor"; do
# Git won't traverse mountpoints looking for .git
if mountpoint -q "$cursor"; then
return 1
fi
# We might be in a submodule
if [ -f "$cursor/.git" ]; then
# If .git is a file, its syntax is "gitdir: " followed by a
# relative path.
relpath="$(awk '/^gitdir:/{print$2}' "$cursor/.git")"
# convert the relative path to an absolute path.
cursor="$(readlink -f "$cursor/$relpath")"
continue
fi
if seemsToBeGitdir "$cursor/.git"; then
echo "$cursor/.git"
return 0
fi
cursor="$(dirname "$cursor")"
done
echo "$cursor"
}
And it works, but seems way too complicated -- clearly, git itself does this sort of calculation every time it's invoked. Is there a way to make git itself tell me where .git is?
Use git rev-parse, which has options specifically for this:
git rev-parse --git-dir
See also:
git rev-parse --absolute-git-dir
(new in Git version 2.13.0), and:
git rev-parse --show-toplevel
and:
git rev-parse --show-cdup
(note that its output is empty if you are already in the top level of the repository). View your own documentation to find out which options your Git supports; most of these have been around since Git 1.7, though.

Automatically launch command when cd into a choosen directory

I would like to launch : $ git status
when I cd into ~/work
I thought about putting an alias that would cd me into the work directory and launch the git status, but I don't find that solution to be optimal.
Add this to your .bashrc:
gitstatusinwork() {
if [[ "$PWD" != "$MYOLDPWD" ]]; then
MYOLDPWD="$PWD"
if [[ "$PWD/" = ~/work/* ]]; then
if [[ "$OLDPWD" != ~/work/* && "$INWORKDIR" == 0 ]]; then
git status
fi
INWORKDIR=1
else
INWORKDIR=0
fi
fi
}
export PROMPT_COMMAND="$PROMPT_COMMAND; gitstatusinwork"
This function executes git status as soon as your enter your ~/work directory (or any of its subdirectory), then never displays it again, unless you get out of the ~/work directory and re-enter it again.
The easiest way is:
cd ~/work && git status
I don't think you're looking for this though.
Another option would be overwriting the default cd command. You could place a bash function at the end of your .bashrc or .bash_profile file like so:
cd() {
builtin cd "$1"
# detect if the current directory is a git repository
if [ -d .git ] || git rev-parse --is-inside-work-tree 2> /dev/null > /dev/null; then
echo ""; git status
fi
}
I hope this helps.
Update:
If you just want to see the git status when you cd into the root of your repo, you can just use the first part of the conditional like so:
cd() {
builtin cd "$1"
# detect if the current directory is a git repository
if [ -d .git ]; then
echo ""; git status
fi
}

Resources