module Git::Repository::Stashing
Facade methods for stash operations
Each method maps onto a ‘git stash` subcommand. Methods that identify or create a stash entry ({#stash_list}, {#stash_push}, {#stash_store}) return {Git::StashInfo} values; methods that only change or display the stash return git’s stdout. Every method that takes a stash ({#stash_apply}, {#stash_pop}, {#stash_drop}, {#stash_show}, {#stash_branch}) accepts a {Git::StashInfo}, a ‘stash@{N}` name, an Integer index (`0` is the most recent entry), or `nil` for the most recent entry. Methods that take options accept them as a trailing positional Hash, so `repo.stash_apply(index: true)` and `repo.stash_apply(nil, opts)` with a stored `opts` Hash both work.
Included by {Git::Repository}.
@api private
Constants
- STASH_APPLY_ALLOWED_OPTS
-
Option keys accepted by {#stash_apply}
- STASH_DROP_ALLOWED_OPTS
-
Option keys accepted by {#stash_drop}
- STASH_POP_ALLOWED_OPTS
-
Option keys accepted by {#stash_pop}
- STASH_PUSH_ALLOWED_OPTS
-
Option keys accepted by {#stash_push}
- STASH_SHOW_ALLOWED_OPTS
-
Option keys accepted by {#stash_show}
- STASH_STORE_ALLOWED_OPTS
-
Option keys accepted by {#stash_store}
Public Instance Methods
Source
# File lib/git/repository/stashing.rb, line 191 def stash_apply(stash = nil, opts = {}) stash, opts = Private.split_stash_and_opts(stash, opts) SharedPrivate.assert_valid_opts!(STASH_APPLY_ALLOWED_OPTS, **opts) Git::Commands::Stash::Apply.new(@execution_context).call(stash, **opts).stdout end
Apply a stash entry to the working tree, keeping it in the stash list
@example Apply the most recent entry
repo.stash_apply #=> "On branch main\nChanges not staged for commit:..."
@example Apply an entry from {#stash_list}
repo.stash_apply(repo.stash_list.last)
@example Apply an entry by name and restore the index too
repo.stash_apply('stash@{1}', index: true)
@param stash [Git::StashInfo, String, Integer, nil] the entry to apply: a
{Git::StashInfo}, a `stash@{N}` name, an Integer `N` (`0` is the most
recent entry), or `nil` for the most recent entry
@param opts [Hash] options for the apply
@option opts [Boolean, nil] :index (nil) restore the index state as
well as the working tree
@option opts [Boolean, nil] :quiet (nil) suppress informational
messages (alias: `:q`)
@option opts [Boolean, nil] :q (nil) alias for ‘:quiet`
@return [String] git’s stdout from the apply
@raise [ArgumentError] if unsupported options are provided
@raise [Git::FailedError] if git exits with a non-zero exit status
@note If git exits non-zero, nothing is unwound: whatever git applied stays
in the working tree and index, including untracked files restored from the entry even when git refused to touch the tracked files, and on a conflict the conflicted paths are left for the caller to resolve.
@see git-scm.com/docs/git-stash git-stash documentation
Source
# File lib/git/repository/stashing.rb, line 388 def stash_branch(branch_name, stash = nil) Git::Commands::Stash::Branch.new(@execution_context).call(branch_name, stash).stdout end
Create and check out a branch from the commit a stash entry was based on
Applies the entry on the new branch and, when that succeeds, drops the entry from the stash list.
@example Branch from the most recent entry
repo.stash_branch('feature') #=> "Switched to a new branch 'feature'\n..."
@example Branch from an entry from {#stash_list}
repo.stash_branch('feature', repo.stash_list.last)
@param branch_name [String] the name of the branch to create
@param stash [Git::StashInfo, String, Integer, nil] the entry to branch
from: a {Git::StashInfo}, a `stash@{N}` name, an Integer `N` (`0` is the
most recent entry), or `nil` for the most recent entry
@return [String] git’s stdout from the branch command
@raise [Git::FailedError] if git exits with a non-zero exit status
@note If applying the entry fails, ‘branch_name` has already been created
and checked out, so the repository is left on it with whatever git could apply in the working tree, and the entry stays in the stash list.
@see git-scm.com/docs/git-stash git-stash documentation
Source
# File lib/git/repository/stashing.rb, line 507 def stash_clear Git::Commands::Stash::Clear.new(@execution_context).call.stdout end
Remove all stash entries
Removes all entries from the stash list. Use with caution as this operation cannot be undone.
@example Clear all stashes
repo.stash_clear #=> ""
@return [String] the output from the git stash clear command
(typically empty)
@raise [Git::FailedError] if git exits with a non-zero exit status
@see git-scm.com/docs/git-stash git-stash documentation
Source
# File lib/git/repository/stashing.rb, line 413 def stash_create(message = nil) oid = Git::Commands::Stash::Create.new(@execution_context).call(message).stdout.strip oid.empty? ? nil : oid end
Create a stash commit without adding it to the stash list
The working tree and index are left unchanged. Pass the returned object id to {#stash_store} to add it to the stash list later.
@example Create a stash commit
repo.stash_create('WIP') #=> "3f8b2d9c..." (the full object id)
@example Nothing to stash
repo.stash_create #=> nil
@param message [String, nil] the message for the stash commit; ‘nil` for
git's default message
@return [String, nil] the object id of the stash commit, or ‘nil` when
there were no local changes
@raise [Git::FailedError] if git exits with a non-zero exit status
@see git-scm.com/docs/git-stash git-stash documentation
Source
# File lib/git/repository/stashing.rb, line 272 def stash_drop(stash = nil, opts = {}) stash, opts = Private.split_stash_and_opts(stash, opts) SharedPrivate.assert_valid_opts!(STASH_DROP_ALLOWED_OPTS, **opts) Git::Commands::Stash::Drop.new(@execution_context).call(stash, **opts).stdout end
Remove a single stash entry from the stash list
@example Drop the most recent entry
repo.stash_drop #=> "Dropped refs/stash@{0} (abc1234...)"
@example Drop an entry from {#stash_list}
repo.stash_drop(repo.stash_list.last)
@param stash [Git::StashInfo, String, Integer, nil] the entry to drop: a
{Git::StashInfo}, a `stash@{N}` name, an Integer `N` (`0` is the most
recent entry), or `nil` for the most recent entry
@param opts [Hash] options for the drop
@option opts [Boolean, nil] :quiet (nil) suppress informational
messages (alias: `:q`)
@option opts [Boolean, nil] :q (nil) alias for ‘:quiet`
@return [String] git’s stdout from the drop
@raise [ArgumentError] if unsupported options are provided
@raise [Git::FailedError] if git exits with a non-zero exit status
@see git-scm.com/docs/git-stash git-stash documentation
Source
# File lib/git/repository/stashing.rb, line 46 def stash_list result = Git::Commands::Stash::List.new(@execution_context).call Git::Parsers::Stash.parse_list(result.stdout) end
Returns every stash entry as a {Git::StashInfo}, newest first
The order and indices match ‘git stash list`: the first element is `stash@{0}`, the most recent entry.
@example List stash entries (newest first)
repo.stash_list.map(&:name) #=> ["stash@{0}", "stash@{1}"]
@example Apply the oldest entry
repo.stash_apply(repo.stash_list.last)
@return [Array<Git::StashInfo>] the stash entries, newest first; empty
when there are none
@raise [Git::FailedError] if git exits with a non-zero exit status
@see git-scm.com/docs/git-stash git-stash documentation
Source
# File lib/git/repository/stashing.rb, line 235 def stash_pop(stash = nil, opts = {}) stash, opts = Private.split_stash_and_opts(stash, opts) SharedPrivate.assert_valid_opts!(STASH_POP_ALLOWED_OPTS, **opts) Git::Commands::Stash::Pop.new(@execution_context).call(stash, **opts).stdout end
Apply a stash entry to the working tree and remove it from the stash list
@example Pop the most recent entry
repo.stash_pop #=> "On branch main\n...Dropped refs/stash@{0} (abc1234...)"
@example Pop an entry from {#stash_list}
repo.stash_pop(repo.stash_list.last)
@param stash [Git::StashInfo, String, Integer, nil] the entry to pop: a
{Git::StashInfo}, a `stash@{N}` name, an Integer `N` (`0` is the most
recent entry), or `nil` for the most recent entry
@param opts [Hash] options for the pop
@option opts [Boolean, nil] :index (nil) restore the index state as
well as the working tree
@option opts [Boolean, nil] :quiet (nil) suppress informational
messages (alias: `:q`)
@option opts [Boolean, nil] :q (nil) alias for ‘:quiet`
@return [String] git’s stdout from the pop
@raise [ArgumentError] if unsupported options are provided
@raise [Git::FailedError] if git exits with a non-zero exit status
@note If git exits non-zero, nothing is unwound, as described at
{#stash_apply}, and the entry is kept in the stash list rather than
dropped.
@see git-scm.com/docs/git-stash git-stash documentation
Source
# File lib/git/repository/stashing.rb, line 140 def stash_push(*pathspec) pathspec, opts = Private.split_pathspec_and_opts(pathspec) SharedPrivate.assert_valid_opts!(STASH_PUSH_ALLOWED_OPTS, **opts) previous_count = stash_list.size Git::Commands::Stash::Push.new(@execution_context).call(*pathspec, **opts) entries = stash_list entries.first if entries.size > previous_count end
Save the working tree and index state to a new stash entry
The stash list is read before and after the push and the entry counts are compared, so the return value is ‘nil` whenever git created no entry. This holds with `quiet: true`, which suppresses git’s “No local changes to save” message.
@overload stash_push(*pathspec, options = {})
@example Stash all changes with a message
info = repo.stash_push(message: 'WIP: feature work')
info.name #=> "stash@{0}"
info.message #=> "On main: WIP: feature work"
@example Stash only specific paths
repo.stash_push('src/a.rb', 'src/b.rb', message: 'partial work')
@example Nothing to stash
repo.stash_push #=> nil
@param pathspec [Array<String>] paths that limit what gets stashed; when
empty, all changes are stashed
@param options [Hash] options for the push
@option options [Boolean, nil] :patch (nil) interactively select hunks to
stash (alias: `:p`)
@option options [Boolean, nil] :p (nil) alias for `:patch`
@option options [Boolean, nil] :staged (nil) stash only the staged changes
(alias: `:S`)
@option options [Boolean, nil] :S (nil) alias for `:staged`
@option options [Boolean, nil] :keep_index (nil) keep the staged changes
in the index (alias: `:k`)
@option options [Boolean, nil] :k (nil) alias for `:keep_index`
@option options [Boolean, nil] :no_keep_index (nil) do not keep the staged
changes in the index
@option options [Boolean, nil] :quiet (nil) suppress informational
messages (alias: `:q`)
@option options [Boolean, nil] :q (nil) alias for `:quiet`
@option options [Boolean, nil] :include_untracked (nil) include untracked
files in the stash (alias: `:u`)
@option options [Boolean, nil] :u (nil) alias for `:include_untracked`
@option options [Boolean, nil] :all (nil) include untracked and ignored
files in the stash (alias: `:a`)
@option options [Boolean, nil] :a (nil) alias for `:all`
@option options [String] :message (nil) the stash message (alias: `:m`)
@option options [String] :m (nil) alias for `:message`
@option options [String] :pathspec_from_file (nil) read pathspecs from the
given file; pass `-` to read from standard input
@option options [Boolean, nil] :pathspec_file_nul (nil) when used with
`:pathspec_from_file`, pathspecs are NUL-separated
@return [Git::StashInfo, nil] the new entry, or `nil` when there were no
local changes to save
@raise [ArgumentError] if unsupported options are provided
@raise [Git::FailedError] if git exits with a non-zero exit status
@see git-scm.com/docs/git-stash git-stash documentation
Source
# File lib/git/repository/stashing.rb, line 355 def stash_show(stash = nil, opts = {}) stash, opts = Private.split_stash_and_opts(stash, opts) SharedPrivate.assert_valid_opts!(STASH_SHOW_ALLOWED_OPTS, **opts) Git::Commands::Stash::Show.new(@execution_context).call(stash, **opts).stdout end
Show the changes recorded in a stash entry as a diff
Without options, git prints a diffstat. The output is returned as git prints it.
@example Show the diffstat of the most recent entry
repo.stash_show #=> " file.txt | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)"
@example Show the full patch of an entry from {#stash_list}
repo.stash_show(repo.stash_list.last, patch: true)
@param stash [Git::StashInfo, String, Integer, nil] the entry to show: a
{Git::StashInfo}, a `stash@{N}` name, an Integer `N` (`0` is the most
recent entry), or `nil` for the most recent entry
@param opts [Hash] options for the show
@option opts [Boolean, nil] :patch (nil) show the diff as a patch
@option opts [Boolean, nil] :numstat (nil) show per-file insertion and
deletion counts
@option opts [Boolean, nil] :raw (nil) show per-file mode, object id,
and status metadata
@option opts [Boolean, nil] :shortstat (nil) show only the summary line
@option opts [Integer, String] :unified (nil) number of context lines
in the patch (alias: `:U`)
@option opts [Integer, String] :U (nil) alias for ‘:unified`
@option opts [Boolean, nil] :include_untracked (nil) include the
untracked files recorded in the entry (alias: `:u`)
@option opts [Boolean, nil] :u (nil) alias for ‘:include_untracked`
@option opts [Boolean, nil] :no_include_untracked (nil) exclude the
untracked files recorded in the entry
@option opts [Boolean, nil] :only_untracked (nil) show only the
untracked files recorded in the entry
@option opts [Boolean, Integer, nil] :find_renames (nil) detect
renames, optionally with a similarity threshold (alias: `:M`)
@option opts [Boolean, Integer, nil] :M (nil) alias for ‘:find_renames`
@option opts [Boolean, Integer, nil] :find_copies (nil) detect copies
as well as renames, optionally with a similarity threshold (alias: `:C`)
@option opts [Boolean, Integer, nil] :C (nil) alias for ‘:find_copies`
@option opts [Boolean, nil] :find_copies_harder (nil) inspect unmodified
files as copy sources
@option opts [Integer, String] :inter_hunk_context (nil) number of
context lines between hunks before they are merged
@option opts [Boolean, String, nil] :dirstat (nil) include directory
statistics, optionally with parameters
@return [String] git’s stdout from the show
@raise [ArgumentError] if unsupported options are provided
@raise [Git::FailedError] if git exits with a non-zero exit status
@see git-scm.com/docs/git-stash git-stash documentation
Source
# File lib/git/repository/stashing.rb, line 484 def stash_store(commit, opts = {}) SharedPrivate.assert_valid_opts!(STASH_STORE_ALLOWED_OPTS, **opts) oid = Private.resolve_commit_oid(@execution_context, commit) Git::Commands::Stash::Store.new(@execution_context).call(oid, **opts) stash_list.find { |entry| entry.oid == oid } || raise(Git::UnexpectedResultError, "stash was stored but not found in the stash list: #{oid}") end
Add a stash commit created by {#stash_create} to the stash list
‘commit` is resolved to the full object id of the commit with `git rev-parse` and that id is what is stored, so an annotated tag stores the tagged commit rather than the tag object (which `git stash store` accepts but `git stash list` cannot show). Because the id is what git sees, a failure from `git stash store` names the resolved id rather than the revision as it was given. The stash list is read after the store and the entry whose object id equals that id is returned.
@example Store a stash commit
oid = repo.stash_create info = repo.stash_store(oid, message: 'saved for later') info.name #=> "stash@{0}" info.message #=> "saved for later"
@example Store a stash commit named by a ref
repo.stash_store('refs/tmp/wip').oid #=> "9b9b31e704c0b85ffdd8d2af2ded85170a5af87d"
@param commit [String, to_s] the stash commit to store, as any revision
that resolves to it
Full or abbreviated object ids, branch, tag, and other ref names,
`stash@{N}`, and `:/<text>` searches all resolve with `git rev-parse`,
and a {Git::StashInfo} resolves through its `#to_s`. A `:/<text>` search
finds only commits reachable from a ref, so it cannot name a commit from
{#stash_create} until that commit is stored or a ref points at it.
@param opts [Hash] options for the store
@option opts [String] :message (nil) the message for the stash entry
(alias: `:m`)
@option opts [String] :m (nil) alias for ‘:message`
@option opts [Boolean, nil] :quiet (nil) suppress informational
messages (alias: `:q`)
@option opts [Boolean, nil] :q (nil) alias for ‘:quiet`
@return [Git::StashInfo] the stored entry
@raise [ArgumentError] if unsupported options are provided
@raise [ArgumentError] if ‘commit` is `nil` or starts with a hyphen or a
caret
@raise [Git::FailedError] if git exits with a non-zero exit status
@raise [Git::UnexpectedResultError] if the stash listing cannot be parsed
or does not contain the stored commit The entry is missing when another process dropped or cleared it between the store and the lookup.
@note Storing the commit that is already at the top of the stash list
adds no entry: `git stash store` writes nothing to the `refs/stash` reflog, any `:message` given is discarded, and the existing top entry is returned.
@see git-scm.com/docs/git-stash git-stash documentation