git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[RFC/PATCH] Add git-squash tool and tests

From
Stephan Beyer <s-beyer@gmx.net>
Date
Jun 9, 2008, 20:29 UTC
Message-ID
<1213043398-30524-1-git-send-email-s-beyer@gmx.net>
In-Reply-To
<484D47C9.9050509@gnu.org>

git-squash is a simple command that, given the parent commit of X, squashes the commits X..HEAD into one.

Signed-off-by: Stephan Beyer <s-beyer@gmx.net>
---
Hi,
perhaps this is a little surprising, but because of:
> This could be done by providing a stand-alone git-squash command;
I thought it could be right to quickly write this as a script.
Here it is as RFC, yet without documentation.
Junio, this could be a backend for the zucchini instruction, by just
 zucchini <n>  =>  git-squash "HEAD~$(expr $n + 1)"   ;-)
 Makefile          |    1 +
 command-list.txt  |    1 +
 git-squash.sh     |   77 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 t/t3150-squash.sh |   66 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 145 insertions(+), 0 deletions(-)
 create mode 100755 git-squash.sh
 create mode 100755 t/t3150-squash.sh
diff --git a/Makefile b/Makefile
index 1937507..863004b 100644
--- a/Makefile
+++ b/Makefile
@@ -251,6 +251,7 @@ SCRIPT_SH += git-rebase.sh
 SCRIPT_SH += git-repack.sh
 SCRIPT_SH += git-request-pull.sh
 SCRIPT_SH += git-sh-setup.sh
+SCRIPT_SH += git-squash.sh
 SCRIPT_SH += git-stash.sh
 SCRIPT_SH += git-submodule.sh
 SCRIPT_SH += git-web--browse.sh
diff --git a/command-list.txt b/command-list.txt
index 3583a33..e342da3 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -108,6 +108,7 @@ git-show-branch                         ancillaryinterrogators
 git-show-index                          plumbinginterrogators
 git-show-ref                            plumbinginterrogators
 git-sh-setup                            purehelpers
+git-squash                              mainporcelain
 git-stash                               mainporcelain
 git-status                              mainporcelain common
 git-stripspace                          purehelpers
diff --git a/git-squash.sh b/git-squash.sh
new file mode 100755
index 0000000..64b5949
--- /dev/null
+++ b/git-squash.sh
@@ -0,0 +1,77 @@
+#!/bin/sh
+#
+# Squash commits from HEAD up to ... into one commit.
+
+SUBDIRECTORY_OK=Yes
+OPTIONS_KEEPDASHDASH=
+OPTIONS_SPEC="\
+git-squash [options] <commit-ish>
+--
+author=           use author <author>
+C,reuse-message=  use commit data from <commit-ish>
+F,file=           use commit message in <file>
+m,message=        use commit message <msg>
+e,edit            force edit of commit message
+s,signoff         add Signed-off-by:
+include-merges    don't fail if merge is in between
+"
+
+. git-sh-setup
+require_work_tree
+
+# test if working tree is clean
+git rev-parse --verify HEAD >/dev/null &&
+git update-index --refresh &&
+git diff-files --quiet &&
+git diff-index --cached --quiet HEAD -- ||
+	die "Working tree is dirty"
+
+git var GIT_COMMITTER_IDENT >/dev/null ||
+	die "You need to set your committer info first"
+
+HEAD=$(git rev-parse --verify HEAD) ||
+	die "No HEAD?"
+
+commitstr="git commit "
+merges=
+while test $# -gt 1
+do
+	case "$1" in
+	-m|-F|-C|--author)
+		commitstr="$commitstr $1 '$2'"
+		shift
+		;;
+	-e|-s)
+		commitstr="$commitstr $1"
+		;;
+	--include-merges)
+		merges=y
+		;;
+	--)
+		break
+		;;
+	esac
+	shift
+done
+
+test $# -gt 2 &&
+	die "Wrong number of arguments."
+test $# -lt 2 &&
+	die "No commit given."
+shift
+
+commit="$1"
+git rev-parse --verify "$commit" >/dev/null ||
+	die "$commit is no valid commit."
+
+# check for merges if no --include-merges given
+test -z "$merges" &&
+git log "$commit.." | grep -q "^Merge:" &&
+	die "$commit..HEAD contains a merge commit. You may try --include-merges."
+
+# reset and commit
+git reset --soft "$commit"
+eval "$commitstr" || {
+	git reset --hard $HEAD
+	die "Commit failed"
+}
diff --git a/t/t3150-squash.sh b/t/t3150-squash.sh
new file mode 100755
index 0000000..9f18995
--- /dev/null
+++ b/t/t3150-squash.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+
+test_description='git-squash'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+	: >file1 &&
+	: >file2 &&
+	: >file3 &&
+	: >file4 &&
+	: >file5 &&
+	: >file6 &&
+	git add file1 &&
+	git commit -m file1 &&
+	git add file2 &&
+	git commit -m file2 &&
+	git checkout -b master2 HEAD^ &&
+	git add file3 &&
+	git commit -m file3 &&
+	git checkout master &&
+	git merge master2 &&
+	git add file4 &&
+	git commit -m file4 &&
+	git add file5 &&
+	git commit -m file5 &&
+	git add file6 &&
+	git commit -m file6
+'
+
+test_expect_success 'git-squash HEAD^ is a nop and fails' '
+	git checkout -b first master &&
+	! git squash HEAD^ &&
+	test "$(git rev-parse HEAD)" = "$(git rev-parse first)" &&
+	test "$(git rev-parse master)" = "$(git rev-parse first)"
+'
+
+test_expect_success 'git-squash works' '
+	git checkout -b second master &&
+	git squash -m "file5 and file6" --signoff HEAD^^ &&
+	test "$(git rev-parse HEAD)" = "$(git rev-parse second)" &&
+	test -f file1 -a -f file2 -a -f file3 -a \
+	     -f file4 -a -f file5 -a -f file6
+'
+
+test_expect_success 'git-squash fails if merge in between' '
+	git checkout -b third master &&
+	! git squash -C master master2^ &&
+	test "$(git rev-parse HEAD)" = "$(git rev-parse third)" &&
+	test "$(git rev-parse master)" = "$(git rev-parse third)"
+'
+
+test_expect_success 'git-squash works with --include-merges if merge in between' '
+	git checkout -b fourth master &&
+	git squash -C master --include-merges master2^ &&
+	test "$(git rev-parse HEAD)" = "$(git rev-parse fourth)"
+'
+
+test_expect_success 'git-squash aborts correctly if no commit message given' '
+	git checkout -b fifth master &&
+	! git squash HEAD~2 &&
+	test "$(git rev-parse HEAD)" = "$(git rev-parse fifth)" &&
+	test "$(git rev-parse master)" = "$(git rev-parse fifth)"
+'
+
+test_done
-- 
1.5.5.3
Previous: Paolo BonziniNext: Johannes Schindelin
Message 8 of 41 in “[RFC] git-sequencer.txt”
  1. Stephan BeyerJun 7, 2008
  2. squashing patches (was: Re: [RFC] git-sequencer.txt)Stephan Beyer, Jun 9, 2008
  3. Johannes SchindelinJun 9, 2008
  4. Paolo BonziniJun 9, 2008
  5. Paolo BonziniJun 9, 2008
  6. Stephan BeyerJun 9, 2008
  7. Paolo BonziniJun 9, 2008
  8. Add git-squash tool and testsStephan Beyer, Jun 9, 2008
  9. Johannes SchindelinJun 9, 2008
  10. Paolo BonziniJun 9, 2008
  11. Johannes SchindelinJun 9, 2008
  12. Stephan BeyerJun 9, 2008
  13. Johannes SchindelinJun 10, 2008
  14. Stephan BeyerJun 9, 2008
  15. Junio C HamanoJun 9, 2008
  16. Stephan BeyerJun 9, 2008
  17. Jeff KingJun 9, 2008
  18. Stephan BeyerJun 9, 2008
  19. Jeff KingJun 10, 2008
  20. Junio C HamanoJun 9, 2008
  21. Stephan BeyerJun 10, 2008
  22. Jakub NarebskiJun 9, 2008
  23. Stephan BeyerJun 10, 2008
  24. Christian CouderJun 10, 2008
  25. Stephan BeyerJun 10, 2008
  26. Christian CouderJun 11, 2008
  27. Daniel BarkalowJun 11, 2008
  28. Jakub NarebskiJun 10, 2008
  29. [RFCv2/FYI] git-sequencer.txtStephan Beyer, Jun 12, 2008
  30. Paolo BonziniJun 12, 2008
  31. Stephan BeyerJun 12, 2008
  32. git-commit: Change --reuse-message to --reuse-commit.Stephan Beyer, Jun 12, 2008
  33. Paolo BonziniJun 12, 2008
  34. Junio C HamanoJun 12, 2008
  35. Stephan BeyerJun 12, 2008
  36. Paolo BonziniJun 13, 2008
  37. Stephan BeyerJun 13, 2008
  38. Paolo BonziniJun 13, 2008
  39. Olivier MarinJun 13, 2008
  40. Jakub NarebskiJun 12, 2008
  41. Stephan BeyerJun 12, 2008

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.