8 struct expire_reflog_cb
{
11 struct commit
*ref_commit
;
12 unsigned long expire_total
;
13 unsigned long expire_unreachable
;
16 static int keep_entry(struct commit
**it
, unsigned char *sha1
)
19 if (is_null_sha1(sha1
))
21 *it
= lookup_commit_reference_gently(sha1
, 1);
25 static int expire_reflog_ent(unsigned char *osha1
, unsigned char *nsha1
,
26 char *data
, void *cb_data
)
28 struct expire_reflog_cb
*cb
= cb_data
;
29 unsigned long timestamp
;
31 struct commit
*old
, *new;
33 cp
= strchr(data
, '>');
34 if (!cp
|| *++cp
!= ' ')
36 timestamp
= strtoul(cp
, &ep
, 10);
39 if (timestamp
< cb
->expire_total
)
42 if (!keep_entry(&old
, osha1
) || !keep_entry(&new, nsha1
))
45 if ((timestamp
< cb
->expire_unreachable
) &&
46 ((old
&& !in_merge_bases(old
, cb
->ref_commit
)) ||
47 (new && !in_merge_bases(new, cb
->ref_commit
))))
51 fprintf(cb
->newlog
, "%s %s %s",
52 sha1_to_hex(osha1
), sha1_to_hex(nsha1
), data
);
56 fprintf(stderr
, "would prune %s", data
);
60 struct cmd_reflog_expire_cb
{
62 unsigned long expire_total
;
63 unsigned long expire_unreachable
;
66 static int expire_reflog(const char *ref
, const unsigned char *sha1
, int unused
, void *cb_data
)
68 struct cmd_reflog_expire_cb
*cmd
= cb_data
;
69 struct expire_reflog_cb cb
;
70 struct ref_lock
*lock
;
71 char *newlog_path
= NULL
;
74 if (strncmp(ref
, "refs/", 5))
75 return error("not a ref '%s'", ref
);
77 memset(&cb
, 0, sizeof(cb
));
78 /* we take the lock for the ref itself to prevent it from
81 lock
= lock_ref_sha1(ref
+ 5, sha1
);
83 return error("cannot lock ref '%s'", ref
);
84 if (!file_exists(lock
->log_file
))
87 newlog_path
= xstrdup(git_path("logs/%s.lock", ref
));
88 cb
.newlog
= fopen(newlog_path
, "w");
91 cb
.ref_commit
= lookup_commit_reference_gently(sha1
, 1);
93 status
= error("ref '%s' does not point at a commit", ref
);
97 cb
.expire_total
= cmd
->expire_total
;
98 cb
.expire_unreachable
= cmd
->expire_unreachable
;
99 for_each_reflog_ent(ref
, expire_reflog_ent
, &cb
);
102 if (fclose(cb
.newlog
))
103 status
|= error("%s: %s", strerror(errno
),
105 if (rename(newlog_path
, lock
->log_file
)) {
106 status
|= error("cannot rename %s to %s",
107 newlog_path
, lock
->log_file
);
116 static const char reflog_expire_usage
[] =
117 "git-reflog expire [--dry-run] [--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...";
119 static int cmd_reflog_expire(int argc
, const char **argv
, const char *prefix
)
121 struct cmd_reflog_expire_cb cb
;
122 unsigned long now
= time(NULL
);
123 int i
, status
, do_all
;
125 save_commit_buffer
= 0;
127 memset(&cb
, 0, sizeof(cb
));
128 cb
.expire_total
= now
- 90 * 24 * 3600;
129 cb
.expire_unreachable
= now
- 30 * 24 * 3600;
131 for (i
= 1; i
< argc
; i
++) {
132 const char *arg
= argv
[i
];
133 if (!strcmp(arg
, "--dry-run") || !strcmp(arg
, "-n"))
135 else if (!strncmp(arg
, "--expire=", 9))
136 cb
.expire_total
= approxidate(arg
+ 9);
137 else if (!strncmp(arg
, "--expire-unreachable=", 21))
138 cb
.expire_unreachable
= approxidate(arg
+ 21);
139 else if (!strcmp(arg
, "--all"))
141 else if (!strcmp(arg
, "--")) {
145 else if (arg
[0] == '-')
146 usage(reflog_expire_usage
);
151 status
|= for_each_ref(expire_reflog
, &cb
);
153 const char *ref
= argv
[i
++];
154 unsigned char sha1
[20];
155 if (!resolve_ref(ref
, sha1
, 1, NULL
)) {
156 status
|= error("%s points nowhere!", ref
);
159 status
|= expire_reflog(ref
, sha1
, 0, &cb
);
164 static const char reflog_usage
[] =
165 "git-reflog (expire | ...)";
167 int cmd_reflog(int argc
, const char **argv
, const char *prefix
)
171 else if (!strcmp(argv
[1], "expire"))
172 return cmd_reflog_expire(argc
- 1, argv
+ 1, prefix
);