I want to have one git alias to commit a message and auto filling the branch name in the commit message.
output example: git commit -m "[EX-1234] This is the commit message"
I am looking for a way to only type in the terminal: git cm this is the commit message and it will execute the output example.
Things I have tried
cm = "git commit -m \'[$(current_branch)] ${1}\'"
cm = "!f() { \
git commit -m '[$(current_branch)] $1'; \
}; f"
cm = '!sh -c '\''git commit --m "${1}"'\'' -'
The above examples dont work
Use $# to propagate all the arguments to the underlying command, as in:
cm = "!f() { git commit -m "[$(current_branch)] $#"; }; f"
Related
Background
I have successfully configured Bash completion for various Git aliases. For example:
$ git config alias.subject
!git --no-pager show --quiet --pretty='%s'
$ function _git_subject() { _git_show; }
$ git subject my<TAB>
$ git subject my-branch
Challenge
However, I have a Git alias that I don't know how to set up Bash completion for. The problem is that I want the alias to complete as if for the top-level Git command itself. The alias is this:
$ git config alias.alias
alias = !"f() { if [[ \"$#\" != 1 ]]; then >&2 echo \"Usage: git alias COMMAND\"; return 1; fi; git config alias.\"$1\"; }; f"
# Example
$ git alias s
status
I have tried using _git, __git_main, and __git_wrap__git_main, but none of them work (I think it leads to an infinite loop since it never returns after I press tab).
Is there a way to add completion for a Git alias that completes as if it was the top-level Git command? Or specifically how to have completion for this alias?
Tried but doesn't work
function _git_alias() { _git; }
function _git_alias() { __git_main; }
function _git_alias() { __git_wrap__git_main; }
Desired behavior
$ git alias su<TAB>
subject submodule
$ git alias sub
Alternatively, if there's an easy way to complete for only aliases that would be cool, too. I would like to know how to complete as if for the top-level Git command just for curiosity as well, though.
I was finally able to create a working solution with a bit of hackery around the "magic" Bash completion variables. I changed these variables to "pretend" we were completing the given command as given to git itself.
If anybody has any suggestions to simplify this I would totally be open to suggestions.
# This is complex because we want to delegate to the completion for Git
# itself without ending up with an infinite loop (which happens if you try
# to just delegate to _git).
_git_alias() {
if [[ "$COMP_CWORD" -lt 2 ]]; then
return
fi
local old_comp_line_length new_comp_line_length
COMP_WORDS=(git "${COMP_WORDS[#]:2}")
((COMP_CWORD -= 1))
old_comp_line_length=${#COMP_LINE}
if [[ "$COMP_LINE" =~ ^[^[:blank:]]+[[:blank:]]+[^[:blank:]]+[[:blank:]]+(.*)$ ]]; then
COMP_LINE="git ${BASH_REMATCH[1]}"
fi
new_comp_line_length=${#COMP_LINE}
(( COMP_POINT += new_comp_line_length - old_comp_line_length ))
_git "$#"
# git alias blah
# ^
# 01234567890123
# 0 1
# point: 11
# length: 13
#
# git blah
# ^
# 01234567
# point: 5
# length: 7
#
# point = point - (old length) + (new length)
# point = 11 - 13 + 7
# point = -2 + 7
# point = 5
}
I have this function
git_list_bad_commits() {
git rev-list master..HEAD --oneline -i ${grep:1}
}
Sometimes I want to call it just as it is.
Sometimes I want to call it with the addition of the git argument --count
How do I do that?
Just add the function arguments to the command:
git_list_bad_commits() {
git rev-list master..HEAD "$#" --oneline -i ${grep:1}
}
Background
I would like to make a shell function that takes .gitmodules and iterates over each module executing certain commands based off of each submodules properties (e.g. <PATH> or <URL> or <BRANCH>).
➡️ The default format of .gitmodules:
[submodule "PATH"]
path = <PATH>
url = <URL>
[submodule "PATH"]
path = <PATH>
url = <URL>
branch = <BRANCH>
➡️ Pseudocode:
def install_modules() {
modules = new list
fill each index of the modules list with each submodule & its properties
iteratate over modules
if module # 'path' contains a specified 'branch':
git submodule add -b 'branch' 'url' 'path'
else:
git submodule add 'url' 'path'
}
⚠️ Current install_modules()
# currently works for grabbing the first line of the file
# doesn't work for each line after.
install_modules() {
declare -A regex
regex["module"]='\[submodule "(.*)"\]'
regex["url"]='url = "(.*)"'
regex["branch"]='branch = "(.*)"'
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
cat < ".gitmodules" | while read -r LINE; do
if [[ $LINE =~ ${regex[module]} ]]; then
PATH=${BASH_REMATCH[1]}
echo "$PATH"
fi
done
}
.gitmodules is a .gitconfig-like file so you can use git config to read it. For example, read all values from a .gitmodules, split values by = (key=value), and split keys by .:
git config -f .gitmodules -l | awk '{split($0, a, /=/); split(a[1], b, /\./); print b[1], b[2], b[3], a[2]}'
git config -f .gitmodules -l prints something like
submodule.native/inotify_simple.path=native/inotify_simple
submodule.native/inotify_simple.url=https://github.com/chrisjbillington/inotify_simple
and awk output would be
submodule native/inotify_simple path native/inotify_simple
submodule native/inotify_simple url https://github.com/chrisjbillington/inotify_simple
With a little help from #phd and Restore git submodules from .gitmodules (which #phd pointed me towards), I was able to construct the function that I needed.
install_submodules()
⚠️ Note: Assume $REPO_PATH is declared & initialized.
⚠️ My answer is an adaptation from https://stackoverflow.com/a/53269641/5290011.
install_submodules() {
git -C "${REPO_PATH}" config -f .gitmodules --get-regexp '^submodule\..*\.path$' |
while read -r KEY MODULE_PATH
do
# If the module's path exists, remove it.
# This is done b/c the module's path is currently
# not a valid git repo and adding the submodule will cause an error.
[ -d "${MODULE_PATH}" ] && sudo rm -rf "${MODULE_PATH}"
NAME="$(echo "${KEY}" | sed 's/^submodule\.\(.*\)\.path$/\1/')"
url_key="$(echo "${KEY}" | sed 's/\.path$/.url/')"
branch_key="$(echo "${KEY}" | sed 's/\.path$/.branch/')"
URL="$(git config -f .gitmodules --get "${url_key}")"
BRANCH="$(git config -f .gitmodules --get "${branch_key}" || echo "master")"
git -C "${REPO_PATH}" submodule add --force -b "${BRANCH}" --name "${NAME}" "${URL}" "${MODULE_PATH}" || continue
done
git -C "${REPO_PATH}" submodule update --init --recursive
}
Point of my task : gather info about repo and place it to file while update hook and commit it ( perfectly with new commit).
Problems : when I'm doing commit -> it lockes origin repository and after this push is failing. my code looks like this :
#!/bin/bash
# --- Command line
refname="$1"
oldrev="$2"
newrev="$3"
export GIT_WORK_TREE=$PWD
# --- Safety check
if [ -z "$GIT_DIR" ]; then
echo "Don't run this script from the command line." >&2
echo " (if you want, you could supply GIT_DIR then run" >&2
echo " $0 <ref> <oldrev> <newrev>)" >&2
exit 1
fi
version="${refname##*_}"
branchName="${refname##*/}"
filePath="_componentVersion/BranchVersion.ps1"
if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
echo "usage: $0 <ref> <oldrev> <newrev>" >&2
exit 1
fi
# --- Check types
# if $newrev is 0000...0000, it's a commit to delete a ref.
zero="0000000000000000000000000000000000000000"
if [ "$newrev" = "$zero" ]; then
newrev_type=delete
else
newrev_type=$(git cat-file -t $newrev)
fi
case "$refname","$newrev_type" in
refs/heads/*,commit)
if [ "$oldrev " != "$zero" ]; then
version="${refname##*_}"
branchName="${refname##*/}"
filePath="_componentVersion/BranchVersion.ps1"
countOfCommits=$(git rev-list --count START_$version..$newrev)
countOfPushes=$(git log --pretty=oneline START_$version..$newrev | grep 'Issue nr: HOOK_$version' | wc -l)
countOfPushes=$(($countOfPushes+1))
echo git log --pretty=oneline START_$version..$newrev
message="
# -----------------------
# Brancht Version Info
# -----------------------
\$branch = '$version'
\$countOfCommits = $countOfCommits
\$countOfPushes = $countOfPushes # push
\$commitHash = '$newrev'
"
# credits go to https://stackoverflow.com/questions/9670302/commit-directly-to-a-bare-repository
# branch commit - here we will do the magic about count of commits and about count of pushes
# here we create file for info
# Empty the index, not sure if this step is necessary
git read-tree --empty
# Load the current tree. A commit ref is fine, it'll figure it out.
git read-tree "${newrev}"
# create blob from stdin
BLOB_ID=$(echo "$message" | git hash-object -w --stdin)
# update indexes in git
git update-index --add --cacheinfo 100644 "$BLOB_ID" "$filePath"
# Create a tree from your new index
TREE_ID=$(git write-tree)
# Commit it.
NEW_COMMIT=$(echo "Issue nr: HOOK_$version $message" | git commit-tree "$TREE_ID" -p "$oldrev")
# Update the branch
git update-ref "$refname" "$NEW_COMMIT" "$oldrev"
fi
# Done
exit 0
;;
*)
# Other actions except commit to branch / for now - we won't check it
exit 0
;;
esac
# --- Finished
exit 0
I'm working with bare repo. And example of commit taken from here
Execte problem is
remote: error: cannot lock ref 'refs/heads/REL_7.0.0': ref refs/heads/REL_7.0.0 is at 54f2454ddab36eda001e27946733a7b0e981f097 but expected 89a3032e0bfb999273205e32b7f6d57173c4bd7e
You can create commits.
You cannot update references that are locked, which includes the one that the update hook is being called for.
Since git push can push multiple reference names, there may be additional locked references. In general it's not a good idea to update anything that anyone might be git pushing inside a hook invoked by git push. In other words, don't try to update any branch or tag name. If you want to create new objects, attach them to some name outside these two name-spaces.
(Aside: the git read-tree --empty is not necessary, but it's a good idea to use a temporary index file anyway, rather than using the main index.)
I use Git commit issue numbers in alignment with GitHub issues. To save time I wrote a bash function to creating a commit message like this:
git commit -m "#4 my commit message"
when calling
gci 4 "my commit message"
where 4 is the issue number, and the commit message follows.
However, my current implementation:
alias gcm='git commit -m '
gci(){
index="${#:1}"
message="#$index ${#:2}"
gcm "$message"
}
yields the commit message twice:
$ gci 4 "my commit message"
[iss2 79d9540] #4 my commit message my commit message
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 h.z
What is causing the message to repeat twice?
The ${#:1} and ${#:2} does not work as you expect, use $1 for first parameter and $2 for the second:
alias gcm='git commit -m '
gci(){
index="$1"
message="#$index $2"
gcm "$message"
}
As a side note, alias will not work in noninteractive shells.
No as to ${#:1}, from here:
${var:pos}
Variable var expanded, starting from offset pos.
So if "$#" == "4 my commit message", then:
"${#:1}" == " my commit message"
"${#:2}" == "my commit message"
As you are concatenating ${#:1} ${#:2} you are seeing my commit message twice.