Permalink
Browse files

Refactor and improve `git squash`

`git squash` refactor:
- first argument can be a branch or a commit reference
- the `--me` argument is not required anymore
- use `git reset --soft` is squashing on a current branch
- if squashing on master branch, prompt for confirmation
- does not delete provided branch after squashing
- fix bug: if `git merge --squash` command fails, exit script

Update README and man pages.

Fixes #95
Closes #198
  • Loading branch information...
1 parent 458c08d commit b2576adae07d41f0f6e9b61cab017c14b87c75cc @bruno- bruno- committed Jul 20, 2014
Showing with 81 additions and 42 deletions.
  1. +9 −2 Readme.md
  2. +44 −29 bin/git-squash
  3. +11 −6 man/git-squash.1
  4. +10 −4 man/git-squash.html
  5. +7 −1 man/git-squash.md
View
@@ -505,13 +505,20 @@ $ git graft new_feature dev
$ git graft new_feature
```
-## git-squash <src-branch> [msg]
+## git-squash <src-branch|commit ref> [msg]
-Merge commits from `src-branch` into the current branch as a _single_ commit. When `[msg]` is given `git-commit(1)` will be invoked with that message. This is useful when small individual commits within a topic branch are irrelevant and you want to consider the topic as a single change.
+Merge commits from `src-branch` into the current branch as a _single_ commit.
+Also works if a commit reference from the current branch is provided.
+When `[msg]` is given `git-commit(1)` will be invoked with that message. This is
+useful when small individual commits within a topic branch are irrelevant and
+you want to consider the topic as a single change.
```bash
$ git squash fixed-cursor-styling
$ git squash fixed-cursor-styling "Fixed cursor styling"
+$ git squash 95b7c52
+$ git squash HEAD~3
+$ git squash HEAD~3 "Work on a feature"
```
## git-changelog
View
@@ -1,38 +1,53 @@
-#!/bin/sh
+#!/bin/bash
-src=$1
-msg=$2
+src="$1"
+msg="$2"
-test -z $src && echo "source branch required, or use --me." && exit 1
+is_branch() {
+ git show-ref --verify --quiet "refs/heads/$src"
+}
-# squash current branch
-# TODO: do this in a less hacky way
-# TODO: less sketchy arguments
+is_commit_reference() {
+ git rev-parse --verify --quiet "$src" > /dev/null 2>&1
+}
-if [[ $1 == "--me" ]]; then
- msg=$3
- branch=`git rev-parse --abbrev-ref HEAD`
-
- # merge against target branch or master
- git checkout ${2-master}
-
- git checkout -B squash-tmp
- git squash $branch
- git branch -D $branch
- git checkout -B $branch
- git branch -D squash-tmp
+is_on_current_branch() {
+ local commit_sha=`git rev-parse "$src"`
+ git rev-list HEAD |
+ grep -q "$commit_sha"
+}
+commit_if_msg_provided() {
if test -n "$msg"; then
git commit -a -m "$msg"
fi
-
- exit
-fi
-
-# squash $src
-
-git merge --squash $src
-
-if test -n "$msg"; then
- git commit -a -m "$msg" && git branch -D $src
+}
+
+prompt_continuation_if_squashing_master() {
+ if [[ $src =~ ^master$ ]]; then
+ read -p "Warning: squashing '$src'! Continue [y/N]? " -r
+ if ! [[ $REPLY =~ ^[Yy]$ ]]; then
+ echo "Exiting"
+ exit 1
+ fi
+ fi
+}
+
+squash_branch() {
+ prompt_continuation_if_squashing_master
+ git merge --squash "$src" || exit 1 # quits if `git merge` fails
+ commit_if_msg_provided
+}
+
+squash_current_branch() {
+ git reset --soft "$src" || exit 1 # quits if `git reset` fails
+ commit_if_msg_provided
+}
+
+if `is_branch`; then
+ squash_branch
+elif `is_commit_reference` && `is_on_current_branch`; then
+ squash_current_branch
+else
+ echo "Source branch or commit reference required." 1>&2 && exit 1
fi
View
@@ -1,13 +1,13 @@
.\" generated with Ronn/v0.7.3
-.\" https://github.com/rtomayko/ronn/tree/0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "GIT\-SQUASH" "1" "July 2012" "" ""
+.TH "GIT\-SQUASH" "1" "July 2014" "" ""
.
.SH "NAME"
-\fBgit\-squash\fR \- Import changes from a branch
+\fBgit\-squash\fR \- Import changes form a branch
.
.SH "SYNOPSIS"
-\fBgit\-squash\fR <source\-branch> [<commit\-message>]
+\fBgit\-squash\fR <source\-branch|commit ref> [<commit\-message>]
.
.SH "DESCRIPTION"
Produce the working tree and index state as if a real merge happened without the commit or merge marks\.
@@ -19,6 +19,9 @@ Produce the working tree and index state as if a real merge happened without the
Branch to squash on the actual branch\.
.
.P
+<commit reference> A commit reference (has to be from the current branch) can also be used as the first argument\. A range of commits \fIsha\fR\.\.HEAD will be squashed\.
+.
+.P
<commit\-message>
.
.P
@@ -35,14 +38,16 @@ Squash commit \-\- not updating HEAD
my\-changed\-file | 1 +
1 file changed, 1 insertion(+)
$ git commit \-m "New commit without a real merge"
+
+$ git squash HEAD~3 "Commit message"
.
.fi
.
.SH "AUTHOR"
Written by Jesús Espino <\fIjespinog@gmail\.com\fR>
.
.SH "REPORTING BUGS"
-<\fIhttp://github\.com/visionmedia/git\-extras/issues\fR>
+<\fIhttps://github\.com/visionmedia/git\-extras/issues\fR>
.
.SH "SEE ALSO"
-<\fIhttp://github\.com/visionmedia/git\-extras\fR>
+<\fIhttps://github\.com/visionmedia/git\-extras\fR>
View
@@ -2,7 +2,7 @@
<html>
<head>
<meta http-equiv='content-type' value='text/html;charset=utf8'>
- <meta name='generator' value='Ronn/v0.7.3 (https://github.com/rtomayko/ronn/tree/0.7.3)'>
+ <meta name='generator' value='Ronn/v0.7.3 (http://github.com/rtomayko/ronn/tree/0.7.3)'>
<title>git-squash(1) - Import changes form a branch</title>
<style type='text/css' media='all'>
/* style: man */
@@ -76,7 +76,7 @@ <h2 id="NAME">NAME</h2>
<h2 id="SYNOPSIS">SYNOPSIS</h2>
-<p><code>git-squash</code> &lt;source-branch&gt; [&lt;commit-message&gt;]</p>
+<p><code>git-squash</code> &lt;source-branch|commit ref&gt; [&lt;commit-message&gt;]</p>
<h2 id="DESCRIPTION">DESCRIPTION</h2>
@@ -89,6 +89,10 @@ <h2 id="OPTIONS">OPTIONS</h2>
<p> Branch to squash on the actual branch.</p>
+<p> &lt;commit reference&gt;
+ A commit reference (has to be from the current branch) can also be used as the
+ first argument. A range of commits <var>sha</var>..HEAD will be squashed.</p>
+
<p> &lt;commit-message&gt;</p>
<p> If commit-message is given, commit the squash result and delete the source-branch.</p>
@@ -102,11 +106,13 @@ <h2 id="EXAMPLES">EXAMPLES</h2>
my-changed-file | 1 +
1 file changed, 1 insertion(+)
$ git commit -m "New commit without a real merge"
+
+$ git squash HEAD~3 "Commit message"
</code></pre>
<h2 id="AUTHOR">AUTHOR</h2>
-<p>Written by Jesús Espino &lt;<a href="&#109;&#x61;&#x69;&#x6c;&#116;&#111;&#x3a;&#106;&#101;&#115;&#112;&#x69;&#110;&#x6f;&#x67;&#64;&#103;&#x6d;&#x61;&#105;&#x6c;&#x2e;&#99;&#x6f;&#x6d;" data-bare-link="true">&#106;&#x65;&#115;&#112;&#105;&#110;&#x6f;&#x67;&#x40;&#103;&#109;&#x61;&#x69;&#108;&#x2e;&#99;&#x6f;&#x6d;</a>&gt;</p>
+<p>Written by Jesús Espino &lt;<a href="&#x6d;&#x61;&#x69;&#x6c;&#x74;&#x6f;&#58;&#106;&#x65;&#x73;&#112;&#x69;&#110;&#111;&#x67;&#64;&#103;&#109;&#x61;&#105;&#108;&#x2e;&#99;&#x6f;&#109;" data-bare-link="true">&#106;&#x65;&#115;&#112;&#105;&#x6e;&#x6f;&#x67;&#x40;&#103;&#109;&#97;&#105;&#108;&#x2e;&#x63;&#111;&#x6d;</a>&gt;</p>
<h2 id="REPORTING-BUGS">REPORTING BUGS</h2>
@@ -119,7 +125,7 @@ <h2 id="SEE-ALSO">SEE ALSO</h2>
<ol class='man-decor man-foot man foot'>
<li class='tl'></li>
- <li class='tc'>July 2012</li>
+ <li class='tc'>July 2014</li>
<li class='tr'>git-squash(1)</li>
</ol>
View
@@ -3,7 +3,7 @@ git-squash(1) -- Import changes form a branch
## SYNOPSIS
-`git-squash` &lt;source-branch&gt; [&lt;commit-message&gt;]
+`git-squash` &lt;source-branch|commit ref&gt; [&lt;commit-message&gt;]
## DESCRIPTION
@@ -16,6 +16,10 @@ git-squash(1) -- Import changes form a branch
Branch to squash on the actual branch.
+ &lt;commit reference&gt;
+ A commit reference (has to be from the current branch) can also be used as the
+ first argument. A range of commits <sha>..HEAD will be squashed.
+
&lt;commit-message&gt;
If commit-message is given, commit the squash result and delete the source-branch.
@@ -30,6 +34,8 @@ git-squash(1) -- Import changes form a branch
1 file changed, 1 insertion(+)
$ git commit -m "New commit without a real merge"
+ $ git squash HEAD~3 "Commit message"
+
## AUTHOR
Written by Jesús Espino &lt;<jespinog@gmail.com>&gt;

0 comments on commit b2576ad

Please sign in to comment.