Last active
August 30, 2018 21:37
-
-
Save AliSoftware/2b3a60118fef2826e127de38b5d2016e to your computer and use it in GitHub Desktop.
A "git squash" command to squash multiple commits into one automatically
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
##### | |
# | |
# git-gerrit v1.1 | |
# O. Halligon, 2017.08.18 | |
# | |
##### | |
# | |
# Usage: | |
# | |
# $ git gerrit status [--prune] | |
# For each branch, display if each commit on that branch is already cherry-picked on master | |
# (by searching a commit on master with the same Change-Id). | |
# Adding '--prune' will automatically delete the local branch if all commits of that branch | |
# have been cherry-picked on master already. | |
# | |
# $ git gerrit push | |
# An alias to 'git push gerrit HEAD:refs/for/master' | |
# | |
##### | |
# | |
if [ $(tput colors) -gt 8 ]; then | |
CLR_RED="$(tput setaf 1)" | |
CLR_GREEN=$(tput setaf 2) | |
CLR_CYAN=$(tput setaf 6) | |
CLR_RESET="$(tput sgr0)" | |
fi | |
case $1 in | |
status) # Gerrit status | |
branches=$(git branch --list {dev,bugfix}-*-branch | sed 's/^. //') | |
git checkout master &>/dev/null | |
for branch in $branches; do | |
echo "== Branch ${branch} ==" | |
ids=$(git log --first-parent $branch master.. | sed -n 's/Change-Id: \(.*\)$/\1/p') | |
ready_to_delete=1 | |
for id in $ids; do | |
commit_in_master=$(git log --grep $id --format=%H) | |
if [ "$commit_in_master" ]; then | |
echo -e "${CLR_GREEN} - $id : cherry-picked by $commit_in_master on master${CLR_RESET}" | |
else | |
echo -e "${CLR_RED} - $id : not yet in master${CLR_RESET}" | |
ready_to_delete=0 | |
fi | |
done | |
if [[ "$2" == "--prune" && $ready_to_delete == 1 ]]; then | |
echo -e "${CLR_CYAN} --> Deleting local branch $branch...${CLR_RESET}" | |
git branch -D $branch | |
fi | |
done | |
git checkout - &>/dev/null | |
;; | |
push) # git push on gerrit | |
git push gerrit HEAD:refs/for/master | |
;; | |
*) # Usage | |
echo "Usage:" | |
echo " git gerrit status [--prune]" | |
echo " git gerrit push" | |
;; | |
esac |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
##### | |
# | |
# git-gsquash v1.4.1 | |
# O. Halligon, 2017.07.17 | |
# | |
##### | |
# | |
# Usage: | |
# | |
# $ git squash <tree-ref> | |
# squash all commits on top of the <tree-ref> commit | |
# e.g.: git squash master | |
# | |
# $ git squash --continue | |
# $ git squash --abort | |
# To continue or abort a squash which has been interrupted by a conflict | |
# | |
##### | |
# | |
case "$1" in | |
--edit-todo) # Editor mode to alter the git-rebase-todo file | |
if [[ $(basename "$2") != "git-rebase-todo" ]]; then exit 0; fi | |
# change "pick" to "squash" for all commits except first | |
sed -i '' -e '2,$s/^pick/squash/' "$2" | |
# end the list of actions with a reword of last commit | |
# also let the commit hook be replayed, to add the final Change-Id after the commit message rewording | |
echo exec EDITOR=\"$0 --reword-squashed-commit\" git commit --amend >>"$2" | |
;; | |
--reword-squashed-commit) # Reword the last commit message nicely | |
# Replace intermediate Change-Ids with a separator line | |
# And remove "[DEV] (FF4) … : " prefixes from intermediate commits history | |
sed -e 's/^Change-Id: .*$/----------/' -e 's/^\[DEV\] (FF4) .* : //' -e 's/^\[DEV\] (FF4) //' "$2" > "$2.tmp" | |
# Add a "[DEV] (FF4) $DESC" header at the beginning of the squashed commit message | |
# Where $DESC is generated from the name of the branch, replacing dashes with spaces | |
BRANCH=$(git symbolic-ref HEAD 2>/dev/null || cat `git rev-parse --git-dir`/rebase-merge/head-name) | |
DESC=$(echo $BRANCH | sed "s#^refs/heads/dev-\(.*\)-branch\$#\1#" | tr "-" " ") | |
echo "[DEV] (FF4) ${DESC}\n\n=== Squashed History ===\n" | cat - "$2.tmp" > "$2" | |
rm "$2.tmp" | |
;; | |
--continue) # Helper to continue a squash which has been interrupted by a rebase conflict | |
EDITOR=true git rebase --continue | |
;; | |
--abort) # Helper to abort a squash which has been interrupted by a rebase conflict | |
git rebase --abort | |
;; | |
*) # Main invocation. That's what to execute when you will call `git squash <REF>` from the terminal | |
EDITOR="$0 --edit-todo" git rebase -i $@ | |
;; | |
esac |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
##### | |
# | |
# git-squash v1.4.1 | |
# O. Halligon, 2017.07.17 | |
# | |
##### | |
# | |
# Usage: | |
# | |
# $ git squash <tree-ref> | |
# squash all commits on top of the <tree-ref> commit | |
# e.g.: git squash master | |
# | |
# $ git squash --continue | |
# $ git squash --abort | |
# To continue or abort a squash which has been interrupted by a conflict | |
# | |
##### | |
# | |
case "$1" in | |
--edit-todo) # Editor mode to alter the git-rebase-todo file | |
if [[ $(basename "$2") != "git-rebase-todo" ]]; then exit 0; fi | |
# change "pick" to "squash" for all commits except first | |
sed -i '' -e '2,$s/^pick/squash/' "$2" | |
;; | |
--continue) # Helper to continue a squash which has been interrupted by a rebase conflict | |
EDITOR=true git rebase --continue | |
;; | |
--abort) # Helper to abort a squash which has been interrupted by a rebase conflict | |
git rebase --abort | |
;; | |
*) # Main invocation. That's what to execute when you will call `git squash <REF>` from the terminal | |
EDITOR="$0 --edit-todo" git rebase -i $@ | |
;; | |
esac |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
git squash
Installation:
git-squash
file somewhere in your$PATH
(e.g./usr/local/bin/git-squash
)chmod +x /usr/local/bin/git-squash
Usage
To squash the last 5 commits:
To squash all commits from
master
to current commit (HEAD
) as a single commit on top ofmaster
:git gerrit
Installation
git-gerrit
file somewhere in your$PATH
(e.g./usr/local/bin/git-gerrit
)chmod +x /usr/local/bin/git-gerrit
Usage
git gerrit status
allows you to check all the commits from your local branches and show if they (or rather theirChange-Id
) have already been cherry-picked on master. If a branch have all its Change-Id commits already cherry-picked to master, that mean it's safe to force-delete that local branch.git gerrit push
is just an alias forgit push gerrit HEAD:refs/for/master
Notes
Script
git-squash
can be used outside Gerrit.Scripts
git-gerrit
andgit-gsquash
has been written for a project which uses Gerrit.git-gsquash
does the same asgit-squash
but additionally replaces intermediateChange-Id: …
lines in intermediate commits with a----------
separator line, then let the Gerrit git hook be replayed on the squashed commit to add its ownChange-Id
to itdev-DESC-branch
whereDESC
is a one or multiple dash-separated words describing the change, likeupdate-settings
oradd-awesome-feature
. That short descriptionDESC
will be used to generate the first line of the squashed commit message, replacing dashes with spaces in theDESC
text.prepare-commit
hook which formats all our commits (so including intermediate commits being squashed later) that way, but when squashing we don't need to keep those prefixes in the generated commit history message.