Merge branch 'jc/maint-no-reflog-expire-unreach-for-head'

* jc/maint-no-reflog-expire-unreach-for-head:
  reflog --expire-unreachable: special case entries in "HEAD" reflog
  more war on "sleep" in tests
  Document gc.<pattern>.reflogexpire variables

Conflicts:
	Documentation/config.txt
This commit is contained in:
Junio C Hamano 2010-05-21 04:02:18 -07:00
commit a660534e06
5 changed files with 92 additions and 19 deletions

View file

@ -946,13 +946,19 @@ gc.pruneexpire::
unreachable objects immediately. unreachable objects immediately.
gc.reflogexpire:: gc.reflogexpire::
gc.<pattern>.reflogexpire::
'git reflog expire' removes reflog entries older than 'git reflog expire' removes reflog entries older than
this time; defaults to 90 days. this time; defaults to 90 days. With "<pattern>" (e.g.
"refs/stash") in the middle the setting applies only to
the refs that match the <pattern>.
gc.reflogexpireunreachable:: gc.reflogexpireunreachable::
gc.<ref>.reflogexpireunreachable::
'git reflog expire' removes reflog entries older than 'git reflog expire' removes reflog entries older than
this time and are not reachable from the current tip; this time and are not reachable from the current tip;
defaults to 30 days. defaults to 30 days. With "<pattern>" (e.g. "refs/stash")
in the middle, the setting applies only to the refs that
match the <pattern>.
gc.rerereresolved:: gc.rerereresolved::
Records of conflicted merge you resolved earlier are Records of conflicted merge you resolved earlier are

View file

@ -88,6 +88,16 @@ commits prior to the amend or rebase occurring. Since these changes
are not part of the current project most users will want to expire are not part of the current project most users will want to expire
them sooner. This option defaults to '30 days'. them sooner. This option defaults to '30 days'.
The above two configuration variables can be given to a pattern. For
example, this sets non-default expiry values only to remote tracking
branches:
------------
[gc "refs/remotes/*"]
reflogExpire = never
reflogexpireUnreachable = 3 days
------------
The optional configuration variable 'gc.rerereresolved' indicates The optional configuration variable 'gc.rerereresolved' indicates
how long records of conflicted merge you resolved earlier are how long records of conflicted merge you resolved earlier are
kept. This defaults to 60 days. kept. This defaults to 60 days.

View file

@ -34,8 +34,11 @@ struct cmd_reflog_expire_cb {
struct expire_reflog_cb { struct expire_reflog_cb {
FILE *newlog; FILE *newlog;
const char *ref; enum {
struct commit *ref_commit; UE_NORMAL,
UE_ALWAYS,
UE_HEAD
} unreachable_expire_kind;
struct commit_list *mark_list; struct commit_list *mark_list;
unsigned long mark_limit; unsigned long mark_limit;
struct cmd_reflog_expire_cb *cmd; struct cmd_reflog_expire_cb *cmd;
@ -305,7 +308,7 @@ static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
goto prune; goto prune;
if (timestamp < cb->cmd->expire_unreachable) { if (timestamp < cb->cmd->expire_unreachable) {
if (!cb->ref_commit) if (cb->unreachable_expire_kind == UE_ALWAYS)
goto prune; goto prune;
if (unreachable(cb, old, osha1) || unreachable(cb, new, nsha1)) if (unreachable(cb, old, osha1) || unreachable(cb, new, nsha1))
goto prune; goto prune;
@ -332,12 +335,27 @@ static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
return 0; return 0;
} }
static int push_tip_to_list(const char *refname, const unsigned char *sha1, int flags, void *cb_data)
{
struct commit_list **list = cb_data;
struct commit *tip_commit;
if (flags & REF_ISSYMREF)
return 0;
tip_commit = lookup_commit_reference_gently(sha1, 1);
if (!tip_commit)
return 0;
commit_list_insert(tip_commit, list);
return 0;
}
static int expire_reflog(const char *ref, const unsigned char *sha1, int unused, void *cb_data) static int expire_reflog(const char *ref, const unsigned char *sha1, int unused, void *cb_data)
{ {
struct cmd_reflog_expire_cb *cmd = cb_data; struct cmd_reflog_expire_cb *cmd = cb_data;
struct expire_reflog_cb cb; struct expire_reflog_cb cb;
struct ref_lock *lock; struct ref_lock *lock;
char *log_file, *newlog_path = NULL; char *log_file, *newlog_path = NULL;
struct commit *tip_commit;
struct commit_list *tips;
int status = 0; int status = 0;
memset(&cb, 0, sizeof(cb)); memset(&cb, 0, sizeof(cb));
@ -357,18 +375,49 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused,
cb.newlog = fopen(newlog_path, "w"); cb.newlog = fopen(newlog_path, "w");
} }
cb.ref_commit = lookup_commit_reference_gently(sha1, 1);
cb.ref = ref;
cb.cmd = cmd; cb.cmd = cmd;
if (cb.ref_commit) {
cb.mark_list = NULL; if (!cmd->expire_unreachable || !strcmp(ref, "HEAD")) {
commit_list_insert(cb.ref_commit, &cb.mark_list); tip_commit = NULL;
cb.unreachable_expire_kind = UE_HEAD;
} else {
tip_commit = lookup_commit_reference_gently(sha1, 1);
if (!tip_commit)
cb.unreachable_expire_kind = UE_ALWAYS;
else
cb.unreachable_expire_kind = UE_NORMAL;
}
if (cmd->expire_unreachable <= cmd->expire_total)
cb.unreachable_expire_kind = UE_ALWAYS;
cb.mark_list = NULL;
tips = NULL;
if (cb.unreachable_expire_kind != UE_ALWAYS) {
if (cb.unreachable_expire_kind == UE_HEAD) {
struct commit_list *elem;
for_each_ref(push_tip_to_list, &tips);
for (elem = tips; elem; elem = elem->next)
commit_list_insert(elem->item, &cb.mark_list);
} else {
commit_list_insert(tip_commit, &cb.mark_list);
}
cb.mark_limit = cmd->expire_total; cb.mark_limit = cmd->expire_total;
mark_reachable(&cb); mark_reachable(&cb);
} }
for_each_reflog_ent(ref, expire_reflog_ent, &cb); for_each_reflog_ent(ref, expire_reflog_ent, &cb);
if (cb.ref_commit)
clear_commit_marks(cb.ref_commit, REACHABLE); if (cb.unreachable_expire_kind != UE_ALWAYS) {
if (cb.unreachable_expire_kind == UE_HEAD) {
struct commit_list *elem;
for (elem = tips; elem; elem = elem->next)
clear_commit_marks(tip_commit, REACHABLE);
free_commit_list(tips);
} else {
clear_commit_marks(tip_commit, REACHABLE);
}
}
finish: finish:
if (cb.newlog) { if (cb.newlog) {
if (fclose(cb.newlog)) { if (fclose(cb.newlog)) {

View file

@ -8,6 +8,7 @@ test_expect_success 'objects in packs marked .keep are not repacked' '
echo content1 > file1 && echo content1 > file1 &&
echo content2 > file2 && echo content2 > file2 &&
git add . && git add . &&
test_tick &&
git commit -m initial_commit && git commit -m initial_commit &&
# Create two packs # Create two packs
# The first pack will contain all of the objects except one # The first pack will contain all of the objects except one
@ -40,6 +41,7 @@ test_expect_success 'loose objects in alternate ODB are not repacked' '
echo content3 > file3 && echo content3 > file3 &&
objsha1=$(GIT_OBJECT_DIRECTORY=alt_objects git hash-object -w file3) && objsha1=$(GIT_OBJECT_DIRECTORY=alt_objects git hash-object -w file3) &&
git add file3 && git add file3 &&
test_tick &&
git commit -m commit_file3 && git commit -m commit_file3 &&
git repack -a -d -l && git repack -a -d -l &&
git prune-packed && git prune-packed &&
@ -73,6 +75,7 @@ test_expect_success 'packed obs in alt ODB are repacked when local repo has pack
rm -f .git/objects/pack/* && rm -f .git/objects/pack/* &&
echo new_content >> file1 && echo new_content >> file1 &&
git add file1 && git add file1 &&
test_tick &&
git commit -m more_content && git commit -m more_content &&
git repack && git repack &&
git repack -a -d && git repack -a -d &&
@ -118,8 +121,8 @@ test_expect_success 'packed unreachable obs in alternate ODB are not loosened' '
mv .git/objects/pack/* alt_objects/pack/ && mv .git/objects/pack/* alt_objects/pack/ &&
csha1=$(git rev-parse HEAD^{commit}) && csha1=$(git rev-parse HEAD^{commit}) &&
git reset --hard HEAD^ && git reset --hard HEAD^ &&
sleep 1 && test_tick &&
git reflog expire --expire=now --expire-unreachable=now --all && git reflog expire --expire=$test_tick --expire-unreachable=$test_tick --all &&
# The pack-objects call on the next line is equivalent to # The pack-objects call on the next line is equivalent to
# git repack -A -d without the call to prune-packed # git repack -A -d without the call to prune-packed
git pack-objects --honor-pack-keep --non-empty --all --reflog \ git pack-objects --honor-pack-keep --non-empty --all --reflog \
@ -156,7 +159,7 @@ test_expect_success 'objects made unreachable by grafts only are kept' '
H1=$(git rev-parse HEAD^) && H1=$(git rev-parse HEAD^) &&
H2=$(git rev-parse HEAD^^) && H2=$(git rev-parse HEAD^^) &&
echo "$H0 $H2" > .git/info/grafts && echo "$H0 $H2" > .git/info/grafts &&
git reflog expire --expire=now --expire-unreachable=now --all && git reflog expire --expire=$test_tick --expire-unreachable=$test_tick --all &&
git repack -a -d && git repack -a -d &&
git cat-file -t $H1 git cat-file -t $H1
' '

View file

@ -11,17 +11,20 @@ tsha1=
test_expect_success '-A with -d option leaves unreachable objects unpacked' ' test_expect_success '-A with -d option leaves unreachable objects unpacked' '
echo content > file1 && echo content > file1 &&
git add . && git add . &&
test_tick &&
git commit -m initial_commit && git commit -m initial_commit &&
# create a transient branch with unique content # create a transient branch with unique content
git checkout -b transient_branch && git checkout -b transient_branch &&
echo more content >> file1 && echo more content >> file1 &&
# record the objects created in the database for file, commit, tree # record the objects created in the database for file, commit, tree
fsha1=$(git hash-object file1) && fsha1=$(git hash-object file1) &&
test_tick &&
git commit -a -m more_content && git commit -a -m more_content &&
csha1=$(git rev-parse HEAD^{commit}) && csha1=$(git rev-parse HEAD^{commit}) &&
tsha1=$(git rev-parse HEAD^{tree}) && tsha1=$(git rev-parse HEAD^{tree}) &&
git checkout master && git checkout master &&
echo even more content >> file1 && echo even more content >> file1 &&
test_tick &&
git commit -a -m even_more_content && git commit -a -m even_more_content &&
# delete the transient branch # delete the transient branch
git branch -D transient_branch && git branch -D transient_branch &&
@ -34,9 +37,11 @@ test_expect_success '-A with -d option leaves unreachable objects unpacked' '
git show $fsha1 && git show $fsha1 &&
git show $csha1 && git show $csha1 &&
git show $tsha1 && git show $tsha1 &&
# now expire the reflog # now expire the reflog, while keeping reachable ones but expiring
sleep 1 && # unreachables immediately
git reflog expire --expire-unreachable=now --all && test_tick &&
sometimeago=$(( $test_tick - 10000 )) &&
git reflog expire --expire=$sometimeago --expire-unreachable=$test_tick --all &&
# and repack # and repack
git repack -A -d -l && git repack -A -d -l &&
# verify objects are retained unpacked # verify objects are retained unpacked
@ -71,7 +76,7 @@ test_expect_success '-A without -d option leaves unreachable objects packed' '
test 1 = $(ls -1 .git/objects/pack/pack-*.pack | wc -l) && test 1 = $(ls -1 .git/objects/pack/pack-*.pack | wc -l) &&
packfile=$(ls .git/objects/pack/pack-*.pack) && packfile=$(ls .git/objects/pack/pack-*.pack) &&
git branch -D transient_branch && git branch -D transient_branch &&
sleep 1 && test_tick &&
git repack -A -l && git repack -A -l &&
test ! -f "$fsha1path" && test ! -f "$fsha1path" &&
test ! -f "$csha1path" && test ! -f "$csha1path" &&