Description
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