From: Jon Seymour <jon.seymour@gmail.com>
To: git@vger.kernel.org
Cc: Jon Seymour <jon.seymour@gmail.com>
Subject: [PATCH 21/23] Introduce git-atomic.
Date: Sat, 23 Apr 2011 17:22:50 +1000 [thread overview]
Message-ID: <1303543372-77843-22-git-send-email-jon.seymour@gmail.com> (raw)
In-Reply-To: <1303543372-77843-1-git-send-email-jon.seymour@gmail.com>
git atomic is intended to provide a simple way to for porcelains to
execute atomic operations on the git repository.
An atomic operation either completes successfully or the
working tree, index and selected references are returned to their
original state.
Signed-off-by: Jon Seymour <jon.seymour@gmail.com>
---
.gitignore | 2 +
Documentation/git-atomic.txt | 92 ++++++++++++++++++++++++++++++++++++++++++
Makefile | 2 +
git-atomic-lib.sh | 58 ++++++++++++++++++++++++++
git-atomic.sh | 5 ++
t/t3419-atomic.sh | 59 +++++++++++++++++++++++++++
6 files changed, 218 insertions(+), 0 deletions(-)
create mode 100644 Documentation/git-atomic.txt
create mode 100644 git-atomic-lib.sh
create mode 100755 git-atomic.sh
create mode 100755 t/t3419-atomic.sh
diff --git a/.gitignore b/.gitignore
index aa0eb8fb..5efc43c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,8 @@
/git-apply
/git-archimport
/git-archive
+/git-atomic
+/git-atomic-lib
/git-bisect
/git-bisect--helper
/git-blame
diff --git a/Documentation/git-atomic.txt b/Documentation/git-atomic.txt
new file mode 100644
index 0000000..02bbee6
--- /dev/null
+++ b/Documentation/git-atomic.txt
@@ -0,0 +1,92 @@
+git-atomic(1)
+===========
+
+NAME
+----
+git-atomic - conditionally execute a command and, if it fails, restore the working tree, index and HEAD to their original state.
+
+SYNOPSIS
+--------
+[verse]
+'git atomic' [options] [--] [cmd args...]
+. $(git --exec-path)/git-atomic-lib.sh
+
+DESCRIPTION
+-----------
+The first form conditionally executes a command depending on whether the pre-conditions are satisified. If the command exits with a non-zero exit code, restores the
+working tree, index and HEAD to their orignal state. If no command is specified, sets the exit code according to the pre-conditions.
+
+'git atomic' exits with:
+
+0::
+ if the pre-conditions are satisified and the command executes successfully
+128::
+ if the command exited with an exit code of 128, 129, 130 or 131.
+129::
+ if git atomic failed during setup or argument parsing
+130::
+ if the pre-conditions were not satisified.
+131::
+ if the command failed and the original state could not be restored.
+
+Otherwise, exits with the actual exit code of the command.
+
+The second form is used to import the definition of a shell function called atomic that can be called by shell scripts that perform git operations. This is useful when the operations to be given atomic behaviour are themselves shell functions rather than external commands.
+
+OPTIONS
+-------
+The following options specify pre-condition tests on various lists which are assumed to be empty in the clean state and non-empty in the dirty state.
+
+The default required state for each specified pre-condition option is clean. The default required state for each unspecified pre-condition option is any, which
+means no tests are applied.
+
+--unstaged [any|clean|dirty]::
+ Fail unless the list of unstaged changes is empty (clean) or non-empty (dirty).
+--staged [any|clean|dirty]::
+ Fail unless the list of staged changes is empty (clean) or non-empty (dirty).
+--untracked [any|clean|dirty]::
+ Fail unless the list of untracked files is empty (clean) or non-empty (dirty).
+--tracked [any|clean|dirty]::
+ Fail unless the list of staged and unstaged changes is empty (clean) or non-empty (dirty).
+--unmerged [any|clean|dirty]::
+ Fail unless the list of unmerged files is empty (clean) or non-empty (dirty).
+--rebase [any|clean|dirty]::
+ Fail unless a rebase is not (clean) or is (dirty) in progress.
+--all::
+ Fail unless the list of staged, unstaged changes and untracked files is empty (clean) or non-empty (dirty)
+
+EXAMPLES
+--------
+* Reset the tree only if there are no staged or unstaged changes and no untracked files.
++
+-----------
+git atomic --all clean git reset --hard upstream/master
+-----------
+* Conditionally perform a merge, but rollback and die if it fails.
++
+-----------
+git atomic --all clean git merge topic || die "unable to merge"
+-----------
+* Import git-atomic-lib.sh into a script and make the execution of the function foo atomic with respect to the state of the git workspace
++
+-----------
+. $(git --exec-path)/git-atomic-lib.sh
+foo()
+{
+ git merge $1
+}
+
+atomic foo $1
+-----------
+
+Author
+------
+Written by Jon Seymour <jon.seymour@gmail.com>
+
+Documentation
+-------------
+Documentation by Jon Seymour
+
+GIT
+---
+Part of the linkgit:git[7] suite
diff --git a/Makefile b/Makefile
index 93ff6c6..9ed877a 100644
--- a/Makefile
+++ b/Makefile
@@ -360,6 +360,7 @@ TEST_PROGRAMS_NEED_X =
unexport CDPATH
SCRIPT_SH += git-am.sh
+SCRIPT_SH += git-atomic.sh
SCRIPT_SH += git-bisect.sh
SCRIPT_SH += git-difftool--helper.sh
SCRIPT_SH += git-filter-branch.sh
@@ -379,6 +380,7 @@ SCRIPT_SH += git-submodule.sh
SCRIPT_SH += git-test.sh
SCRIPT_SH += git-web--browse.sh
+SCRIPT_LIB += git-atomic-lib
SCRIPT_LIB += git-conditions-lib
SCRIPT_LIB += git-mergetool--lib
SCRIPT_LIB += git-parse-remote
diff --git a/git-atomic-lib.sh b/git-atomic-lib.sh
new file mode 100644
index 0000000..db48300
--- /dev/null
+++ b/git-atomic-lib.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+#
+# Provides a function that provides for robust recovery from
+#
+. git-test-lib
+atomic()
+{
+ assert --not-conflicted --message "cannot perform an atomic operation while there are merge conflicts"
+ HEAD=$(git rev-parse --verify HEAD) || setup_failed "failed to resolve HEAD"
+ if REF=$(git symbolic-ref -q HEAD)
+ then
+ BRANCH=${REF#refs/heads/}
+ else
+ BRANCH=${HEAD}
+ fi
+
+ STASH=$(git stash create) || setup_failed "failed to stash"
+ REF=$(git rev-parse --symbolic-full-name HEAD) || setup_failed "failed to acquire REF"
+ REBASE_COUNT=1
+ test_condition -q --rebasing || REBASE_COUNT=0
+
+ (
+ "$@"
+ ) || (
+ RC=$?
+
+ command_failed()
+ {
+ rc=$1
+ shift
+ echo "command failed: $* rc=$rc" 1>&2
+ exit 1
+ }
+
+ restore_failed()
+ {
+ echo "restore failed: $*" 1>&2
+ exit 2
+ }
+
+ if test $REBASE_COUNT -eq 0 && test -d "$REBASE_DIR"
+ then
+ git rebase --abort || restore_failed "failed to abort rebase"
+ fi
+
+ {
+ git reset --hard HEAD &&
+ git checkout -q ${BRANCH}
+ } || restore_failed "failed to checkout ${BRANCH}"
+
+ if test -n "$STASH"
+ then
+ git stash apply --index "$STASH" || restore_failed "failed to reapply stash $STASH to $HEAD"
+ echo "restored $REF to $(git describe --always --abbrev=6 $HEAD), reapplied stash $(git describe --always --abbrev=6 $STASH)" 1>&2
+ fi
+ command_failed $RC "$*"
+ )
+}
diff --git a/git-atomic.sh b/git-atomic.sh
new file mode 100755
index 0000000..aa14e68
--- /dev/null
+++ b/git-atomic.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+SUBDIRECTORY_OK=true
+. git-sh-setup
+. git-atomic-lib
+atomic "$@"
diff --git a/t/t3419-atomic.sh b/t/t3419-atomic.sh
new file mode 100755
index 0000000..2b651d2
--- /dev/null
+++ b/t/t3419-atomic.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+#
+# Copyright (c) 2010 Jon Seymour
+#
+
+test_description='git atomic tests
+
+Performs tests on the functions of git atomic
+'
+. ./test-lib.sh
+
+GIT_AUTHOR_NAME=author@name
+GIT_AUTHOR_EMAIL=bogus@email@address
+export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL
+
+test_expect_success \
+ 'setup' \
+ '
+ test_commit A &&
+ test_commit B &&
+ test_commit C &&
+ test_commit D &&
+ git checkout -b branch A &&
+ test_commit X &&
+ echo >> B.t &&
+ git add B.t &&
+ test_commit Y
+ true
+'
+
+test_expect_success 'no arguments' '
+ git atomic
+'
+
+test_expect_success 'successful command' \
+'
+ git atomic true
+'
+
+test_expect_success 'unsuccessful command' \
+'
+ ! git atomic false
+'
+
+test_expect_success 'rebase' \
+'
+ git reset --hard HEAD &&
+ git checkout master &&
+ MASTER=$(git rev-parse HEAD) &&
+ ! git rebase --onto D A Y &&
+ git test --conflicted &&
+ git rebase --abort &&
+ git checkout master &&
+ ! git atomic git rebase --onto D A Y &&
+ git test --same HEAD refs/heads/master &&
+ git test --same HEAD $MASTER
+'
+
+test_done
--
1.7.5.rc1.23.g7f622
next prev parent reply other threads:[~2011-04-23 7:25 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-04-23 7:22 [PATCH 00/23] RFC: Introducing git-test, git-atomic, git-base and git-work Jon Seymour
2011-04-23 7:22 ` [PATCH 01/23] Introduce git-test.sh and git-test-lib.sh Jon Seymour
2011-04-27 19:11 ` Drew Northup
2011-04-23 7:22 ` [PATCH 02/23] Introduce --unstaged Jon Seymour
2011-04-23 7:22 ` [PATCH 03/23] Introduce --staged Jon Seymour
2011-04-23 7:22 ` [PATCH 04/23] Introduce --untracked Jon Seymour
2011-04-23 7:22 ` [PATCH 05/23] Introduce --conflicted Jon Seymour
2011-04-23 7:22 ` [PATCH 06/23] Introduce --rebasing Jon Seymour
2011-04-23 7:22 ` [PATCH 07/23] Introduce --detached Jon Seymour
2011-04-23 7:22 ` [PATCH 08/23] Introduce --branch-exists Jon Seymour
2011-04-23 7:22 ` [PATCH 09/23] Introduce --tag-exists Jon Seymour
2011-04-23 7:22 ` [PATCH 10/23] Introduce --ref-exists Jon Seymour
2011-04-23 7:22 ` [PATCH 11/23] Introduce --commit-exists Jon Seymour
2011-04-23 7:22 ` [PATCH 12/23] Introduce --checked-out Jon Seymour
2011-04-23 7:22 ` [PATCH 13/23] Introduce --reachable Jon Seymour
2011-04-23 7:22 ` [PATCH 14/23] Introduce --tree-same Jon Seymour
2011-04-23 7:22 ` [PATCH 15/23] Introduce --same Jon Seymour
2011-04-23 7:22 ` [PATCH 16/23] misc Jon Seymour
2011-04-23 7:22 ` [PATCH 17/23] whitespace fix Jon Seymour
2011-04-23 7:22 ` [PATCH 18/23] tests --conflicted Jon Seymour
2011-04-23 7:22 ` [PATCH 19/23] rebasing: add tests Jon Seymour
2011-04-23 7:22 ` [PATCH 20/23] test: git test cleanups Jon Seymour
2011-04-23 7:22 ` Jon Seymour [this message]
2011-04-23 7:22 ` [PATCH 22/23] Introduce git base Jon Seymour
2011-04-23 7:22 ` [PATCH 23/23] Introduce support for the git-work command Jon Seymour
2011-04-23 9:13 ` [PATCH 00/23] RFC: Introducing git-test, git-atomic, git-base and git-work Peter Baumann
2011-04-23 17:16 ` Jon Seymour
2011-04-23 18:37 ` Jon Seymour
2011-04-24 15:47 ` Jon Seymour
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1303543372-77843-22-git-send-email-jon.seymour@gmail.com \
--to=jon.seymour@gmail.com \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).