git-annex/ git-annex-undo

# NAME

git-annex undo - undo last change to a file or directory

# SYNOPSIS

git annex `[filename|directory] ...`

# DESCRIPTION

When passed a filename, undoes the last change that was made to that file.

When passed a directory, undoes the last change that was made to the contents of that directory.

Running undo a second time will undo the undo, returning the working tree to the same state it had before. To support undoing an undo of staged changes, any staged changes are first committed by the undo command.

Note that this does not undo get/drop of a file's content; it only operates on the file tree committed to git.

# OPTIONS

- `--json`

  Enable JSON output. This is intended to be parsed by programs that use git-annex. Each line of output is a JSON object.

- `--json-error-messages`

  Messages that would normally be output to standard error are included in the JSON instead.

- The git-annex-common-options(1) can also be used.

# SEE ALSO

git-annex(1)

git-annex-add(1)

# AUTHOR

Joey Hess id@joeyh.name

Warning: Automatically converted into a man page by mdwn2man. Edit with care.

git-annex-undo: 3 issues and fix suggestions

Hello Joey.

Thank you for your answer. It makes things clearer. I believe the documentation should reflect it.

## Where the bug (1) is: not defining the level of operation

> git annex undo undoes the last change that was committed to the file.

Ah, committed. That's an important information. It's not at all what I expected from reading the page.

I was expecting tree-level undo, not commit-level undo. I've found the bug: The documentation for git-annex undo does not define "undo" or the level at which it operates.

### Suggestion (1): define the level of operation

What if the documentation included something like this?

> Here, "undo" means: "undo a commit", that is "add a commit in the history that undoes the previous commit".

## Case (2) of staged changes

> If the file has staged changes, git annex undo first commits those changes (to avoid losing data) and then undoes that commit.

This sounds strange.

So, if I call git-annex-undo to undo a commit A, but there are staged changes, git-annex-undo will add a commit B then add another commit C to undo B?

This will not undo A.

What use case where you thinking of?

### Case of staged changes: suggestion (2)

Perhaps in case when file has staged changes, it would be better to display a warning message, perhaps with a `--commit-staged` option to bypass it.

## Internal rationale: got it

> The reason that git annex undo deleted the files from your working tree is that the previous commit did not have those files in it, and it undid to the state at that commit.

> So, you will never lose the content of a file by running git annex undo. If git annex undo deletes a file, you can always get it back by checking out a previous version of the branch. Or even by running git annex undo a second time, to undo the undo.

Ok I understand the data was not lost. But this kind of reasoning is only reachable when one knows what git-annex-undo really does. So, this command is still dangerous to the unsavvy. Perhaps document that?

## Issue (3): What was actually needed (all this time)

It seems that what I really needed was git-annex-unannex.

### Suggested changes to documentation (3)

Perhaps in case when file has staged changes, it would be better to display a warning message and suggest using git-annex-unannex instead?

> If you are looking for a way to undo changes in the directory tree, consider git-annex-unannex.

## Conclusion

What do you think about the 3 issues and fix suggestions?

Thanks again. `git-annex` has started to become useful here.

Comment by https://launchpad.net/~stephane-gourichon-lpad — Tue Jul 22 18:11:47 2025
comment 3

`git annex undo` undoes the last change that was committed to the file. If the file has staged changes, `git annex undo` first commits those changes (to avoid losing data) and then undoes that commit.

The reason that `git annex undo` deleted the files from your working tree is that the previous commit did not have those files in it, and it undid to the state at that commit.

So, you will never lose the content of a file by running `git annex undo`. If `git annex undo` deletes a file, you can always get it back by checking out a previous version of the branch. Or even by running `git annex undo` a second time, to undo the undo.

Comment by joey — Tue Jul 22 18:11:47 2025
comment 2

Adding this to `.gitattributes`:

    *.xmp annex.largefiles=nothing

Causes `git-annex add` to behave as expected. Questions about `git annex undo` behavior remain.

Comment by https://launchpad.net/~stephane-gourichon-lpad — Tue Jul 22 18:11:47 2025
git-annex-undo removes files, possibly destroying information? Please explain.

Hello,

## Context

Thank you for git-annex. I'm progressing in learning how to use it. Seems to work as intended with only annexed files.

I actually need mixed content repository and like the idea of `annex.largefiles` deciding which files go into the annex.

While experimenting with mixed content repository, I had `git-annex-undo` destroy information twice. Or perhaps I did something wrong?

## What happened

Here's my .gitattributes

    *.NEF annex.largefiles=anything
    *.JPG annex.largefiles=anything
    *.jpg annex.largefiles=anything

I had a directory (say, `newdir`) with some jpg and some other files, not known by git or git-annex so far.

Based on https://git-annex.branchable.com/tips/largefiles/ I expected both `git add` and `git annex add` to add NEF JPG jpg to the annex, and other files as regular git files.

In case of problem, I expected `git annex undo` to revert state to the one just before the last command (which is: full of my regular files, not symlinks or empty).

- `git add newdir` added them all as regular files, not partly in the annex as expected. Surprised, I wanted to undo and try another command.
- `git annex undo` emptied `newdir` completely. Wow! Fortunately these were copies, else they would have been gone forever! To be fair I have not checked at that point if files had been copied in annex, which as only copy would still be a mess because file names would have been lost anyway.

I used `git reset <hash>` to revert state git-style, checked with `git status` that state was indeed back to pre-add (newdir empty, not known to git), then copied the files again from their source.

- `git annex add newdir` added them all as annexed files, replacing with links, not partly as regular files as expected.
- `git annex undo` emptied `newdir` completely. I expected my regular files back in place.

I had the intended result by using `git add` on regular files and `git annex add` to add files to be annexed. As if `.gitattributes` were absent.

git-annex compiled on Debian unstable as of 2016-10-13 from git source, commit 3135d35094aa5453ef7a5f12762e00e0139a6dbb.

## Questions

- Have I explained situation clearly?
- Did `git annex add` behave as intended by you? Wasn't it supposed to automatically decide which files go to the annex?
- Did `git annex undo` behave as intended by you? Wasn't it supposed to revert working directory to the state just before the wrong "add"?
- Have I used `.gitattributes`, `add` commands correctly?

Thank you.

Comment by https://launchpad.net/~stephane-gourichon-lpad — Tue Jul 22 18:11:47 2025
Comments on this page are closed.