Merge branch 'cw/log-updates-for-all-refs-really'
The "core.logAllRefUpdates" that used to be boolean has been enhanced to take 'always' as well, to record ref updates to refs other than the ones that are expected to be updated (i.e. branches, remote-tracking branches and notes). * cw/log-updates-for-all-refs-really: doc: add note about ignoring '--no-create-reflog' update-ref: add test cases for bare repository refs: add option core.logAllRefUpdates = always config: add markup to core.logAllRefUpdates doc
This commit is contained in:
@ -520,10 +520,12 @@ core.logAllRefUpdates::
|
|||||||
"`$GIT_DIR/logs/<ref>`", by appending the new and old
|
"`$GIT_DIR/logs/<ref>`", by appending the new and old
|
||||||
SHA-1, the date/time and the reason of the update, but
|
SHA-1, the date/time and the reason of the update, but
|
||||||
only when the file exists. If this configuration
|
only when the file exists. If this configuration
|
||||||
variable is set to true, missing "`$GIT_DIR/logs/<ref>`"
|
variable is set to `true`, missing "`$GIT_DIR/logs/<ref>`"
|
||||||
file is automatically created for branch heads (i.e. under
|
file is automatically created for branch heads (i.e. under
|
||||||
refs/heads/), remote refs (i.e. under refs/remotes/),
|
`refs/heads/`), remote refs (i.e. under `refs/remotes/`),
|
||||||
note refs (i.e. under refs/notes/), and the symbolic ref HEAD.
|
note refs (i.e. under `refs/notes/`), and the symbolic ref `HEAD`.
|
||||||
|
If it is set to `always`, then a missing reflog is automatically
|
||||||
|
created for any ref under `refs/`.
|
||||||
+
|
+
|
||||||
This information can be used to determine what commit
|
This information can be used to determine what commit
|
||||||
was the tip of a branch "2 days ago".
|
was the tip of a branch "2 days ago".
|
||||||
|
@ -91,6 +91,9 @@ OPTIONS
|
|||||||
based sha1 expressions such as "<branchname>@\{yesterday}".
|
based sha1 expressions such as "<branchname>@\{yesterday}".
|
||||||
Note that in non-bare repositories, reflogs are usually
|
Note that in non-bare repositories, reflogs are usually
|
||||||
enabled by default by the `core.logallrefupdates` config option.
|
enabled by default by the `core.logallrefupdates` config option.
|
||||||
|
The negated form `--no-create-reflog` only overrides an earlier
|
||||||
|
`--create-reflog`, but currently does not negate the setting of
|
||||||
|
`core.logallrefupdates`.
|
||||||
|
|
||||||
-f::
|
-f::
|
||||||
--force::
|
--force::
|
||||||
|
@ -150,7 +150,11 @@ This option is only applicable when listing tags without annotation lines.
|
|||||||
'strip' removes both whitespace and commentary.
|
'strip' removes both whitespace and commentary.
|
||||||
|
|
||||||
--create-reflog::
|
--create-reflog::
|
||||||
Create a reflog for the tag.
|
Create a reflog for the tag. To globally enable reflogs for tags, see
|
||||||
|
`core.logAllRefUpdates` in linkgit:git-config[1].
|
||||||
|
The negated form `--no-create-reflog` only overrides an earlier
|
||||||
|
`--create-reflog`, but currently does not negate the setting of
|
||||||
|
`core.logallrefupdates`.
|
||||||
|
|
||||||
<tagname>::
|
<tagname>::
|
||||||
The name of the tag to create, delete, or describe.
|
The name of the tag to create, delete, or describe.
|
||||||
|
2
branch.c
2
branch.c
@ -298,7 +298,7 @@ void create_branch(const char *name, const char *start_name,
|
|||||||
start_name);
|
start_name);
|
||||||
|
|
||||||
if (reflog)
|
if (reflog)
|
||||||
log_all_ref_updates = 1;
|
log_all_ref_updates = LOG_REFS_NORMAL;
|
||||||
|
|
||||||
if (!dont_change_ref) {
|
if (!dont_change_ref) {
|
||||||
struct ref_transaction *transaction;
|
struct ref_transaction *transaction;
|
||||||
|
@ -612,22 +612,25 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
|
|||||||
const char *old_desc, *reflog_msg;
|
const char *old_desc, *reflog_msg;
|
||||||
if (opts->new_branch) {
|
if (opts->new_branch) {
|
||||||
if (opts->new_orphan_branch) {
|
if (opts->new_orphan_branch) {
|
||||||
if (opts->new_branch_log && !log_all_ref_updates) {
|
char *refname;
|
||||||
|
|
||||||
|
refname = mkpathdup("refs/heads/%s", opts->new_orphan_branch);
|
||||||
|
if (opts->new_branch_log &&
|
||||||
|
!should_autocreate_reflog(refname)) {
|
||||||
int ret;
|
int ret;
|
||||||
char *refname;
|
|
||||||
struct strbuf err = STRBUF_INIT;
|
struct strbuf err = STRBUF_INIT;
|
||||||
|
|
||||||
refname = mkpathdup("refs/heads/%s", opts->new_orphan_branch);
|
|
||||||
ret = safe_create_reflog(refname, 1, &err);
|
ret = safe_create_reflog(refname, 1, &err);
|
||||||
free(refname);
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
fprintf(stderr, _("Can not do reflog for '%s': %s\n"),
|
fprintf(stderr, _("Can not do reflog for '%s': %s\n"),
|
||||||
opts->new_orphan_branch, err.buf);
|
opts->new_orphan_branch, err.buf);
|
||||||
strbuf_release(&err);
|
strbuf_release(&err);
|
||||||
|
free(refname);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
strbuf_release(&err);
|
strbuf_release(&err);
|
||||||
}
|
}
|
||||||
|
free(refname);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
create_branch(opts->new_branch, new->name,
|
create_branch(opts->new_branch, new->name,
|
||||||
|
@ -262,7 +262,7 @@ static int create_default_files(const char *template_path,
|
|||||||
const char *work_tree = get_git_work_tree();
|
const char *work_tree = get_git_work_tree();
|
||||||
git_config_set("core.bare", "false");
|
git_config_set("core.bare", "false");
|
||||||
/* allow template config file to override the default */
|
/* allow template config file to override the default */
|
||||||
if (log_all_ref_updates == -1)
|
if (log_all_ref_updates == LOG_REFS_UNSET)
|
||||||
git_config_set("core.logallrefupdates", "true");
|
git_config_set("core.logallrefupdates", "true");
|
||||||
if (needs_work_tree_config(original_git_dir, work_tree))
|
if (needs_work_tree_config(original_git_dir, work_tree))
|
||||||
git_config_set("core.worktree", work_tree);
|
git_config_set("core.worktree", work_tree);
|
||||||
|
9
cache.h
9
cache.h
@ -695,7 +695,6 @@ extern int minimum_abbrev, default_abbrev;
|
|||||||
extern int ignore_case;
|
extern int ignore_case;
|
||||||
extern int assume_unchanged;
|
extern int assume_unchanged;
|
||||||
extern int prefer_symlink_refs;
|
extern int prefer_symlink_refs;
|
||||||
extern int log_all_ref_updates;
|
|
||||||
extern int warn_ambiguous_refs;
|
extern int warn_ambiguous_refs;
|
||||||
extern int warn_on_object_refname_ambiguity;
|
extern int warn_on_object_refname_ambiguity;
|
||||||
extern const char *apply_default_whitespace;
|
extern const char *apply_default_whitespace;
|
||||||
@ -763,6 +762,14 @@ enum hide_dotfiles_type {
|
|||||||
};
|
};
|
||||||
extern enum hide_dotfiles_type hide_dotfiles;
|
extern enum hide_dotfiles_type hide_dotfiles;
|
||||||
|
|
||||||
|
enum log_refs_config {
|
||||||
|
LOG_REFS_UNSET = -1,
|
||||||
|
LOG_REFS_NONE = 0,
|
||||||
|
LOG_REFS_NORMAL,
|
||||||
|
LOG_REFS_ALWAYS
|
||||||
|
};
|
||||||
|
extern enum log_refs_config log_all_ref_updates;
|
||||||
|
|
||||||
enum branch_track {
|
enum branch_track {
|
||||||
BRANCH_TRACK_UNSPECIFIED = -1,
|
BRANCH_TRACK_UNSPECIFIED = -1,
|
||||||
BRANCH_TRACK_NEVER = 0,
|
BRANCH_TRACK_NEVER = 0,
|
||||||
|
7
config.c
7
config.c
@ -826,7 +826,12 @@ static int git_default_core_config(const char *var, const char *value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(var, "core.logallrefupdates")) {
|
if (!strcmp(var, "core.logallrefupdates")) {
|
||||||
log_all_ref_updates = git_config_bool(var, value);
|
if (value && !strcasecmp(value, "always"))
|
||||||
|
log_all_ref_updates = LOG_REFS_ALWAYS;
|
||||||
|
else if (git_config_bool(var, value))
|
||||||
|
log_all_ref_updates = LOG_REFS_NORMAL;
|
||||||
|
else
|
||||||
|
log_all_ref_updates = LOG_REFS_NONE;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,6 @@ int ignore_case;
|
|||||||
int assume_unchanged;
|
int assume_unchanged;
|
||||||
int prefer_symlink_refs;
|
int prefer_symlink_refs;
|
||||||
int is_bare_repository_cfg = -1; /* unspecified */
|
int is_bare_repository_cfg = -1; /* unspecified */
|
||||||
int log_all_ref_updates = -1; /* unspecified */
|
|
||||||
int warn_ambiguous_refs = 1;
|
int warn_ambiguous_refs = 1;
|
||||||
int warn_on_object_refname_ambiguity = 1;
|
int warn_on_object_refname_ambiguity = 1;
|
||||||
int ref_paranoia = -1;
|
int ref_paranoia = -1;
|
||||||
@ -64,6 +63,7 @@ int merge_log_config = -1;
|
|||||||
int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
|
int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
|
||||||
unsigned long pack_size_limit_cfg;
|
unsigned long pack_size_limit_cfg;
|
||||||
enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
|
enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
|
||||||
|
enum log_refs_config log_all_ref_updates = LOG_REFS_UNSET;
|
||||||
|
|
||||||
#ifndef PROTECT_HFS_DEFAULT
|
#ifndef PROTECT_HFS_DEFAULT
|
||||||
#define PROTECT_HFS_DEFAULT 0
|
#define PROTECT_HFS_DEFAULT 0
|
||||||
|
15
refs.c
15
refs.c
@ -638,12 +638,17 @@ int copy_reflog_msg(char *buf, const char *msg)
|
|||||||
|
|
||||||
int should_autocreate_reflog(const char *refname)
|
int should_autocreate_reflog(const char *refname)
|
||||||
{
|
{
|
||||||
if (!log_all_ref_updates)
|
switch (log_all_ref_updates) {
|
||||||
|
case LOG_REFS_ALWAYS:
|
||||||
|
return 1;
|
||||||
|
case LOG_REFS_NORMAL:
|
||||||
|
return starts_with(refname, "refs/heads/") ||
|
||||||
|
starts_with(refname, "refs/remotes/") ||
|
||||||
|
starts_with(refname, "refs/notes/") ||
|
||||||
|
!strcmp(refname, "HEAD");
|
||||||
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
return starts_with(refname, "refs/heads/") ||
|
}
|
||||||
starts_with(refname, "refs/remotes/") ||
|
|
||||||
starts_with(refname, "refs/notes/") ||
|
|
||||||
!strcmp(refname, "HEAD");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int is_branch(const char *refname)
|
int is_branch(const char *refname)
|
||||||
|
2
refs.h
2
refs.h
@ -64,6 +64,8 @@ int read_ref(const char *refname, unsigned char *sha1);
|
|||||||
|
|
||||||
int ref_exists(const char *refname);
|
int ref_exists(const char *refname);
|
||||||
|
|
||||||
|
int should_autocreate_reflog(const char *refname);
|
||||||
|
|
||||||
int is_branch(const char *refname);
|
int is_branch(const char *refname);
|
||||||
|
|
||||||
extern int refs_init_db(struct strbuf *err);
|
extern int refs_init_db(struct strbuf *err);
|
||||||
|
@ -2682,7 +2682,7 @@ static int files_rename_ref(struct ref_store *ref_store,
|
|||||||
}
|
}
|
||||||
|
|
||||||
flag = log_all_ref_updates;
|
flag = log_all_ref_updates;
|
||||||
log_all_ref_updates = 0;
|
log_all_ref_updates = LOG_REFS_NONE;
|
||||||
if (write_ref_to_lockfile(lock, orig_sha1, &err) ||
|
if (write_ref_to_lockfile(lock, orig_sha1, &err) ||
|
||||||
commit_ref_update(refs, lock, orig_sha1, NULL, &err)) {
|
commit_ref_update(refs, lock, orig_sha1, NULL, &err)) {
|
||||||
error("unable to write current sha1 into %s: %s", oldrefname, err.buf);
|
error("unable to write current sha1 into %s: %s", oldrefname, err.buf);
|
||||||
@ -2835,8 +2835,8 @@ static int log_ref_write_1(const char *refname, const unsigned char *old_sha1,
|
|||||||
{
|
{
|
||||||
int logfd, result, oflags = O_APPEND | O_WRONLY;
|
int logfd, result, oflags = O_APPEND | O_WRONLY;
|
||||||
|
|
||||||
if (log_all_ref_updates < 0)
|
if (log_all_ref_updates == LOG_REFS_UNSET)
|
||||||
log_all_ref_updates = !is_bare_repository();
|
log_all_ref_updates = is_bare_repository() ? LOG_REFS_NONE : LOG_REFS_NORMAL;
|
||||||
|
|
||||||
result = log_ref_setup(refname, logfile, err, flags & REF_FORCE_CREATE_REFLOG);
|
result = log_ref_setup(refname, logfile, err, flags & REF_FORCE_CREATE_REFLOG);
|
||||||
|
|
||||||
|
@ -133,8 +133,6 @@ int verify_refname_available(const char *newname,
|
|||||||
*/
|
*/
|
||||||
int copy_reflog_msg(char *buf, const char *msg);
|
int copy_reflog_msg(char *buf, const char *msg);
|
||||||
|
|
||||||
int should_autocreate_reflog(const char *refname);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Information needed for a single ref update. Set new_sha1 to the new
|
* Information needed for a single ref update. Set new_sha1 to the new
|
||||||
* value or to null_sha1 to delete the ref. To check the old value
|
* value or to null_sha1 to delete the ref. To check the old value
|
||||||
|
@ -8,23 +8,33 @@ test_description='Test git update-ref and basic ref logging'
|
|||||||
|
|
||||||
Z=$_z40
|
Z=$_z40
|
||||||
|
|
||||||
test_expect_success setup '
|
m=refs/heads/master
|
||||||
|
n_dir=refs/heads/gu
|
||||||
|
n=$n_dir/fixes
|
||||||
|
outside=refs/foo
|
||||||
|
bare=bare-repo
|
||||||
|
|
||||||
|
create_test_commits ()
|
||||||
|
{
|
||||||
|
prfx="$1"
|
||||||
for name in A B C D E F
|
for name in A B C D E F
|
||||||
do
|
do
|
||||||
test_tick &&
|
test_tick &&
|
||||||
T=$(git write-tree) &&
|
T=$(git write-tree) &&
|
||||||
sha1=$(echo $name | git commit-tree $T) &&
|
sha1=$(echo $name | git commit-tree $T) &&
|
||||||
eval $name=$sha1
|
eval $prfx$name=$sha1
|
||||||
done
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
test_expect_success setup '
|
||||||
|
create_test_commits "" &&
|
||||||
|
mkdir $bare &&
|
||||||
|
cd $bare &&
|
||||||
|
git init --bare &&
|
||||||
|
create_test_commits "bare" &&
|
||||||
|
cd -
|
||||||
'
|
'
|
||||||
|
|
||||||
m=refs/heads/master
|
|
||||||
n_dir=refs/heads/gu
|
|
||||||
n=$n_dir/fixes
|
|
||||||
outside=refs/foo
|
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
"create $m" \
|
"create $m" \
|
||||||
"git update-ref $m $A &&
|
"git update-ref $m $A &&
|
||||||
@ -93,6 +103,61 @@ test_expect_success 'update-ref creates reflogs with --create-reflog' '
|
|||||||
git reflog exists $outside
|
git reflog exists $outside
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'creates no reflog in bare repository' '
|
||||||
|
git -C $bare update-ref $m $bareA &&
|
||||||
|
git -C $bare rev-parse $bareA >expect &&
|
||||||
|
git -C $bare rev-parse $m >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
test_must_fail git -C $bare reflog exists $m
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'core.logAllRefUpdates=true creates reflog in bare repository' '
|
||||||
|
test_when_finished "git -C $bare config --unset core.logAllRefUpdates && \
|
||||||
|
rm $bare/logs/$m" &&
|
||||||
|
git -C $bare config core.logAllRefUpdates true &&
|
||||||
|
git -C $bare update-ref $m $bareB &&
|
||||||
|
git -C $bare rev-parse $bareB >expect &&
|
||||||
|
git -C $bare rev-parse $m >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
git -C $bare reflog exists $m
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'core.logAllRefUpdates=true does not create reflog by default' '
|
||||||
|
test_config core.logAllRefUpdates true &&
|
||||||
|
test_when_finished "git update-ref -d $outside" &&
|
||||||
|
git update-ref $outside $A &&
|
||||||
|
git rev-parse $A >expect &&
|
||||||
|
git rev-parse $outside >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
test_must_fail git reflog exists $outside
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'core.logAllRefUpdates=always creates reflog by default' '
|
||||||
|
test_config core.logAllRefUpdates always &&
|
||||||
|
test_when_finished "git update-ref -d $outside" &&
|
||||||
|
git update-ref $outside $A &&
|
||||||
|
git rev-parse $A >expect &&
|
||||||
|
git rev-parse $outside >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
git reflog exists $outside
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'core.logAllRefUpdates=always creates no reflog for ORIG_HEAD' '
|
||||||
|
test_config core.logAllRefUpdates always &&
|
||||||
|
git update-ref ORIG_HEAD $A &&
|
||||||
|
test_must_fail git reflog exists ORIG_HEAD
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success '--no-create-reflog overrides core.logAllRefUpdates=always' '
|
||||||
|
test_config core.logAllRefUpdates true &&
|
||||||
|
test_when_finished "git update-ref -d $outside" &&
|
||||||
|
git update-ref --no-create-reflog $outside $A &&
|
||||||
|
git rev-parse $A >expect &&
|
||||||
|
git rev-parse $outside >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
test_must_fail git reflog exists $outside
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
"create $m (by HEAD)" \
|
"create $m (by HEAD)" \
|
||||||
"git update-ref HEAD $A &&
|
"git update-ref HEAD $A &&
|
||||||
@ -501,6 +566,7 @@ test_expect_success 'stdin does not create reflogs by default' '
|
|||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'stdin creates reflogs with --create-reflog' '
|
test_expect_success 'stdin creates reflogs with --create-reflog' '
|
||||||
|
test_when_finished "git update-ref -d $outside" &&
|
||||||
echo "create $outside $m" >stdin &&
|
echo "create $outside $m" >stdin &&
|
||||||
git update-ref --create-reflog --stdin <stdin &&
|
git update-ref --create-reflog --stdin <stdin &&
|
||||||
git rev-parse $m >expect &&
|
git rev-parse $m >expect &&
|
||||||
|
@ -71,6 +71,7 @@ test_expect_success 'creating a tag for an unknown revision should fail' '
|
|||||||
|
|
||||||
# commit used in the tests, test_tick is also called here to freeze the date:
|
# commit used in the tests, test_tick is also called here to freeze the date:
|
||||||
test_expect_success 'creating a tag using default HEAD should succeed' '
|
test_expect_success 'creating a tag using default HEAD should succeed' '
|
||||||
|
test_config core.logAllRefUpdates true &&
|
||||||
test_tick &&
|
test_tick &&
|
||||||
echo foo >foo &&
|
echo foo >foo &&
|
||||||
git add foo &&
|
git add foo &&
|
||||||
@ -90,6 +91,13 @@ test_expect_success '--create-reflog does not create reflog on failure' '
|
|||||||
test_must_fail git reflog exists refs/tags/mytag
|
test_must_fail git reflog exists refs/tags/mytag
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'option core.logAllRefUpdates=always creates reflog' '
|
||||||
|
test_when_finished "git tag -d tag_with_reflog" &&
|
||||||
|
test_config core.logAllRefUpdates always &&
|
||||||
|
git tag tag_with_reflog &&
|
||||||
|
git reflog exists refs/tags/tag_with_reflog
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'listing all tags if one exists should succeed' '
|
test_expect_success 'listing all tags if one exists should succeed' '
|
||||||
git tag -l &&
|
git tag -l &&
|
||||||
git tag
|
git tag
|
||||||
|
Reference in New Issue
Block a user