Skip to content

Commit

Permalink
Be more careful about updating refs
Browse files Browse the repository at this point in the history
This makes write_ref_sha1() more careful: it actually checks the SHA1 of
the ref it is updating, and refuses to update a ref with an object that it
cannot find.

Perhaps more importantly, it also refuses to update a branch head with a
non-commit object. I don't quite know *how* the stable series maintainers
were able to corrupt their repository to have a HEAD that pointed to a tag
rather than a commit object, but they did. Which results in a totally
broken repository that cannot be cloned or committed on.

So make it harder for people to shoot themselves in the foot like that.

The test t1400-update-ref.sh is fixed at the same time, as it
assumed that the commands involved in the particular test would
not care about corrupted repositories whose refs point at
nonexistant bogus objects.  That assumption does not hold true
anymore.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Linus Torvalds authored and Junio C Hamano committed Jan 16, 2008
1 parent 9f6fe82 commit c3b0dec
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 6 deletions.
19 changes: 19 additions & 0 deletions refs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1119,17 +1119,36 @@ static int log_ref_write(const char *ref_name, const unsigned char *old_sha1,
return 0;
}

static int is_branch(const char *refname)
{
return !strcmp(refname, "HEAD") || !prefixcmp(refname, "refs/heads/");
}

int write_ref_sha1(struct ref_lock *lock,
const unsigned char *sha1, const char *logmsg)
{
static char term = '\n';
struct object *o;

if (!lock)
return -1;
if (!lock->force_write && !hashcmp(lock->old_sha1, sha1)) {
unlock_ref(lock);
return 0;
}
o = parse_object(sha1);
if (!o) {
error("Trying to write ref %s with nonexistant object %s",
lock->ref_name, sha1_to_hex(sha1));
unlock_ref(lock);
return -1;
}
if (o->type != OBJ_COMMIT && is_branch(lock->ref_name)) {
error("Trying to write non-commit object %s to branch %s",
sha1_to_hex(sha1), lock->ref_name);
unlock_ref(lock);
return -1;
}
if (write_in_full(lock->lock_fd, sha1_to_hex(sha1), 40) != 40 ||
write_in_full(lock->lock_fd, &term, 1) != 1
|| close(lock->lock_fd) < 0) {
Expand Down
19 changes: 13 additions & 6 deletions t/t1400-update-ref.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,19 @@ test_description='Test git update-ref and basic ref logging'
. ./test-lib.sh

Z=0000000000000000000000000000000000000000
A=1111111111111111111111111111111111111111
B=2222222222222222222222222222222222222222
C=3333333333333333333333333333333333333333
D=4444444444444444444444444444444444444444
E=5555555555555555555555555555555555555555
F=6666666666666666666666666666666666666666

test_expect_success setup '
for name in A B C D E F
do
test_tick &&
T=$(git write-tree) &&
sha1=$(echo $name | git commit-tree $T) &&
eval $name=$sha1
done
'

m=refs/heads/master
n_dir=refs/heads/gu
n=$n_dir/fixes
Expand Down

0 comments on commit c3b0dec

Please sign in to comment.