git/list[1] front-page[2] threads[3] people[4] search[5] about
 

gc and repack ignore .git/*HEAD when checking reachability

From
Josh Triplett <josh@joshtriplett.org>
Date
Jul 8, 2016, 02:59 UTC
Message-ID
<20160708025948.GA3226@x>
The manpage for git gc says:
Show 6 quoted lines
> git gc tries very hard to be safe about the garbage it collects. In
> particular, it will keep not only objects referenced by your current
> set of branches and tags, but also objects referenced by the index,
> remote-tracking branches, refs saved by git filter-branch in
> refs/original/, or reflogs (which may reference commits in branches
> that were later amended or rewound).

gc, repack, and anything else that uses the machinery in reachable.c will also check HEAD, to include objects only reachable from a detached HEAD (which the manpage should document).

However, unreachable.c does not check any other ref that sits directly in the .git directory, such as MERGE_HEAD, FETCH_HEAD, or CHERRY_PICK_HEAD. To test this, try creating a new empty repository with "git init repo ; cd repo", then use "git fetch URL" to fetch a repository into FETCH_HEAD, then run "git repack -a -d -f", and then "git show FETCH_HEAD". This similarly affects "git gc", which will unpack all the objects from the pack and leave them loose.

This could result in data loss, if a user expected that having an object referenced from those places would protect it from pruning.

I think the right fix for this would involve having mark_reachable_objects in reachable.c add all refs that match .git/*HEAD, not just .git/HEAD itself. (I'd suggest matching .git/*HEAD rather than hardcoding the list of "special" refs, to provide compatibility with any other tool or future version of git that introduces another such ref.) This seems fairly easily done with a new variant of do_head_ref that includes all such refs, along with a one-line change to mark_reachable_objects to use it.

Does this seem like a reasonable approach?
- Josh Triplett
Next: Junio C Hamano
Message 1 of 27 in “gc and repack ignore .git/*HEAD when checking reachability”
  1. Josh TriplettJul 8, 2016
  2. Junio C HamanoJul 8, 2016
  3. Josh TriplettJul 8, 2016
  4. Junio C HamanoJul 8, 2016
  5. Theodore Ts'oJul 8, 2016
  6. Junio C HamanoJul 8, 2016
  7. Theodore Ts'oJul 8, 2016
  8. Josh TriplettJul 9, 2016
  9. Josh TriplettJul 8, 2016
  10. Johannes SchindelinJul 9, 2016
  11. Josh TriplettJul 9, 2016
  12. Duy NguyenJul 9, 2016
  13. Johannes SchindelinJul 10, 2016
  14. Duy NguyenJul 10, 2016
  15. Johannes SchindelinJul 10, 2016
  16. Duy NguyenJul 10, 2016
  17. Johannes SchindelinJul 11, 2016
  18. Junio C HamanoJul 11, 2016
  19. Johannes SchindelinJul 12, 2016
  20. Jeff KingJul 12, 2016
  21. Duy NguyenJul 12, 2016
  22. Jeff KingJul 12, 2016
  23. Duy NguyenJul 12, 2016
  24. Johannes SchindelinJul 13, 2016
  25. Duy NguyenJul 13, 2016
  26. Johannes SchindelinJul 13, 2016
  27. Duy NguyenJul 15, 2016

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.