bash maintain old value for variable - bash

I have this bash script that I want to duplicate a branch and make a PR to a remote repo using that duplicate branch then delete the duplicate branch:
gPullRequest () {
branch=$(git rev-parse --abbrev-ref HEAD)
if [ $# -eq 0 ]
then
git checkout -b development-$branch
elif [ $# -eq 1 ]
then
git checkout -b release-$branch
fi
gp
prBranch=$(git rev-parse --abbrev-ref HEAD)
if [ $# -eq 0 ]
then
hub pull-request -h org:$prBranch -b org:development
elif [ $# -eq 1 ]
then
hub pull-request -h org:$prBranch -b org:$1
fi
git checkout $branch
git branch -D $prBranch
}
The problem is the variable branch gets re evaluated to what prBranch is pointing to by the time
git checkout $branch
When this code runs, the branch variable is the new branches name instead of the first value from the first line of code.
Any thoughts on how to preserve the value of branch for later execution of the bash script?
edit
gp () {
branch=$(git rev-parse --abbrev-ref HEAD)
git push origin $branch
}
this was previously not present in the original prompt, but is the reason for the bug.

This quite certainly means your bp function starts like:
bp() {
branch=$1
othervar=$(whatever)
# ...do stuff here...
}
You can't do that safely, because -- like Javascript -- variables are global by default in bash. Thus, setting branch inside a function you call changes the value in the parent as well.
Always declare your locals, like so:
bp() {
local branch othervar
branch=$1
othervar=$(whatever)
# ...do stuff here...
}
(Why two separate lines, rather than local branch=$1? Because when you want to move on to local foo=$(bar), the local command eats the exit status of bar, making its success or failure impossible to determine later; maintaining a habit of keeping your local declarations to a separate line avoids the issue).

Related

change directory in bash is not affecting the post-commit hook

i've made the following bash script to commit the parent repo after some change in submodule.
it's all about that the script want to cd .. to check the parent repo current branch but the problem is that the cd .. is not affecting the upcoming commands because i guess the subshell
i've tried to run
1- cd ../ && before each command
2- make alias but didn't succeed
3- run exec but the script didn't continued
#!/bin/sh
#
# An example hook script to verify what is about to be committed.
# Called by "git commit" with no arguments. The hook should
# exit with non-zero status after issuing an appropriate message if
# it wants to stop the commit.
#
# To enable this hook, rename this file to "post-commit".
commit_msg= git log -1 --pretty=%B
if [[ $(git branch | grep \* | cut -d ' ' -f2) == "int1177/next" ]]; then
cd ..
if [[ $(git branch | grep \* | cut -d ' ' -f2) == "B0/next" ]]; then
git add 6_Tests
git commit -m "bs esss"
echo "development branch B0/next has now new commit"
else
echo "development branch isn't B0/next"
fi
else
echo "current branch isn't int1177/next"
fi
Actually, this particular problem is not a bash issue, but rather a Git issue.
Why doesn't "cd" work in a shell script? is valid in general, and is a suitable answer to many other questions. But this particular post-commit hook is trying to chdir out of a submodule into its parent superproject, then make a commit within the parent superproject. That is possible. It may be a bad idea for other reasons—in general it's unwise to have Git commit hooks create commits, even in other repositories1—but in this particular case you're running into the fact that Git finds its directories through environment variables.
In particular, there's an environment variable GIT_DIR that tells Git: The .git directory containing the repository is at this path. When Git runs a Git hook, Git typically sets $GIT_DIR to . or .git. If $GIT_DIR is not set, Git will find the .git directory by means of a directory-tree search, but if $GIT_DIR is set, Git assumes that $GIT_DIR is set correctly.
The solution is to unset GIT_DIR:
unset GIT_DIR
cd ..
The rest of the sub-shell commands will run in the one-step-up directory, and now that $GIT_DIR is no longer set, Git will search the superproject's work-tree for the .git directory for the superproject.
As an aside, this:
$(git branch | grep \* | cut -d ' ' -f2)
is a clumsy way to get the name of the current branch. Use:
git rev-parse --abbrev-ref HEAD
instead, here. (The other option is git symbolic-ref --short HEAD but that fails noisily with a detached HEAD, while you probably want the quiet result to be just the word HEAD, which the rev-parse method will produce.)
1The main danger in this case is that the superproject repository is not necessarily in any shape to handle a commit right now. Edit: or, as discovered in this comment, is not even set up to be a superproject for that submodule, yet, much less to have a submodule-updating commit added.

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.

ZSH alias with parameter

I am trying to make an alias with parameter for my simple git add/commit/push.
I've seen that a function could be used as an alias, so I tried but I didn't make it.
Before I had:
alias gitall="git add . ; git commit -m 'update' ; git push"
But I want to be able to modify my commits:
function gitall() {
"git add ."
if [$1 != ""]
"git commit -m $1"
else
"git commit -m 'update'"
fi
"git push"
}
If you really need to use an alias with a parameter for some reason, you can hack it by embedding a function in your alias and immediately executing it:
alias example='f() { echo Your arg was $1. };f'
I see this approach used a lot in .gitconfig aliases.
You can't make an alias with arguments*, it has to be a function. Your function is close, you just need to quote certain arguments instead of the entire commands, and add spaces inside the [].
gitall() {
git add .
if [ "$1" != "" ] # or better, if [ -n "$1" ]
then
git commit -m "$1"
else
git commit -m update
fi
git push
}
*: Most shells don't allow arguments in aliases, I believe csh and derivatives do, but you shouldn't be using them anyway.
I used this function in .zshrc file:
function gitall() {
git add .
if [ "$1" != "" ]
then
git commit -m "$1"
else
git commit -m update # default commit message is `update`
fi # closing statement of if-else block
git push origin HEAD
}
Here git push origin HEAD is responsible to push your current branch on remote.
From command prompt run this command: gitall "commit message goes here"
If we just run gitall without any commit message then the commit message will be update as the function said.
"git add ." and the other commands between " are just strings for bash, remove the "s.
You might want to use [ -n "$1" ] instead in your if body.
I tried the accepted answer (Kevin's) but was getting the following error
defining function based on alias `gitall'
parse error near `()'
Hence changed the syntax to this, based on the git issue and it worked.
function gitall {
git add .
if [ "$1" != "" ]
then
git commit -m "$1"
else
git commit -m update
fi
git push
}
I can easily add params just using $1.
Eg:
alias gsf="git show --name-only $1"
works just fine. To call it I just use gsf 2342aa225

How to get the current git branch in shell

I'm trying to write a shell script that should fail out if the current git branch doesn't match a pre-defined value.
if $gitBranch != 'my-branch'; then
echo 'fail'
exit 1
fi
Unfortunately, my shell scripting skills are not up to scratch: How do I get the current git branch in my variable?
To get the name of the current branch: git rev-parse --abbrev-ref HEAD
So, to check:
if test "$(git rev-parse --abbrev-ref HEAD)" != my-branch; then
echo Current branch is not my-branch >&2
exit 1
fi
You can get the branch using git branch and a regex:
$gitBranch=$(git branch | sed -n -e 's/^\* \(.*\)/\1/p')
After that you just have to make your test.

Git Bash Script Check Working Tree

Is there a way in Git Bash to check if the working tree is clean, that is no uncommitted changes or untracked files?
I'm working on a bash script for my group to automate the process of daily rebasing working branches. Unclean working trees is a common problem. I can manually correct the problem by executing git checkout .. This would have the desired result most of the time, but not always, so I need to be able to have my script programatically check that the working directory/tree is clean.
The git-sh-setup script included with git contains a number of useful functions for working with git repositories. Among them is require_clean_work_tree:
require_clean_work_tree () {
git rev-parse --verify HEAD >/dev/null || exit 1
git update-index -q --ignore-submodules --refresh
err=0
if ! git diff-files --quiet --ignore-submodules
then
echo >&2 "Cannot $1: You have unstaged changes."
err=1
fi
if ! git diff-index --cached --quiet --ignore-submodules HEAD --
then
if [ $err = 0 ]
then
echo >&2 "Cannot $1: Your index contains uncommitted changes."
else
echo >&2 "Additionally, your index contains uncommitted changes."
fi
err=1
fi
if [ $err = 1 ]
then
test -n "$2" && echo >&2 "$2"
exit 1
fi
}
This is in addition to being able to check the output from git status --porcelain and/or git status -z if you need to be more specific about what the state currently is.

Resources