Recently I've encountered a problem. I have an app that talks to the server. I want it to talk to different servers depending on what branch I'm on right now. I think the way for doing that is create a bash script which creates a .h file like
#define BRANCH #"{here goes branch name}"
The only thing is that I don't know Bash. At all :(
Here is what I've tried
branch= git branch| grep '*'
echo $branch
Dunno what to do next... (By the way I'm using Xcode and running this in a "Runs script phase")
This creates the file for the current branch:
current_branch=$(git branch --no-color | grep '*' | sed 's/^\*.//')
echo "#define BRANCH #\"$current_branch\"" > file.h
file.h would contain: #define BRANCH #"your current branch"
You can get the current Git branch with:
git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e "s/* \(.*\)/\1/"
Use vcprompt
It supports Git, Mercurial, subversion and others(?)
Here is one repo: https://github.com/xvzf/vcprompt#readme
It links to other sources as well
Related
I have a bash script containing the following code:
git -C "$1" push origin "$(git_current_branch)"
where "$1" is the git dir I am trying to push.
The problem is, I cannot get the correct "$(git_current_branch)" variable when I run the script from outside the git directory. I know I can just cd to "$1" before pushing, but I want a better solution (which makes my script cleaner).
Is there any way to do that? Thanks in advance!
Edit: I prefer to do this through git command option, if possible.
You can try that:
current_git_branch=$(git -C "$1" branch | sed '/^\*/!d;s/\* //')
explanation
call git in directory "$1" and print all branches
delete all branches without * at start of line
remove '* ' marker for current branch from line
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.
I'm trying to parse the branch I'm currently checked out into to my bash prompt. This is quite easy using the following bash function in your PS1:
parse_git_branch() {
git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'
}
export PS1="\[$(tput setaf 3)\]\u\[$(tput setaf 2)\]#\[$(tput setaf 4)\]\h \[$(tput setaf 5)\]\w\[$(tput setaf 7)\]\[$(tput setaf 3)\]\$(parse_git_branch) \[$(tput setaf 7)\]\\$ \[$(tput sgr0)\]"
My problem arises when the prompt still shows a 'checked out' branch from within a folder inside the .gitignore file.
For instance:
Let's suppose /home/rbroggi/workspace/project_one is the root of my repository tracked by git ( e.g.: the place where the .git folder is to be found). And within this repository I have a .gitignore file /home/rbroggi/workspace/project_one/.gitignore with the following record:
ignoredfolder/. I would assume an empty output/result from git branch once changing directory into the ignoredfolder but instead it keeps outputting the branch I'm checked out in the parent folder. This is very annoying and maybe if I had visibility over how the command git branch works I could avoid getting the output for ignored folders.
rbroggi#arch ~/workspace/project_one (master) $ pwd
/home/rbroggi/workspace/project_one
rbroggi#arch ~/workspace/project_one (master) $ cat .gitignore
ignoredfolder/
rbroggi#arch ~/workspace/project_one (master) $ cd ignoredfolder/
rbroggi#arch ~/workspace/project_one/ignoredfolder (master) $ git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'
(master)
rbroggi#arch ~/workspace/project_one/ignoredfolder (master) $
Thank you for taking the time to trying and helping me.
Rodrigo Broggi
You are assuming that different parts of your worktree could be checked out differently. That is incorrect.
(You can use git checkout to update specific worktree files to match the version from a different commit, but that doesn't change what version is checked out; it just means you have uncommitted changes to that file, which if committed would cause that file to match the other commit's version.)
A given branch (or, in detached head state, a given commit) is checked out for the entire repo. .gitignore has nothing to do with that, and no matter where you go in your worktree, it will be the same. If you see a situation where cding seems to change what branch you're on, it's because you've changed what worktree you're in.
I'm currently using the following two bash functions to chunk through our git repo to determine what the latest version number is on each branch. Since we have several git hooks, including post-checkout, the gitTrackAll function can take quite a while to run. Is there any way to do what I'm doing without checking out every branch, pulling it in, then running a git show?
To clarify, I'm currently checking out each branch and getting the contents of the VERSION file. This essentially tells me what the last version that was merged into that branch is. We occasionally have some branches that stagnate while the developer is working on them. This list provides us a quick way to see what's way behind.
gitTrackAll && gitBranchVersions
function gitTrackAll(){
remote='origin';
for brname in `git branch -r | grep $remote | grep -v master | grep -v HEAD| awk '{gsub(/^[^\/]+\//,"",$1); print $1}'`; do
git checkout "$brname"
git branch --set-upstream-to $remote/$brname $brname;
git pull
done
git checkout master
}
function gitBranchVersions(){
line='--------------------------------------------------------------------------------'
line="$line$line"
for branch in $(git for-each-ref --format='%(refname)' refs/heads/); do
VER=$(git show "$branch":VERSION);
printf "%s %s $VER\n" $branch "${line:${#branch}}"
done
}
The resulting output looks a little like the following (branch names changed)
refs/heads/1954-branch-a ---------------------------------------------------------------------------------------------------------------------------------------- 2.9.27
refs/heads/1955-branch-b ---------------------------------------------------------------------------------------------------------------------------------------- 2.9.43
refs/heads/1965-branch-c ---------------------------------------------------------------------------------------------------------------------------------------- 2.9.32
refs/heads/1968-branch-d ---------------------------------------------------------------------------------------------------------------------------------------- 2.9.101
refs/heads/1969-branch-e ---------------------------------------------------------------------------------------------------------------------------------------- 2.9.114
refs/heads/master ----------------------------------------------------------------------------------------------------------------------------------------------- 2.9.115
I would rewrite gitTrackAll the following way without any checkout at all:
function gitTrackAll(){
remote='origin';
for brname in `git branch -r | grep $remote | grep -v master | grep -v HEAD| awk '{gsub(/^[^\/]+\//,"",$1); print $1}'`; do
git branch --set-upstream-to $remote/$brname $brname;
# git fetch cannot update the current branch - use git pull
git fetch $remote $brname:$brname || git pull $remote $brname
done
}
It looks like I can read files straight from remote. Using pieces from both functions, I've come up with the following, which works perfectly for the application I need.
function gitBranchVersions(){
line='--------------------------------------------------------------------------------'
line="$line$line"
remote='origin' ;
git fetch --all --prune
for brname in `git branch -r | grep $remote | grep -v HEAD| awk '{gsub(/^[^\/]+\//,"",$1); print $1}'`; do
VER=$(git show "$remote/$brname":VERSION);
printf "%s %s $VER\n" $brname "${line:${#brname}}"
done
}
We have a big repo... and drive encryption. So git reset --(whatever) takes quite long. Let's imagine a situation:
you're on a feature branch
you have some configuration changed
you want to checkout master a-clean && pull
checking out master is not possible straight away because you have made some changes
There are several options I know to revert those changes:
git reset --hard --> slow
git checkout . in root dir --> seems it's identical to reset --hard, and slow as well the same way
git stash - takes even longer
git status and then git checkout -- (filename). Now, that's fast, but you have to repeat it for every file!
Myself and bash don't understand each other very well, so doing something fancy like git status | grep modified: | awk "git checkout -- {%2}" is something beyond my current knowledge.
However, maybe there's a command in mgit that does git checkout -- to all the "modified:" files?
git status -s | grep -Po '^ ?M ?\K.*' | xargs git checkout --
-s short format useful to parse
grep -Po : -P perl regex \K keep out of match left of \K, -o print matches
xargs repeat argument as much shell command can accept