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:
commit
a660534e06
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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) {
|
|
||||||
|
if (!cmd->expire_unreachable || !strcmp(ref, "HEAD")) {
|
||||||
|
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;
|
cb.mark_list = NULL;
|
||||||
commit_list_insert(cb.ref_commit, &cb.mark_list);
|
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)) {
|
||||||
|
@ -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
|
||||||
'
|
'
|
||||||
|
@ -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" &&
|
||||||
|
Loading…
Reference in New Issue
Block a user