-
Notifications
You must be signed in to change notification settings - Fork 165
[GSoC] receive.denyCurrentBranch: respect all worktrees #535
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
Conversation
dscho
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you get a chance to investigate why t5516.93 receive.denyCurrentBranch = updateInstead and t5516.94 updateInstead with push-to-checkout hook fail?
|
In this comment, I had also suggested to look for a test case to imitate. I see that you did not do that yet. So let me guide you a little more closely here: $ git grep -i denycurrentbranch upstream/master -- t/
upstream/master:t/t5400-send-pack.sh: ( cd victim && git config receive.denyCurrentBranch warn && git log ) &&
upstream/master:t/t5400-send-pack.sh: git config receive.denyCurrentBranch warn &&
upstream/master:t/t5405-send-pack-rewind.sh: git config receive.denyCurrentBranch warn &&
upstream/master:t/t5507-remote-environment.sh:# due to receive.denyCurrentBranch=true
upstream/master:t/t5507-remote-environment.sh: test_must_fail git -c receive.denyCurrentBranch=false push remote
upstream/master:t/t5507-remote-environment.sh: test_must_fail git -c receive.denyCurrentBranch=false push host:remote
upstream/master:t/t5516-fetch-push.sh: git config receive.denyCurrentBranch warn &&
upstream/master:t/t5516-fetch-push.sh: git config receive.denyCurrentBranch warn
upstream/master:t/t5516-fetch-push.sh: git config receive.denyCurrentBranch true
upstream/master:t/t5516-fetch-push.sh: git config receive.denyCurrentBranch true &&
upstream/master:t/t5516-fetch-push.sh: git config receive.denyCurrentBranch false
upstream/master:t/t5516-fetch-push.sh: git config receive.denyCurrentBranch false
upstream/master:t/t5516-fetch-push.sh: git config receive.denyCurrentBranch false
upstream/master:t/t5516-fetch-push.sh: git config receive.denyCurrentBranch true) &&
upstream/master:t/t5516-fetch-push.sh: git config receive.denyCurrentBranch true) &&
upstream/master:t/t5516-fetch-push.sh:test_expect_success 'receive.denyCurrentBranch = updateInstead' '
upstream/master:t/t5516-fetch-push.sh: git config receive.denyCurrentBranch updateInstead
upstream/master:t/t5516-fetch-push.sh: git config receive.denyCurrentBranch updateInstead
upstream/master:t/t5516-fetch-push.sh: git config receive.denyCurrentBranch updateInstead &&
upstream/master:t/t5516-fetch-push.sh: git config receive.denyCurrentBranch updateInstead &&
upstream/master:t/t5517-push-mirror.sh: git config receive.denyCurrentBranch warn
upstream/master:t/t5522-pull-symlink.sh: git config receive.denyCurrentBranch warn
upstream/master:t/t5522-pull-symlink.sh: git config receive.denyCurrentBranch warn
upstream/master:t/t5543-atomic-push.sh: git config receive.denyCurrentBranch warn
upstream/master:t/t5545-push-options.sh: git config receive.denyCurrentBranch warn &&
upstream/master:t/t5605-clone-local.sh: git config receive.denyCurrentBranch warn) &&There are a lot of hits, and the However, what you want to do is to initialize a worktree with a new branch, then clone into a separate worktree (probably with |
I fricking appreciate it...
I'm on it, senpai !!! |
I need to edit this one?? Also, is there any way to check why my test failed (error message or something). |
Copy-edit it, or maybe just imitate it and add a new one. Like,
|
BTW that one seems to fail with your patch. Have you analyzed the difference in the output of |
Yep, this is the output after patch applied. During execution of this command |
I don't think so. It tries to push into If I were you, I would instrument the code both before and after the patch to show a bit more, e.g. inserting |
Before the patch applied: After the patch applied: Still, I'm unable to figure the things out. |
|
Sounds like the worktree path is wrong: if This looks like it might be a bug in |
How should I proceed further? |
Investigate why the Git directory is mistaken for a worktree? |
So, now I'm left with test ? |
|
Woot, the PR build passed!
Yep. This is roughly how it should start: test_expect_success 'denyCurrentBranch and worktrees' '
git worktree add -b new-wt &&
git clone . cloned &&
[...](Those lines already implement the first two bullet points, hopefully illustrating the idea.) |
|
I'm really having a hard time while writing test for this. I tried many other ways, but still unable to figure things out. where did I go wrong? |
That's a pretty good start already! Only a couple changes are necessary:
|
|
Oh, also: you will want to use |
push is still passing even after pushing with Here are the logs: |
Good thing we have that regression test to catch this, eh? The next step is to instrument the code (i.e. to insert debug print statements) to figure out what is going wrong, or maybe to debug interactively. I fear that we cannot really debug interactively in this instance because the |
|
The work-in-progress diff would look somewhat like this: diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 3f8b4e5c904..eb473905270 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -1003,12 +1003,14 @@ static const char *update_worktree(unsigned char *sha1, const struct worktree *w
const char *retval, *work_tree, *git_dir = NULL;
struct argv_array env = ARGV_ARRAY_INIT;
+error("worktree: %p (path: %s)", worktree, worktree ? worktree->path : "(none)");
if (worktree && worktree->path)
work_tree = worktree->path;
else if (git_work_tree_cfg)
work_tree = git_work_tree_cfg;
else
work_tree = "..";
+error("work_tree: %s", work_tree);
if (is_bare_repository())
return "denyCurrentBranch = updateInstead needs a worktree";
@@ -1017,6 +1019,7 @@ static const char *update_worktree(unsigned char *sha1, const struct worktree *w
git_dir = get_worktree_git_dir(worktree);
if (!git_dir)
git_dir = get_git_dir();
+error("git_dir: %s", git_dir);
argv_array_pushf(&env, "GIT_DIR=%s", absolute_path(git_dir));
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index c81ca360ac4..2642212d330 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -130,6 +130,16 @@ test_expect_success setup '
'
+test_expect_success 'denyCurrentBranch and worktrees' '
+ git worktree add new-wt &&
+ git clone . cloned &&
+ test_commit -C cloned first &&
+ test_config receive.denyCurrentBranch refuse &&
+ test_must_fail git -C cloned push origin HEAD:new-wt &&
+ test_config receive.denyCurrentBranch updateInstead &&
+ git -C cloned push origin HEAD:new-wt
+'
+
test_expect_success 'fetch without wildcard' '
mk_empty testrepo &&
(And to accelerate the edit/build/run loop, I would run t5516 once, then run only the failing command (after resetting the git -C ./trash\ directory.t5516-fetch-push/new-wt/ reset --hard master &&
../git --exec-path=$PWD/.. -C ./trash\ directory.t5516-fetch-push/cloned/ push origin HEAD:new-wtI use multiple tricks here to make this (manual) loop more efficient:
To make things a bit more convenient yet, I can prefix those two commands with However, my first attempt to actually run this looks a bit funny because none of the stuff is actually printed... |
Aha! I added two more debug print statements, one in diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 3f8b4e5c904..e31c424b6af 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -1003,12 +1003,14 @@ static const char *update_worktree(unsigned char *sha1, const struct worktree *w
const char *retval, *work_tree, *git_dir = NULL;
struct argv_array env = ARGV_ARRAY_INIT;
+error("worktree: %p (path: %s)", worktree, worktree ? worktree->path : "(none)");
if (worktree && worktree->path)
work_tree = worktree->path;
else if (git_work_tree_cfg)
work_tree = git_work_tree_cfg;
else
work_tree = "..";
+error("work_tree: %s", work_tree);
if (is_bare_repository())
return "denyCurrentBranch = updateInstead needs a worktree";
@@ -1017,6 +1019,7 @@ static const char *update_worktree(unsigned char *sha1, const struct worktree *w
git_dir = get_worktree_git_dir(worktree);
if (!git_dir)
git_dir = get_git_dir();
+error("git_dir: %s", git_dir);
argv_array_pushf(&env, "GIT_DIR=%s", absolute_path(git_dir));
@@ -1049,6 +1052,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
free(namespaced_name);
namespaced_name = strbuf_detach(&namespaced_name_buf, NULL);
+error("%s:%d HERE: is_ref_checked_out says %d", __FILE__, __LINE__, is_ref_checked_out(namespaced_name));
if (is_ref_checked_out(namespaced_name)) {
switch (deny_current_branch) {
case DENY_IGNORE:
@@ -1952,6 +1956,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
OPT_END()
};
+error("%s:%d: HERE", __FILE__, __LINE__);
packet_trace_identity("receive-pack");
argc = parse_options(argc, argv, prefix, options, receive_pack_usage, 0);And I do see this in the output: Which means that Instead of asking Of course, this was the only caller of worktree = is_bare_repository() ? NULL : find_shared_symref("HEAD", name);I also cannot fail to notice that the Finally, I looked around whether - if (head_name && !strcmp(namespaced_name, head_name)) {
+ if (worktree || (head_name && !strcmp(namespaced_name, head_name))) {and then we definitely want to test for that, too, e.g. via test_must_fail git -C cloned push --delete origin new-wt |
|
This patch series was integrated into pu via git@ced34bb. |
OutputWith current changes Without this patch |
|
All I need to do in this test is to compare output of |
|
What Eric suggested will also produce the same output as current changes. |
|
This patch series was integrated into pu via git@32e8f7f. |
|
This patch series was integrated into next via git@84e35c4. |
Would it not be enough to just call |
|
This patch series was integrated into pu via git@4c19b1b. |
|
Hrm. Since this was already merged to |
got it
Means opening another PR (based on next) and submit ? |
|
This patch series was integrated into pu via git@ef4d67c. |
|
I would target not |
(back on a device with a proper keyboard) What I meant was this comment by the
In essence, I would suggest to add the remote |
this will do the job ? |
I don't actually think so... First of all, you do not need to initialize a new repository. That's just wasteful. Just use the one in Second, you do not even need a new worktree to reproduce the bug, so why add one? All you need to do is to list the worktrees when the current working directory is inside the gitdir, i.e. Lastly, I guess the best way forward is to verify that |
+1
I guess that's not the case here. Indeed
We can go this way too. |
|
My bad, missed the |
that will suffice ? 🤔 |
|
Yep :-) |
I've added test to 3rd last commit. |
Your branch is already in git remote add gitgitgadget https://github.com/gitgitgadget/git
git fetch gitgitgadget hv/receive-denycurrent-everywhere
git switch -c verify-get_main_worktree-fix gitgitgadget/hv/receive-denycurrent-everywhereand then cherry-pick the previous commit via Technically, you only want the test part of that commit. However, the rest of the commit is already applied in that branch, so the cherry-pick will end up having only the test. You will then need to amend the commit message to reflect that you're only adding the forgotten test, and then open a new PR. |
|
Superseded by #570 |
|
This patch series was integrated into pu via git@a258e25. |
|
This patch series was integrated into pu via git@4a2e91d. |
|
This patch series was integrated into master via git@4a2e91d. |
|
Closed via 4a2e91d. |
The receive.denyCurrentBranch config option controls what happens if
you push to a branch that is checkout into a non-bare repository.
By default, it rejects it. It can be disabled via
ignoreorwarn.Another yet trickier option is
updateInstead.When receive.denyCurrentBranch is set to updateInstead, a push that
tries to update the branch that is currently checked out is accepted only
when the index and the working tree exactly matches the currently
checked out commit, in which case the index and the working tree are
updated to match the pushed commit. Otherwise, the push is refused.
However, this setting was forgotten when the git worktree command was
introduced: only the main worktree's current branch is respected.
[ fixes: #331 ]
Incidently, this change also fixes another bug
i.e.
receive.denyCurrentBranch = truewas ignored when pushing into anon-bare repository using ref namespaces.
Thanks, @dscho for helping me out.
Regards,
Hariom