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

git_push() silently succeeds with protected branches, expecting failure #236

Open
krlmlr opened this issue Aug 18, 2024 · 5 comments
Open

Comments

@krlmlr
Copy link
Member

krlmlr commented Aug 18, 2024

Add a ruleset indicating that a status check must pass, or that PRs are required, for the main branch. Then:

gert::git_push()

info <- gert::git_info()
info$commit
#> [1] "0df1ef7c90ef5d4aa939e0d1aea56ab130d50d17"
gert::git_commit_id(info$upstream)
#> [1] "81680ff5d1608d1f64688e29c2852b41351b8fdb"

Created on 2024-08-18 with reprex v2.1.0

In interactive mode (can't reprex), I'm seeing:

d> gert::git_push()
Trying to authenticate 'git' using ssh-agent...
[status] refs/heads/main: push declined due to repository rule violations

I can work around by checking if <remote>/<branch> is the same as the local branch, but it would be better IMO if git_push() did that for me.

@jeroen
Copy link
Member

jeroen commented Aug 18, 2024

Is this something that can be done with libgit2? https://libgit2.org/libgit2/#HEAD/search

@krlmlr
Copy link
Member Author

krlmlr commented Aug 18, 2024

Pushing a conflicting commit fails, but not with the technology GitHub uses (perhaps some hook on the remote repo?).

# Demo for failing push with conflicts
system("git init --bare remote-repo")
system("git clone remote-repo local-repo")
system("git -C local-repo commit --allow-empty -m 'Initial commit'")
system("git -C local-repo push")

system("git clone remote-repo local-repo2")

writeLines("This is a test file", "local-repo/test.txt")
system("git -C local-repo add test.txt")
system("git -C local-repo commit -m 'Add test file'")
system("git -C local-repo push")

writeLines("This is a conflicting test file", "local-repo2/test.txt")
system("git -C local-repo2 add test.txt")
system("git -C local-repo2 commit -m 'Add conflicting test file'")

# Fails
system("git -C local-repo2 push", intern = TRUE)
#> Warning in system("git -C local-repo2 push", intern = TRUE): running command
#> 'git -C local-repo2 push' had status 1
#> character(0)
#> attr(,"status")
#> [1] 1

# Fails too
withr::with_dir("local-repo2", gert::git_push())
#> Error in libgit2::git_remote_push: cannot push because a reference that you are trying to update on the remote contains commits that are not present locally.

Created on 2024-08-18 with reprex v2.1.0

@krlmlr
Copy link
Member Author

krlmlr commented Aug 18, 2024

I don't know too much about libgit2 to be helpful here, but could the above example be extended by such a hook in the remote repo?

@krlmlr
Copy link
Member Author

krlmlr commented Aug 18, 2024

Perhaps "Server-side hooks" in https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks ?

@krlmlr
Copy link
Member Author

krlmlr commented Aug 19, 2024

It's interesting that I can't even create an example with gert and hooks, these seem to be circumvented:

# Demo for failing push with conflicts
unlink("remote-repo", recursive = TRUE, force = TRUE)
unlink("local-repo", recursive = TRUE, force = TRUE)

run <- function(cmd, args) {
  invisible(processx::run(cmd, args, echo = TRUE))
}

run("git", c("init", "--bare", "remote-repo"))
#> Initialized empty Git repository in /private/var/folders/dj/yhk9rkx97wn_ykqtnmk18xvc0000gn/T/RtmpnNkFOo/reprex-c4aa7a5fbe6e-stout-scaup/remote-repo/
run("git", c("clone", "remote-repo", "local-repo"))
#> Cloning into 'local-repo'...
#> warning: You appear to have cloned an empty repository.
#> done.
run("git", c("-C", "local-repo", "commit", "--allow-empty", "-m", "Initial commit"))
#> [main (root-commit) 4cfc8d2] Initial commit
run("git", c("-C", "local-repo", "push", "-u", "origin", "HEAD"))
#> To /private/var/folders/dj/yhk9rkx97wn_ykqtnmk18xvc0000gn/T/RtmpnNkFOo/reprex-c4aa7a5fbe6e-stout-scaup/remote-repo
#>  * [new branch]      HEAD -> main
#> branch 'main' set up to track 'origin/main'.

writeLines(c("#!/bin/sh", "exit 1"), "remote-repo/hooks/update")
Sys.chmod("remote-repo/hooks/update", mode = as.octmode("755"))

writeLines("This is a test file", "local-repo/test.txt")
run("git", c("-C", "local-repo", "add", "test.txt"))
run("git", c("-C", "local-repo", "commit", "-m", "Add test file"))
#> [main d37ccf9] Add test file
#>  1 file changed, 1 insertion(+)
#>  create mode 100644 test.txt

# Fails as expected
run("git", c("-C", "local-repo", "push"))
#> remote: error: hook declined to update refs/heads/main        
#> To /private/var/folders/dj/yhk9rkx97wn_ykqtnmk18xvc0000gn/T/RtmpnNkFOo/reprex-c4aa7a5fbe6e-stout-scaup/remote-repo
#>  ! [remote rejected] main -> main (hook declined)
#> error: failed to push some refs to '/private/var/folders/dj/yhk9rkx97wn_ykqtnmk18xvc0000gn/T/RtmpnNkFOo/reprex-c4aa7a5fbe6e-stout-scaup/remote-repo'
#> Error in "processx::run(cmd, args, echo = TRUE)": ! System command 'git' failed

# Succeeds
withr::with_dir("local-repo", gert::git_push())

# WAT?
run("git", c("-C", "local-repo", "push"))
#> Everything up-to-date

Created on 2024-08-19 with reprex v2.1.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants