git-annex/ git-annex-unannex

# NAME

git-annex unannex - undo accidental add command

# SYNOPSIS

git annex unannex `[path ...]`

# DESCRIPTION

Use this to undo an accidental `git annex add` command. It puts the file back how it was before the add.

Note that for safety, the content of the file remains in the annex, until you use `git annex unused` and `git annex dropunused`.

This is not the command you should use if you intentionally added a file some time ago, and don't want its contents any more. In that case you should use `git annex drop` instead, and you can also `git rm` the file.

# OPTIONS

- `--fast`

  Normally this does a slow copy of the file. In `--fast` mode, it instead makes a hard link from the file to the content in the annex. But use --fast mode with caution, because editing the file will change the content in the annex.

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

- file matching options

  The git-annex-matching-options(1) can be used to specify files to unannex.

- Also the git-annex-common-options(1) can be used.

# SEE ALSO

git-annex(1)

# AUTHOR

Joey Hess id@joeyh.name

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

Re: Weird behavior of git archive in combination with largefiles configuration
Thanks a lot Joey for your very clear explanation and clean workaround.
Comment by arnaud.legrand — Wed Oct 29 14:05:27 2025
Re: Weird behavior of git archive in combination with largefiles configuration

That behavior does not really have anything to do with the use of `git-annex unannex`.

You have configured annex.largefiles to something that matches a file. The file is not checked into git (perhaps because you ran `git-annex unannex` after adding it earlier, but it could just as well be a new file). You run `git add` on the file. What happens? Well, `git add` asks git-annex if the file should be annexed. Your annex.largefiles configuration tells it it should. So the file is added to the annex, and a pointer file is checked into git. (Not a symlink because the file is added unlocked; see git-annex-unlock.)

`git archive` does not archive the contents of the annex, so it only archives the pointer file content.

What you can do is use `git-annex add --force-small` when adding the file to override the annex.largefiles config. See largefiles at the bottom for a recipe for using that to convert an annexed file to be stored in git.

Comment by joey — Wed Oct 29 14:05:27 2025
Weird behavior of git archive in combination with largefiles configuration

Hi,

I'm preparing a lecture on how git annex can help research data management and I stumbled, when playing with `git-annex unannex`, on a strange behavior that I fail to understand nor to properly work around. When preparing for a public archive it may make sense to include some annexed files in the archive while it may be desirable to keep the symlinks for others (e.g., because they are already available from somewhere else). This is why I do not want to rely on the `git-annex export` mechanism that would replace the symlinks of all annexed files by their content.

Instead, I `unannex` some of my files but surprisingly, depending on git annex configuration, their content may not be in the archive produced by `git archive`. Here is a minimal working example.

    DIR=/tmp/test
    chmod -Rf u+w $DIR; rm -rf $DIR ; mkdir -p $DIR; cd $DIR
    git init
    git annex init
    git config --local annex.largefiles 'largerthan=100kb and include=data/*'

    echo "Hello" > README
    git add README

    mkdir data/
    dd if=/dev/zero of=data/foo.dat bs=1M count=1 2>/dev/null
    git annex add data/foo.dat
    git commit -m "Initial commit"

    ## git config --local annex.largefiles ''
    git annex unannex data/foo.dat && git add data/foo.dat && git commit -m "Unannexing"
    git archive --format=tar.gz --prefix nobel_project/ -o ../archive.tgz HEAD

    tar zxf ../archive.tgz
    tree -s nobel_project/

     Initialized empty Git repository in /tmp/test/.git/
    init  ok
    (recording state in git...)
           add data/foo.dat
    31.98 KiB        14 MiB/s 0s100%  1 MiB           137 MiB/s 0s                                  ok
    (recording state in git...)
    [master (root-commit) 8fbb907] Initial commit
     2 files changed, 2 insertions(+)
     create mode 100644 README
     create mode 120000 data/foo.dat
      unannex data/foo.dat ok
    (recording state in git...)
    [master da73fb0] Unannexing
     1 file changed, 1 insertion(+), 1 deletion(-)
    )
    100644
    mnobel_project/
    ├── [       4096]  data
    │   └── [        102]  foo.dat
    └── [          6]  README

    1 directory, 2 files

As you may see from the output, `foo.dat` is only 102 bytes whereas it should be 1MB. Instead the content of `foo.dat` is:

    cat nobel_project/data/foo.dat

    /annex/objects/SHA256E-s1048576--30e14955ebf1352266dc2ff8067e68104607e750abb9d3b36582b8af909fcb58.dat

But if I remove the `annex.largefiles` configuration (either upfront or right before calling `unannex`), everything works as expected, i.e., my archive comprises the content of the annexed file.

Is this an expected behavior ? This is the kind of operation I typically do in a branch that I erase afterward but it (temporarily) messes my local git configuration, which I don't like, so I'm looking for a better workaround.

Thanks for you amazing work,

Arnaud

Comment by arnaud.legrand — Wed Oct 29 14:05:27 2025
comment 5

@datamanager the `git-annex unannex` command can't rewrite git history, it just stops further tracking of an annexed file by git. Any way you would usually scrub an unwanted commit out of git's history can be used with git-annex; scrubbing mentioned of hashes out of the git-annex branch's history gets more involved.

Once you have run `git-annex unannex` on a file, it's not annexed, so commands like `git-annex whereis` will not have anything to say about it.

Comment by joey — Wed Oct 29 14:05:27 2025
is there some way to remove a file I've commited?

Essentially, I want to tell git-annex to forget about my file; remove it from the annex, and put the original file back where it was in my local filesystem.

I made the mistake of adding a list of files accidentally, and then panicked. I even ran git-annex-sync, so there's now a commit on the git-annex branch with my accidentally added files. I thought that maybe I could just revert that commit and all would be well, but I thought I'd seek some assistance before doing that.

I haven't copied the files to any other remotes as yet, but git-annex-whereis returns nothing when I give it one of the paths I added by mistake, so those files seem to be in some kind of limbo, where they're in the annex, but it doesn't know about them. I am not sure what I broke along the way.

Comment by datamanager — Wed Oct 29 14:05:27 2025
Ok, v6 not mature yet (as of 2016-10).

> with the newer v6 repository format, git annex unannex is able to safely handle files that have been added and not committed yet.

I was puzzled, believing that recent versions used v6 repository format.

Indeed, all my repositories have been created with 6.20161011-g3135d35 with default options (indirect mode).

    git-annex version: 6.20161011-g3135d35
    build flags: Assistant Webapp Pairing Testsuite S3(multipartupload)(storageclasses) WebDAV Inotify DBus DesktopNotify XMPP ConcurrentOutput TorrentParser MagicMime Feeds Quvi
    key/value backends: SHA256E SHA256 SHA512E SHA512 SHA224E SHA224 SHA384E SHA384 SHA3_256E SHA3_256 SHA3_512E SHA3_512 SHA3_224E SHA3_224 SHA3_384E SHA3_384 SKEIN256E SKEIN256 SKEIN512E SKEIN512 SHA1E SHA1 MD5E MD5 WORM URL
    remote types: git gcrypt S3 bup directory rsync web bittorrent webdav tahoe glacier ddar hook external
    local repository version: 5
    supported repository versions: 3 5 6
    upgrade supported from repository versions: 0 1 2 3 4 5
    operating system: linux x86_64

I understand now that v6 is still experimental and not enabled by default ( ref http://git-annex.branchable.com/devblog/day_421__lost_in_the_trees/ ).

Comment by https://launchpad.net/~stephane-gourichon-lpad — Wed Oct 29 14:05:27 2025
comment 2

The behavior your comment describes is only the case with v5 repoitories in indirect mode. With v5 direct mode repositories and with the newer v6 repository format, `git annex unannex` is able to safely handle files that have been added and not committed yet.

Comment by joey — Wed Oct 29 14:05:27 2025
This needs to commit first. Any alternative?

Hello and thank you for git-annex.

## Context

Every newbie needs to understand what steps are possible and what to do when a wrong step was made.

The wording "undo accidental add command" suggested (to me at least) that it was intended to be issued just right after the accidental add command, before any commit.

## Steps to reproduce

Right after `git annex add path`, do `git annex unannex path`.

## Expected behavior

`git annex unannex path` would undo the add.

More precisely, it would walk the path given, find any symlink pointing to annexed data and not committed yet, and replace it with a plain file with the linked content, honoring `--fast` option if given.

## Observed behavior

    git-annex: Cannot proceed with uncommitted changes staged in the index. Recommend you: git commit

If user follows this path, there will be two unnecessary commits: an add commit and an unannex commit.

There may be reasons to prefer not to introduce those commits. Granted, git allows to adjust history after the fact. Is there a simpler solution?

## Question, summarized

Is there a command to just revert a "add", without introducing any commit?

## Details

Full test log below:

    {
    cd /tmp/ ; mkdir testga ; cd testga ;
    git init ; git annex init ;
    echo "test" > test ;
    git annex add test ; git annex unannex test
    }

    Initialized empty Git repository in /tmp/testga/.git/
    init  ok
    (recording state in git...)
    add test ok
    (recording state in git...)
    git-annex: Cannot proceed with uncommitted changes staged in the index. Recommend you: git commit

Thank you for any hint.

Comment by https://launchpad.net/~stephane-gourichon-lpad — Wed Oct 29 14:05:27 2025
Comments on this page are closed.