Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Throw error on aborted rebase #19651

Merged
merged 7 commits into from
Jan 6, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 74 additions & 33 deletions base/libgit2/libgit2.jl
Original file line number Diff line number Diff line change
Expand Up @@ -386,51 +386,91 @@ function merge!(repo::GitRepo;
merge_opts::MergeOptions = MergeOptions(),
checkout_opts::CheckoutOptions = CheckoutOptions())
# merge into head branch
with(head(repo)) do head_ref
upst_anns = if !isempty(committish) # merge committish into HEAD
if committish == Consts.FETCH_HEAD # merge FETCH_HEAD
fheads = fetchheads(repo)
filter!(fh->fh.ismerge, fheads)
if isempty(fheads)
throw(GitError(Error.Merge, Error.ERROR,
"There is no fetch reference for this branch."))
end
map(fh->GitAnnotated(repo,fh), fheads)
else # merge commitish
[GitAnnotated(repo, committish)]
upst_anns = if !isempty(committish) # merge committish into HEAD
if committish == Consts.FETCH_HEAD # merge FETCH_HEAD
fheads = fetchheads(repo)
filter!(fh->fh.ismerge, fheads)
if isempty(fheads)
throw(GitError(Error.Merge, Error.ERROR,
"There is no fetch reference for this branch."))
end
else
if !isempty(branch) # merge provided branch into HEAD
with(GitReference(repo, branch)) do brn_ref
[GitAnnotated(repo, brn_ref)]
map(fh->GitAnnotated(repo,fh), fheads)
else # merge commitish
[GitAnnotated(repo, committish)]
end
else
if !isempty(branch) # merge provided branch into HEAD
with(GitReference(repo, branch)) do brn_ref
[GitAnnotated(repo, brn_ref)]
end
else # try to get tracking remote branch for the head
if !isattached(repo)
throw(GitError(Error.Merge, Error.ERROR,
"Repository HEAD is detached. Remote tracking branch cannot be used."))
end
if isorphan(repo)
# this isn't really a merge, but really moving HEAD
# https://github.com/libgit2/libgit2/issues/2135#issuecomment-35997764
# try to figure out remote tracking of orphan head

m = with(GitReference(repo, Consts.HEAD_FILE)) do head_sym_ref
match(r"refs/heads/(.*)", fullname(head_sym_ref))
end
else # try to get tracking remote branch for the head
if !isattached(repo)
if m === nothing
throw(GitError(Error.Merge, Error.ERROR,
"Repository HEAD is detached. Remote tracking branch cannot be used."))
"Unable to determine name of orphan branch."))
end
branchname = m.captures[1]
remotename = with(GitConfig, repo) do cfg
LibGit2.get(String, cfg, "branch.$branchname.remote")
end
obj = with(GitReference(repo, "refs/remotes/$remotename/$branchname")) do ref
LibGit2.Oid(ref)
end
with(get(GitCommit, repo, obj)) do cmt
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have you been able to come up with any scheme or logic for when and what needs management like this?

Copy link
Contributor Author

@simonbyrne simonbyrne Dec 20, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It happens in our tests: basically whenever you clone a repository without any commits.

LibGit2.create_branch(repo, branchname, cmt)
end
with(upstream(head_ref)) do tr_brn_ref
if tr_brn_ref === nothing
throw(GitError(Error.Merge, Error.ERROR,
"There is no tracking information for the current branch."))
return true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

was newbase not hooked up at all?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

guess we should add that to the list in #19839 since it would be a useful feature to have at some point

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point.

else
with(head(repo)) do head_ref
with(upstream(head_ref)) do tr_brn_ref
if tr_brn_ref === nothing
throw(GitError(Error.Merge, Error.ERROR,
"There is no tracking information for the current branch."))
end
[GitAnnotated(repo, tr_brn_ref)]
end
[GitAnnotated(repo, tr_brn_ref)]
end
end
end
end

try
merge!(repo, upst_anns, fastforward,
merge_opts=merge_opts,
checkout_opts=checkout_opts)
finally
map(finalize, upst_anns)
end
try
merge!(repo, upst_anns, fastforward,
merge_opts=merge_opts,
checkout_opts=checkout_opts)
finally
map(finalize, upst_anns)
end
end

""" git rebase --merge [--onto <newbase>] [<upstream>] """
function rebase!(repo::GitRepo, upstream::AbstractString="", newbase::AbstractString="")
"""
LibGit2.rebase!(repo::GitRepo[, upstream::AbstractString])

Attempt an automatic merge rebase of the current branch, from `upstream` if provided, or
otherwise from the upstream tracking branch.

If any conflicts arise which cannot be automatically resolved, the rebase will abort,
leaving the repository and working tree in its original state, and the function will throw
a `GitError`. This is roughly equivalent to the following command line statement:

git rebase --merge [<upstream>]
if [ -d ".git/rebase-merge" ]; then
git rebase --abort
fi

"""
function rebase!(repo::GitRepo, upstream::AbstractString="")
with(head(repo)) do head_ref
head_ann = GitAnnotated(repo, head_ref)
upst_ann = if isempty(upstream)
Expand All @@ -455,6 +495,7 @@ function rebase!(repo::GitRepo, upstream::AbstractString="", newbase::AbstractSt
finish(rbs, sig)
catch err
abort(rbs)
rethrow(err)
finally
finalize(rbs)
end
Expand Down
12 changes: 12 additions & 0 deletions base/libgit2/reference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,18 @@ function GitReference(repo::GitRepo, obj_oid::Oid, refname::AbstractString = Con
return GitReference(ref_ptr_ptr[])
end

"""
LibGit2.isorphan(repo::GitRepo)

Checks if the current branch is an "orphan" branch, i.e. has no commits. The first commit
to this branch will have no parents.
"""
function isorphan(repo::GitRepo)
r = @check ccall((:git_repository_head_unborn, :libgit2), Cint,
(Ptr{Void},), repo.ptr)
r != 0
end

function head(repo::GitRepo)
head_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
@check ccall((:git_repository_head, :libgit2), Cint,
Expand Down
4 changes: 3 additions & 1 deletion test/libgit2.jl
Original file line number Diff line number Diff line change
Expand Up @@ -242,11 +242,12 @@ mktempdir() do dir
end
end
@testset "normal" begin
repo = LibGit2.clone(cache_repo, test_repo, remote_cb = LibGit2.mirror_cb())
repo = LibGit2.clone(cache_repo, test_repo)
try
@test isdir(test_repo)
@test isdir(joinpath(test_repo, ".git"))
@test LibGit2.isattached(repo)
@test LibGit2.isorphan(repo)
finally
finalize(repo)
end
Expand Down Expand Up @@ -460,6 +461,7 @@ mktempdir() do dir

# Try rebasing on master instead
LibGit2.rebase!(repo, master_branch)
@test LibGit2.head_oid(repo) == head_oid

# Switch to the master branch
LibGit2.branch!(repo, master_branch)
Expand Down