Notes API: prune_notes(): Prune notes that belong to non-existing objects
When an object is made unreachable by Git, any notes that annotate that object are not automagically made unreachable, since all notes are always trivially reachable from a notes ref. In order to remove notes for non-existing objects, we therefore need to add functionality for traversing the notes tree and explicitly removing references to notes that annotate non-reachable objects. Thus the notes objects themselves also become unreachable, and are removed by a later garbage collect. prune_notes() performs this traversal (by using for_each_note() internally), and removes the notes in question from the notes tree. Note that the effect of prune_notes() is not persistent unless a subsequent call to write_notes_tree() is made. Signed-off-by: Johan Herland <johan@herland.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
							parent
							
								
									b0032d1e06
								
							
						
					
					
						commit
						00fbe63627
					
				
							
								
								
									
										39
									
								
								notes.c
								
								
								
								
							
							
						
						
									
										39
									
								
								notes.c
								
								
								
								
							|  | @ -749,6 +749,29 @@ static int write_each_note(const unsigned char *object_sha1, | ||||||
| 		write_each_note_helper(d->root, note_path, mode, note_sha1); | 		write_each_note_helper(d->root, note_path, mode, note_sha1); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | struct note_delete_list { | ||||||
|  | 	struct note_delete_list *next; | ||||||
|  | 	const unsigned char *sha1; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static int prune_notes_helper(const unsigned char *object_sha1, | ||||||
|  | 		const unsigned char *note_sha1, char *note_path, | ||||||
|  | 		void *cb_data) | ||||||
|  | { | ||||||
|  | 	struct note_delete_list **l = (struct note_delete_list **) cb_data; | ||||||
|  | 	struct note_delete_list *n; | ||||||
|  |  | ||||||
|  | 	if (has_sha1_file(object_sha1)) | ||||||
|  | 		return 0; /* nothing to do for this note */ | ||||||
|  |  | ||||||
|  | 	/* failed to find object => prune this note */ | ||||||
|  | 	n = (struct note_delete_list *) xmalloc(sizeof(*n)); | ||||||
|  | 	n->next = *l; | ||||||
|  | 	n->sha1 = object_sha1; | ||||||
|  | 	*l = n; | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
| int combine_notes_concatenate(unsigned char *cur_sha1, | int combine_notes_concatenate(unsigned char *cur_sha1, | ||||||
| 		const unsigned char *new_sha1) | 		const unsigned char *new_sha1) | ||||||
| { | { | ||||||
|  | @ -922,6 +945,22 @@ int write_notes_tree(struct notes_tree *t, unsigned char *result) | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void prune_notes(struct notes_tree *t) | ||||||
|  | { | ||||||
|  | 	struct note_delete_list *l = NULL; | ||||||
|  |  | ||||||
|  | 	if (!t) | ||||||
|  | 		t = &default_notes_tree; | ||||||
|  | 	assert(t->initialized); | ||||||
|  |  | ||||||
|  | 	for_each_note(t, 0, prune_notes_helper, &l); | ||||||
|  |  | ||||||
|  | 	while (l) { | ||||||
|  | 		remove_note(t, l->sha1); | ||||||
|  | 		l = l->next; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| void free_notes(struct notes_tree *t) | void free_notes(struct notes_tree *t) | ||||||
| { | { | ||||||
| 	if (!t) | 	if (!t) | ||||||
|  |  | ||||||
							
								
								
									
										12
									
								
								notes.h
								
								
								
								
							
							
						
						
									
										12
									
								
								notes.h
								
								
								
								
							|  | @ -161,6 +161,18 @@ int for_each_note(struct notes_tree *t, int flags, each_note_fn fn, | ||||||
|  */ |  */ | ||||||
| int write_notes_tree(struct notes_tree *t, unsigned char *result); | int write_notes_tree(struct notes_tree *t, unsigned char *result); | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Remove all notes annotating non-existing objects from the given notes tree | ||||||
|  |  * | ||||||
|  |  * All notes in the given notes_tree that are associated with objects that no | ||||||
|  |  * longer exist in the database, are removed from the notes tree. | ||||||
|  |  * | ||||||
|  |  * IMPORTANT: The changes made by prune_notes() to the given notes_tree | ||||||
|  |  * structure are not persistent until a subsequent call to write_notes_tree() | ||||||
|  |  * returns zero. | ||||||
|  |  */ | ||||||
|  | void prune_notes(struct notes_tree *t); | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Free (and de-initialize) the given notes_tree structure |  * Free (and de-initialize) the given notes_tree structure | ||||||
|  * |  * | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Johan Herland
						Johan Herland