git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Re: [RFC] New command: 'git snapshot'.
@ 2009-02-10 23:58 Ulrik Sverdrup
  2009-02-11  0:05 ` Ulrik Sverdrup
  2009-02-11  0:08 ` [RFC/PATCH] shortstatus v1 Nanako Shiraishi
  0 siblings, 2 replies; 19+ messages in thread
From: Ulrik Sverdrup @ 2009-02-10 23:58 UTC (permalink / raw)
  To: git; +Cc: Geoffrey Lee

> On Tue, Feb 10, 2009 at 3:08 PM, Junio C Hamano <gitster@pobox.com> wrote:
> > Jeff King <peff@peff.net> writes:
> > How is it different from "git stash create"?
>
> Git stash doesn't touch untracked files, whereas git snapshot would.
> Take another closer look at the table in the original post titled
> "What are the differences between 'git stash' and 'git snapshot'?"
>
> -Geoffrey Lee

I'm understanding this just as I read this, but it seems that implementing a
git snapshot (I'm myself interested), could be done quickly with a new git.
(When was git stash create introduced? I don't know it?)

Something like this:
cp .git/index .git/tmp-index
GIT_INDEX_FILE=.git/tmp-index
git add -N .
git stash create

So we use add -N to put all files into tracked but unstaged by default, but we
keep our old index. Now stash is ready to save off the working directory, and
further logic has to be applied on the returned commit to save it off..


Ulrik Sverdrup

^ permalink raw reply	[flat|nested] 19+ messages in thread
* [RFC] New command: 'git snapshot'.
@ 2009-02-09 18:54 Fabio Augusto Dal Castel
  2009-02-09 19:52 ` Giuseppe Bilotta
  2009-02-09 22:36 ` Brandon Casey
  0 siblings, 2 replies; 19+ messages in thread
From: Fabio Augusto Dal Castel @ 2009-02-09 18:54 UTC (permalink / raw)
  To: git

Abstract: Requesting suggestions for a new command to save the current
working dir state without collateral effects.


Q. "Why another command? We already have stash!"

A. Stash was always subject of many controversies. Trying to stay
apart from near-religious debates like

* whether the syntax should be "dangerous" [sic] or "newbie friendly";
* whether untracked files should be stashed or not;
* whether stashes should expire or not

the fact is that different users have different needs and those
discussions arise when trying to apply different behaviors to same
command. Stash was always oriented to a 'pull into a dirty tree'
solution, and serves this purpose very well.

So, I propose a new 'git snapshot' command to use when 'git stash'
behaviour is not exactly what user needs.


Q. Why on earth would someone want this instead of our lovely stash?

A. Sometimes what we want is just a (you bet) "snapshot" of working
dir. Something like "Just remember. Do not touch."

In the excellent paper "Git From the Bottom Up" John Wiegley suggests
a "git-snapshot" script to be used in a cron job -- nothing more than:

git stash && git stash apply

However, this is not an optimal solution for a 'real' snapshot:

* It makes TWO unnecessary changes to working dir (to HEAD and back
again). Besides the heavier disk usage, this could, for example,
cause an editor using inotify to think that the current file was
externally changed by another program and annoy the user asking if he
wants to load the new content.

* It will not save untracked files. An user counting with periodic
snapshots and working furiously for three days may be disappointed (to
say the least) when discover that a significant part of his work were
NOT saved in history because contents actually were in new (untracked)
files.

* Stashes expire (already discussed in
http://thread.gmane.org/gmane.comp.version-control.git/84665 )

In resume, all that 'git snapshot' would NOT do.


Q. What are the differences between 'git stash' and 'git snapshot'?

A.

git stash                         git snapshot

temporary/short-term              permanent/long-term
reflog-based                      branch-based
applies a "git reset --hard"      leaves working dir / index untouched
does not stash untracked files    snapshots ALL files (except ignored)


Q. How it works?

A.[What follows is a textual description of my current implementation.
Of course, there is nothing carved in stone: suggestions and comments
are MORE than welcome.]

All snapshots are stored in a special branch ("<branch>_snapshots").
So, if you are on 'master' branch, a 'git snapshot' will create/use a
'master_snapshots' branch.

If anything differs from last snapshot (a change into index, into a
file, or a new untracked file) the command will:

1. Save the current index state;
2. Add untracked/updated files to index;
3. Create a new commit for the current state in snapshots branch;
4. Update the HEAD of snapshots branch to this new commit;
5. Restore the original index state (of step 1).

However, if the current state of working dir is equal to the last
snapshot taken, there is no need to make another identical copy and
the command will just exit.

The command would not work if the current branch is a detached head.
It is by design, but just because I had a no better idea of what to do
in this case <g>.

Typical usage:

	(hack hack hack)
	git-snapshot
	(hack hack hack)
	git-snapshot
	(...)

Open questions / To-do list:

- How to 'rollback' to a specific snapshot?
  - Make a 'git-rollback <snapshot>' ? It would:
   - Apply diffs between <snapshot> and current head (possible loss!).
   - Restore the original index (where to save it? 'Hidden' commit?)


Best Regards,

Fabio.





diff --git a/git-snapshot.sh b/git-snapshot.sh
new file mode 100644
index 0000000..5f19a6f
--- /dev/null
+++ b/git-snapshot.sh
@@ -0,0 +1,61 @@
+#!/bin/sh
+#
+# Copyright (c) 2009 F.D.Castel.
+#
+
+. git-sh-setup
+require_work_tree
+cd_to_toplevel
+
+# Get current branch.
+current_branch=$(git symbolic-ref -q HEAD | sed -e 's|^refs/heads/||')
+test -z "$current_branch" &&
+	die 'fatal: Cannot take snapshot from a detached HEAD.'
+	
+# Save the current index state.
+original_index=$(git write-tree) ||
+	die "fatal: Error saving original index state."
+
+# Create commit message describing the changes.
+temp_file="$TMP/.git-snapshot"
+(
+	date -R
+	printf '\n* New files:\n'		# ToDo: How to get only untracked? (without added)
+	git ls-files --full-name -o
+	printf '\n* Changed files:\n'
+	git ls-files --full-name -m		# ToDo: How to get only modified?
(without deleted)
+	printf '\n* Deleted files:\n'
+	git ls-files --full-name -d
+) > "${temp_file}.message"
+
+# Add untracked/updated files to index.
+git add --all . ||
+	die "fatal: Error adding current state to index."
+
+# Set clean up trap (restore original index and delete temp files on exit).
+trap "git read-tree $original_index && rm -f '$temp_file.*'" 0
+
+# Create snapshots branch (if needed).
+snapshots_branch="${current_branch}_snapshots"
+git show-ref --verify --quiet -- "refs/heads/$snapshots_branch" ||
+	git branch $snapshots_branch
+
+# Compare changes with last snapshot.
+git diff --exit-code --raw --cached $snapshots_branch &&
+	die 'Nothing to do: no changes since the last snapshot.'
+
+# Create a new commit for the current state in snapshots branch.
+new_index=$(git write-tree) &&
+	snapshots_head=$(git rev-parse --verify $snapshots_branch) &&
+	new_commit=$(cat ${temp_file}.message | git commit-tree $new_index
-p $snapshots_head) ||
+		die "fatal: Error commiting current state into snapshots branch."
+
+# ToDo: Where to store the original index (for a future 'rollback')?
+#original_index_commit=$(printf '(original index for child commit)' |
git commit-tree $original_index)
+
+# Update the HEAD of snapshots branch to this new commit.
+git symbolic-ref HEAD refs/heads/$snapshots_branch &&
+	git update-ref -m "'Snapshotting $current_branch to $new_commit'"
HEAD $new_commit $snapshots_head &&
+	git symbolic-ref HEAD refs/heads/$current_branch ||
+		die "fatal: Error updating HEAD of snapshots branch."
+		
\ No newline at end of file

^ permalink raw reply related	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2009-02-11 20:42 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-02-10 23:58 [RFC] New command: 'git snapshot' Ulrik Sverdrup
2009-02-11  0:05 ` Ulrik Sverdrup
2009-02-11  0:08 ` [RFC/PATCH] shortstatus v1 Nanako Shiraishi
  -- strict thread matches above, loose matches on Subject: below --
2009-02-09 18:54 [RFC] New command: 'git snapshot' Fabio Augusto Dal Castel
2009-02-09 19:52 ` Giuseppe Bilotta
     [not found]   ` <38cfbb550902101232l4c83b6dfjc70e1e2f79a8c3c1@mail.gmail.com>
2009-02-10 20:48     ` Fabio Augusto Dal Castel
2009-02-09 22:36 ` Brandon Casey
2009-02-10  4:51   ` Sitaram Chamarty
2009-02-10 19:47     ` Jon Loeliger
2009-02-10 20:31       ` Junio C Hamano
2009-02-11  1:22       ` Sitaram Chamarty
2009-02-10 20:40   ` Fabio Augusto Dal Castel
2009-02-10 23:00     ` Jeff King
2009-02-10 23:08       ` Junio C Hamano
2009-02-10 23:38         ` Jeff King
2009-02-10 23:39         ` Geoffrey Lee
2009-02-11 13:43           ` Jeff King
2009-02-11  9:04       ` Matthieu Moy
2009-02-11 20:40         ` Fabio Augusto Dal Castel

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).