8 struct expire_reflog_cb
{
11 struct commit
*ref_commit
;
12 unsigned long expire_total
;
13 unsigned long expire_unreachable
;
16 static int tree_is_complete(const unsigned char *sha1
)
18 struct tree_desc desc
;
22 buf
= read_sha1_file(sha1
, type
, &desc
.size
);
27 const unsigned char *elem
;
31 elem
= tree_entry_extract(&desc
, &name
, &mode
);
32 if (!has_sha1_file(elem
) ||
33 (S_ISDIR(mode
) && !tree_is_complete(elem
))) {
37 update_tree_entry(&desc
);
43 static int keep_entry(struct commit
**it
, unsigned char *sha1
)
45 struct commit
*commit
;
48 if (is_null_sha1(sha1
))
50 commit
= lookup_commit_reference_gently(sha1
, 1);
54 /* Make sure everything in this commit exists. */
55 parse_object(commit
->object
.sha1
);
56 if (!tree_is_complete(commit
->tree
->object
.sha1
))
62 static int expire_reflog_ent(unsigned char *osha1
, unsigned char *nsha1
,
63 char *data
, void *cb_data
)
65 struct expire_reflog_cb
*cb
= cb_data
;
66 unsigned long timestamp
;
68 struct commit
*old
, *new;
70 cp
= strchr(data
, '>');
71 if (!cp
|| *++cp
!= ' ')
73 timestamp
= strtoul(cp
, &ep
, 10);
76 if (timestamp
< cb
->expire_total
)
79 if (!keep_entry(&old
, osha1
) || !keep_entry(&new, nsha1
))
82 if ((timestamp
< cb
->expire_unreachable
) &&
83 ((old
&& !in_merge_bases(old
, cb
->ref_commit
)) ||
84 (new && !in_merge_bases(new, cb
->ref_commit
))))
88 fprintf(cb
->newlog
, "%s %s %s",
89 sha1_to_hex(osha1
), sha1_to_hex(nsha1
), data
);
93 fprintf(stderr
, "would prune %s", data
);
97 struct cmd_reflog_expire_cb
{
99 unsigned long expire_total
;
100 unsigned long expire_unreachable
;
103 static int expire_reflog(const char *ref
, const unsigned char *sha1
, int unused
, void *cb_data
)
105 struct cmd_reflog_expire_cb
*cmd
= cb_data
;
106 struct expire_reflog_cb cb
;
107 struct ref_lock
*lock
;
108 char *newlog_path
= NULL
;
111 if (strncmp(ref
, "refs/", 5))
112 return error("not a ref '%s'", ref
);
114 memset(&cb
, 0, sizeof(cb
));
115 /* we take the lock for the ref itself to prevent it from
118 lock
= lock_ref_sha1(ref
+ 5, sha1
);
120 return error("cannot lock ref '%s'", ref
);
121 if (!file_exists(lock
->log_file
))
124 newlog_path
= xstrdup(git_path("logs/%s.lock", ref
));
125 cb
.newlog
= fopen(newlog_path
, "w");
128 cb
.ref_commit
= lookup_commit_reference_gently(sha1
, 1);
129 if (!cb
.ref_commit
) {
130 status
= error("ref '%s' does not point at a commit", ref
);
134 cb
.expire_total
= cmd
->expire_total
;
135 cb
.expire_unreachable
= cmd
->expire_unreachable
;
136 for_each_reflog_ent(ref
, expire_reflog_ent
, &cb
);
139 if (fclose(cb
.newlog
))
140 status
|= error("%s: %s", strerror(errno
),
142 if (rename(newlog_path
, lock
->log_file
)) {
143 status
|= error("cannot rename %s to %s",
144 newlog_path
, lock
->log_file
);
153 static const char reflog_expire_usage
[] =
154 "git-reflog expire [--dry-run] [--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...";
156 static int cmd_reflog_expire(int argc
, const char **argv
, const char *prefix
)
158 struct cmd_reflog_expire_cb cb
;
159 unsigned long now
= time(NULL
);
160 int i
, status
, do_all
;
162 save_commit_buffer
= 0;
164 memset(&cb
, 0, sizeof(cb
));
165 cb
.expire_total
= now
- 90 * 24 * 3600;
166 cb
.expire_unreachable
= now
- 30 * 24 * 3600;
168 for (i
= 1; i
< argc
; i
++) {
169 const char *arg
= argv
[i
];
170 if (!strcmp(arg
, "--dry-run") || !strcmp(arg
, "-n"))
172 else if (!strncmp(arg
, "--expire=", 9))
173 cb
.expire_total
= approxidate(arg
+ 9);
174 else if (!strncmp(arg
, "--expire-unreachable=", 21))
175 cb
.expire_unreachable
= approxidate(arg
+ 21);
176 else if (!strcmp(arg
, "--all"))
178 else if (!strcmp(arg
, "--")) {
182 else if (arg
[0] == '-')
183 usage(reflog_expire_usage
);
188 status
|= for_each_ref(expire_reflog
, &cb
);
190 const char *ref
= argv
[i
++];
191 unsigned char sha1
[20];
192 if (!resolve_ref(ref
, sha1
, 1, NULL
)) {
193 status
|= error("%s points nowhere!", ref
);
196 status
|= expire_reflog(ref
, sha1
, 0, &cb
);
201 static const char reflog_usage
[] =
202 "git-reflog (expire | ...)";
204 int cmd_reflog(int argc
, const char **argv
, const char *prefix
)
208 else if (!strcmp(argv
[1], "expire"))
209 return cmd_reflog_expire(argc
- 1, argv
+ 1, prefix
);