Skip to content

Git::Branch function update_ref doesn't work as expected #599

Closed
@mblythe86

Description

@mblythe86

Subject of the issue

Git::Branch#update_ref creates the wrong ref name, resulting in "refname is ambiguous" warnings.

Your environment

  • git 2.16.2
  • ruby 2.3.1
  • ruby-git 1.12.0

Steps to reproduce

require 'git'
git = Git.init
File.write('foo','rev 1')
git.add('foo')
git.commit('rev 1')
git.branch('testing').create
puts "HEAD", git.revparse('HEAD')
puts "testing", git.revparse('testing')
puts "refs/heads/testing", git.revparse('refs/heads/testing')
puts "\n\n"
File.write('foo','rev 2')
git.add('foo')
git.commit('rev 2')
git.branch('testing').update_ref(git.revparse('HEAD'))
puts "HEAD", git.revparse('HEAD')
puts "testing", git.revparse('testing')
puts "refs/heads/testing", git.revparse('refs/heads/testing')

Expected behaviour

I'd expect git.branch('testing').update_ref(<HASH>) to behave the same as git branch -f testing <HASH> from the command line.

If that were the case, the code above should print the following (sha values may vary):

HEAD
2a0b5b7b...
testing
2a0b5b7b...
refs/heads/testing
2a0b5b7b...

HEAD
decf91cb...
testing
decf91cb...
refs/heads/testing
decf91cb...

Actual behaviour

The code above prints this:

HEAD
2a0b5b7b...
testing
2a0b5b7b...
refs/heads/testing
2a0b5b7b...

HEAD
decf91cb...
testing
warning: refname 'testing' is ambiguous.
decf91cb...
refs/heads/testing
2a0b5b7b...

It looks like instead of updating the file .git/refs/heads/testing with the new hash, instead the call to update_ref() creates a new file .git/testing with the new hash.

Discussion

For reference, this is the current implementation of Git::Branch#update_ref:

def update_ref(commit)
  @base.lib.update_ref(@full, commit)
end

And this is the implementation of Git::Lib#update_ref that it's calling:

def update_ref(branch, commit)
  command('update-ref', [branch, commit])
end

I think the branch naming of that function argument is problematic, since it just passes through to the git update-ref command, which accepts a 'ref' as an argument, not a branch name. If we really intend for that function to accept a branch name, then the implementation should probably change to prepend refs/heads/ before calling the command. However, this makes the behavior of the function diverge from the behavior of the command, which is probably undesirable.

With that in mind, I think the fix needs to happen in Git::Branch#update_ref to call Git::Lib#update_ref with the right ref name instead of just using the 'full branch' name.

Recommendation

Git::Branch#update_ref:

def update_ref(commit)
  if @remote
    @base.lib.update_ref("refs/remotes/#{@remote.name}/#{@name}", commit)
  else
    @base.lib.update_ref("refs/heads/#{@name}", commit)
  end
end

Git::Lib#update_ref:

def update_ref(ref, commit)
  command('update-ref', [ref, commit])
end

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions