😎

dura使ってみた

に公開

みなさん、gitレポジトリで作業中に、「コミットしないファイルを間違って削除してしまった」のようなやらかしをしたことがありませんか?一度経験するともう二度とこのような経験をしたくないと思うでしょう。

今回はそのような状況になりにくくするためのツールであるduraというものをご紹介させてもらいます。

duraとは?

duraの公式GitHubリポジトリから引用させてもらいますと、duraとは

Dura is a background process that watches your Git repositories and commits your uncommitted changes without impacting HEAD, the current branch, or the Git index (staged files). If you ever get into an "oh snap!" situation where you think you just lost days of work, checkout a dura branch and recover.
Without dura, you use Ctrl-Z in your editor to get back to a good state. That's so 2021. Computers crash and Ctrl-Z only works on files independently. Dura snapshots changes across the entire repository as-you-go, so you can revert to "4 hours ago" instead of "hit Ctrl-Z like 40 times or whatever". Finally, some sanity.

ということです。要約すると、

  • gitレポジトリをバックグラウンドで監視し、HEADに影響しないように編集内容をコミットとして保持する
  • duraを使うと作業を復元することができる

何かしらエディタなどを使っていればCtrl-Zで戻せるかもしれませんが、エディタを閉じてしまったりするとこの方法は成り立ちませんし、そうなった時は諦めて最初から同じ実装をすることになりかねません。このような問題に対処するためにduraは開発されました。

https://github.com/tkellogg/dura

実際に使ってみよう

インストール方法

レポジトリのREADMEに書かれていますので、その方法を適宜参照してください。Macbookを使っている方はbrew install duraでインストールができます。

サンプルレポジトリの作成

今回の実験で利用するためのサンプルレポジトリをまず作りましょう。レポジトリはいつも作成する流れで問題ありません。例えばこんな感じですね。

mkdir dura_test_repo
cd dura_test_repo
git init
git checkout -b develop
touch README.md
git add README.md && git commit -m "initial commit"

duraのプロセスを実行する

duraを利用するためには、バックグラウンドプロセスとして実行する必要があります。以下のコマンドを実行することでプロセスを実行してください。

dura serve &

コマンドを見ていただくと分かる通り、このコマンドを実行するとdura serveはバックグラウンドプロセスとして実行されます。ドキュメントにもありますが、このコマンドを実行する場所はどこでもよく、とにかくduraを使いたい場合このコマンドを実行するとのことです。ただし、実行するフォルダはどこでもいいですが、コマンドを実行したターミナルウィンドウで作業するようにしてください。

duraにレポジトリを監視させる

duraのプロセスが起動したので、次はレポジトリを監視するようにduraに依頼しましょう。レポジトリ内で以下のコマンドを実行します。

dura watch

するとログにStarted watching /Users/.../dura_test_repoのように表示されるはずです。

ファイルを編集してみる

今回はREADME.mdを編集中に間違って削除してしまった程で、最後に保存した状態を復元してみたいと思います。
まずはエディタでREADME.mdを開いて、以下の内容を入力してみてください。

hoge
fuga

これを保存した状態でgit statusを実行すると以下のように表示されるはずです。

On branch develop
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   README.md

no changes added to commit (use "git add" and/or "git commit -a")

ファイルを削除してみる

本来であればREADME.mdの変更をcommitするところですが、ここでファイルを削除してみたいと思います。

まず初めに、今duraがどのように状況を認識しているかみてみましょう。この状態でブランチ一覧を見ると、duraが自動生成したブランチが確認できます。私の環境では以下のようになりました。

* develop
  dura/2d3b23b0b2b678a6dc432bdf00965b11b300c8da

また、全てのログを見るためにgit log --allを実行すると、duraが自動でバックアップを作成していることがわかります。私の環境では以下のようになりました。

commit e0fd5ca3826f6db992d8facd188171aecb0562f8 (dura/2d3b23b0b2b678a6dc432bdf00965b11b300c8da)
Author: ...
Date:   Mon Apr 28 20:33:33 2025 +0900

    dura auto-backup

commit 2d3b23b0b2b678a6dc432bdf00965b11b300c8da (HEAD -> develop)
Author: ...
Date:   Mon Apr 28 20:32:06 2025 +0900

    initial commit

dura auto-backupとあるように、先ほど作成されていたduraのブランチにてこの追跡が自動でされています。ではここでREADME.mdを削除してみましょう。

rm README.md

もちろん、git statusを実行するとREADMEはただ削除されただけと認識され、我々が編集したんだけど間違って消したことはgitからは知る由もありません。

n branch develop
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	deleted:    README.md

no changes added to commit (use "git add" and/or "git commit -a")

この時、dura側のブランチのログも見ると、先ほどのauto-backupの後にもう一つバックアップが作成されているのが確認できます。これはファイルが削除されたことをバックアップしています。

commit 4f37bbfb5d91d23be2c3d2dd7b631032e7ebc3bc (dura/2d3b23b0b2b678a6dc432bdf00965b11b300c8da)
Author: ...
Date:   Mon Apr 28 20:36:53 2025 +0900

    dura auto-backup

commit e0fd5ca3826f6db992d8facd188171aecb0562f8
Author: ...
Date:   Mon Apr 28 20:33:33 2025 +0900

    dura auto-backup

commit 2d3b23b0b2b678a6dc432bdf00965b11b300c8da (HEAD -> develop)
Author: ...
Date:   Mon Apr 28 20:32:06 2025 +0900

    initial commit

README.mdを編集後に復元する

それではREADME.mdを編集した後に復元します。復元方法自体は手続きは毎回一緒なのですが、duraコマンドでできるわけではなく、自動生成されたコミットを利用して復元します。少し長いですが、以下のコマンドを実行することで復元できます。

git reset HEAD --hard
git checkout 編集を記録していた自動バックアップコミットのHASH
# 私の場合e0fd5ca3826f6db992d8facd188171aecb0562f8です
git checkout -b temp-branch
git reset develop
git checkout develop
git branch -D temp-branch

これを実行すると以下のようなログが表示されます。

HEAD is now at 2d3b23b initial commit
Note: switching to 'e0fd5ca3826f6db992d8facd188171aecb0562f8'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at e0fd5ca dura auto-backup
Switched to a new branch 'temp-branch'
Unstaged changes after reset:
M	README.md
M	README.md
Switched to branch 'develop'
Deleted branch temp-branch (was 2d3b23b).

いろいろ書かれていますが、この状態でREADME.mdを確認すると以下の内容で復元されているはずです。

hoge
fuga

あとはこの情報を利用してcommitをすることで無事ファイル復元完了となります。
注意点としては

  • 自動バックアップのメッセージだけではなんのことかわからないので、必要に応じてバックアップコミットの変更点を確認する
  • duraが自動生成したブランチを削除するとバックアップ復元ができない

になります。

まとめ

今回はduraを利用して間違って消したりしてしまったファイルの復元方法を共有しました。内部的にはgitを使って自動でファイル追跡をしてくれているだけですが、この仕組みが用意されているだけでメンタル的にも安心するのではないでしょうか。

ただし、duraは便利ですがこのコマンドを使わなくても済むようにファイル管理を気をつけたいなと編集しながら思いました。

みなさんもぜひ興味があれば使ってみてください。

Discussion