I'm creating an install script for a load aliases and git config is not playing nice with them
Here is the command in the shell script
git config --global alias.sync-fork '"!f() { oldhash="$(git rev-parse -q --verify refs/stash)"; (git fetch --all && git stash --include-untracked) && ( (git checkout "$(git default-branch)" && git pull && git merge upstream/"$(git default-branch)" && git push && git checkout -); [ "$(git rev-parse -q --verify refs/stash)" != "$oldhash" ] || git stash pop) }; f"'
When I run it and look in the ~/.gitconfig file, I see "\" everywhere and it doesn't work. Using echo, I can see the string I want. This is driving me crazy.
The most immediate problem is that you have too many quotes; '"..."' should just be '...' without the "s inside. However, I can't guarantee that you won't have more issues after you fix that one.
Instead of trying to escape your shell function by hand, have the shell itself do it for you using declare -f to serialize your function.
f() {
oldhash="$(git rev-parse -q --verify refs/stash)"
(git fetch --all &&
git stash --include-untracked
) && (
(git checkout "$(git default-branch)" &&
git pull &&
git merge upstream/"$(git default-branch)" &&
git push &&
git checkout -)
[ "$(git rev-parse -q --verify refs/stash)" != "$oldhash" ] || git stash pop)
}
git config --global alias.sync-fork '!'"$(declare -f f); f"
This does mean git will add some extra escapes to fit the function into proper config-file form, but when you use declare -f the output is guaranteed to be well-formed (at least if your /bin/sh is provided by bash).
Related
I've been trying to create an alias of a long Git command. The command is of this format:
git clone "https://MyUserName#MyDomain.com/a/PathToRepo/RepoName" && (cd "RepoName" && mkdir -p .git/hooks && curl -Lo `git rev-parse --git-dir`/hooks/commit-msg https://MyUserName#MyDomain.com/tools/hooks/commit-msg; chmod +x `git rev-parse --git-dir`/hooks/commit-msg)
I am fine with either an alias or a bash function that can help me accomplish this.
Don't use aliases. They are in every aspect inferior to functions.
Writing this as a function also avoids the quoting errors you probably were bumping into when trying to create an alias (though it's not impossible to solve those, too; but if that's what you want, probably ask a new question with your actual attempt).
The following only has very small changes compared to your original (and to the extent that the original worked in the first place, it would have worked just as well without any changes at all).
func () {
git clone "https://MyUserName#MyDomain.com/a/PathToRepo/RepoName" &&
(
cd "RepoName" &&
mkdir -p .git/hooks &&
curl -Lo "$(git rev-parse --git-dir)/hooks/commit-msg" "https://MyUserName#MyDomain.com/tools/hooks/commit-msg" &&
chmod +x "$(git rev-parse --git-dir)/hooks/commit-msg"
)
}
The switch from legacy `command substitution` syntax to modern $(command substitution) syntax is mainly for aesthetic reasons. The addition of double quotes is crucial for handling file names with spaces or other shell metacharacters in them. Adding && instead of ; before chmod +x seemed to make sense for consistency.
Personally, I would calling git rev-parse --git-dir twice, and just create a variable with the name of the directory:
func () {
git clone "https://MyUserName#MyDomain.com/a/PathToRepo/RepoName" &&
local hookdir=RepoName/$(git -C "RepoName" rev-parse --git-dir)/hooks &&
mkdir -p "$hookdir" &&
curl -Lo "$hookdir/commit-msg" "https://MyUserName#MyDomain.com/tools/hooks/commit-msg" &&
chmod +x "$hookdir/commit-msg"
}
If you want to make the repository name and/or the URL configurable parameters, I would suggest to make the repo name the first parameter and the base URL the second, but this obviously depends on your use case.
func () {
git clone "${2-https://MyUserName#MyDomain.com/a/PathToRepo}/$1" &&
local hookdir="$1"/$(git -C "$1" rev-parse --git-dir)/hooks &&
mkdir -p "$hookdir" &&
curl -Lo "$hookdir/commit-msg" "https://MyUserName#MyDomain.com/tools/hooks/commit-msg" &&
chmod +x "$hookdir/commit-msg"
}
The syntax ${2-default} falls back to default if $2 is unset.
How can I check, in a bash script, if currently homebrew-core and homebrew-cask are shallow clones and unshallow them if they are? If they are already not shallow, I would like to print a message as well.
Running git -C "/usr/local/Homebrew/Library/Taps/homebrew/homebrew-cask" fetch --unshallow on an already non shallow clone just gives an error message instead of graceful handling.
I tried this
if [[ "git rev-parse --is-shallow-repository /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core" == "false" ]]
then
echo "homebrew core is already non shallow. Moving to next step."
else
git -C "/usr/local/Homebrew/Library/Taps/homebrew/homebrew-core" fetch --unshallow
fi
but got
fatal: --unshallow on a complete repository does not make sense
You can use something like
$ for d in homebrew-core homebrew-cask
do
(cd /usr/local/Homebrew/Library/Taps/homebrew/$d && git rev-parse --is-shallow-repository)
done
it will print true or false if the repo is shallow.
This seemed to work
if [[ "git rev-parse --is-shallow-repository /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core | grep -q 'false'" ]]
then
echo "homebrew core is already non shallow. Moving to next step."
else
git -C "/usr/local/Homebrew/Library/Taps/homebrew/homebrew-core" fetch --unshallow
fi
Related to this question: git checkout -B without reset or alternatives?
I want to change branches, but create the branch if it doesn't exist. -B doesn't work, as I have un-pushed commits on the branches and don't want them to be reset.
How would you write this: git checkout branchname -- 2>/dev/null || git checkout -b branchname in powershell?
The equivalent of this shell command...
git checkout branchname -- 2>/dev/null || git checkout -b branchname
...in PowerShell would be this:
$branchname = "your-branch"
git checkout $branchname 2>&1 | Out-Null
if (-not $?) {
git checkout -b $branchname
}
It uses the $? automatic variable, to determine if the last command succeeded. Also, error stream redirection and Out-Null.
Note that in PowerShell 7 (Core), || and && are also available, called pipeline chain operators.
git checkout $branchname || git checkout -b $branchname
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.
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