2

I am working on an interactive git tutorial that a user learns how to use git by following a series of instructions and operating a real git repository. To prevent the learner from ruining the repository or taking wrong steps (and causing the tutorial cannot be continued), I am thinking of taking snapshots of the state of the repository (refs, index, and HEAD etc.) betweeen every few steps and reset to the last one when something unexpected happens.

As taking snapshots of a repo sounds like doing some sort of version control for the .git folder to me, I am wondering if it is possible to use any version control tool to do the work?

I have tried to put a git repo inside another git repo, and set the .gitignore of the parent repo to include .git folder of the child, but there is no luck. git status does not show .git as untracked directory.

Would be glad to hear any idea that can help me taking snapshots of the .git folder or tricks to preserve status of a git repo and apply it back later.

edit 1

Tried git add -f to force add the .git folder, but git refused to add it and threw an error message.

Fortunately, another really dumb trick works. Renaming .git to any other name would be good enough to trick git to treat it as a normal folder. It is an acceptable solution to me, but not perfect, though.

That being said, since @ErikMD mentioned that my attempts to preserver git repository state via copying .git does not seem feasible at first sight, I am wondering if I have overlooked something critical? Would there be any problem to keep snapshots of a git repository by managing .git with a version control toll?

YAC
  • 405
  • 4
  • 14

1 Answers1

0

Your "workaround" does not seem feasible at first sight (If you try to commit a .git subfolder contained in a parent git repo, you will get some kind of (broken) git-submodule...)

To be more precise: Git is not designed to track the low-level contents of .git folders as regular files. Instead, Git allows to combine several repositories (several subfolders containing themselves a .git subfolder) in a root repository. This corresponds to the so-called git submodule feature. But setting up a submodule correctly requires using dedicated commands, which in turn also updates a special file .gitmodules. Hence what I had said earlier that you might obtain a "broken git-submodule layout" if you don't follow the normal workflow. Actually, the use of git-submodules is rather heavy and cumbersome in practice, compared to more recent features such as git subtree.

However I think you could achieve what you want (facilitate the recovery of the repo for an automatic tutorial system) by relying on git reflog or related commands to restore=overwrite the history, index, and working directory (the 3 mains parts of a repository) as well as branches and tags…

To exemplify my suggestion, assuming we only deal with one branch:

  1. The "state" of the current active branch (HEAD) can be identified by the corresponding SHA1:

    $ git rev-parse --verify HEAD
    0ed45a5994bceea7c6b1d6530c72cd9ce29a46af  # for example
    
  2. Suppose the user did a wrong step:

    $ git add UnwantedFile && git commit -m "Unwanted commit"
      # or
    $ git reset --hard HEAD~3  # remove 3 commits by mistake
    

    (and you notice it using appropriate commands)

  3. Then you can restore the state of the working dir. + index + current branch by doing:

    $ git reset --hard 0ed45a5994bceea7c6b1d6530c72cd9ce29a46af
    

    (or if ever the step 1 had not been performed at first to remember the previous state, the reflog could give the required hint):

    $ git reflog
    d62277c84 HEAD@{0}: reset: moving to HEAD~3
    0ed45a599 HEAD@{1}: checkout: moving from master to V8.8.2
    …
    $ git reset --hard HEAD@{1}
    

To conclude, I only see three ways to achieve what you want:

  1. Use manual rsync or bash hacks to overwrite the repo if you want to rollback it, but this is maybe not very satisfactory;
  2. Use standard commands such as git reset, git branch, git checkout or git tag… (depending on the focus of the tutorial you are working on) to reset the repo accordingly;
  3. Or use a local remote (or a local clone, in one way or the other) with appropriate commands such as git push --mirror or git pull/git fetch?
ErikMD
  • 13,377
  • 3
  • 35
  • 71
  • Thanks for your idea. This approach is similar to what I thought in the first place. Tracking key information such as current branch location and use it to reset when necessary, simple and clean. However, I plan to teach branch merging in the tutorial so there would be plenty branches in the repository. Keeping all of them tracked would be quite tedious. Therefore I am seeking a way to take complete snapshots of a repo to simplify the backup/restore process. – YAC Jan 25 '19 at 04:06
  • I am curious about your description "you will get some kind of (broken) git-submodule", which refers to the result of a full copy of a .git folder. What do you mean by "broken"? I thought the copy will be exactly the status of the repo. What am I missing? – YAC Jan 25 '19 at 04:06
  • 1
    @YAC I've added one paragraph to explain git-submodules in more depth, then a few suggestions at the end of my answer. – ErikMD Jan 25 '19 at 23:10