public inbox for git@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] restore: allow --staged on unborn branch
@ 2024-02-06 23:03 Ghanshyam Thakkar
  2024-02-07 16:06 ` Junio C Hamano
  0 siblings, 1 reply; 3+ messages in thread
From: Ghanshyam Thakkar @ 2024-02-06 23:03 UTC (permalink / raw)
  To: git; +Cc: Ghanshyam Thakkar

Some users expect that being on an unborn branch is similar to having an
empty tree checked out. However, when running "git restore --staged ."
on unborn branch having staged changes, the follwing error gets printed,

    fatal: could not resolve HEAD

Therefore, teach "git restore --staged ." without a source option, to
take empty tree as source on unborn branch. Note that, this assumption
is already taken by "git reset" (166ec2e9). However, still disallow
explicitly referring to HEAD on unborn branch.

Signed-off-by: Ghanshyam Thakkar <shyamthakkar001@gmail.com>
---
 builtin/checkout.c        | 27 +++++++++++++++++++-------
 t/t2073-restore-unborn.sh | 40 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 60 insertions(+), 7 deletions(-)
 create mode 100755 t/t2073-restore-unborn.sh

diff --git a/builtin/checkout.c b/builtin/checkout.c
index a6e30931b5..1258ae0a59 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -1691,6 +1691,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
 			 struct branch_info *new_branch_info)
 {
 	int parseopt_flags = 0;
+	int unborn_and_unspecified = 0;
 
 	opts->overwrite_ignore = 1;
 	opts->prefix = prefix;
@@ -1754,12 +1755,6 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
 	}
 	if (opts->checkout_index < 0 || opts->checkout_worktree < 0)
 		BUG("these flags should be non-negative by now");
-	/*
-	 * convenient shortcut: "git restore --staged [--worktree]" equals
-	 * "git restore --staged [--worktree] --source HEAD"
-	 */
-	if (!opts->from_treeish && opts->checkout_index)
-		opts->from_treeish = "HEAD";
 
 	/*
 	 * From here on, new_branch will contain the branch to be checked out,
@@ -1785,6 +1780,18 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
 		opts->new_branch = argv0 + 1;
 	}
 
+	/*
+	 * convenient shortcut: "git restore --staged [--worktree]" equals
+	 * "git restore --staged [--worktree] --source HEAD"
+	 */
+	if (!opts->from_treeish && opts->checkout_index) {
+		struct object_id oid;
+		opts->from_treeish = "HEAD";
+
+		if(repo_get_oid(the_repository, opts->from_treeish, &oid))
+			unborn_and_unspecified = 1;
+	}
+
 	/*
 	 * Extract branch name from command line arguments, so
 	 * all that is left is pathspecs.
@@ -1812,7 +1819,13 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
 	} else if (!opts->accept_ref && opts->from_treeish) {
 		struct object_id rev;
 
-		if (repo_get_oid_mb(the_repository, opts->from_treeish, &rev))
+		/*
+		 * when the branch is unborn and no revision is given, use
+		 * empty tree as source
+		 */
+		if(unborn_and_unspecified)
+			oidcpy(&rev, the_hash_algo->empty_tree);
+		else if (repo_get_oid_mb(the_repository, opts->from_treeish, &rev))
 			die(_("could not resolve %s"), opts->from_treeish);
 
 		setup_new_branch_info_and_source_tree(new_branch_info,
diff --git a/t/t2073-restore-unborn.sh b/t/t2073-restore-unborn.sh
new file mode 100755
index 0000000000..fbd8b2df5f
--- /dev/null
+++ b/t/t2073-restore-unborn.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+test_description='restore --staged should work on unborn branch'
+. ./test-lib.sh
+
+test_expect_success 'explicitly naming HEAD on unborn should fail' '
+	echo a >foo &&
+	echo b >bar &&
+	git add foo bar &&
+	test_must_fail git restore --staged --source=HEAD .
+'
+
+test_expect_success 'restore --staged .' '
+	rm .git/index &&
+	git add foo bar &&
+	git restore --staged . &&
+	git diff --cached --name-only >actual &&
+	test_must_be_empty actual
+'
+
+test_expect_success 'restore --staged $file' '
+	rm .git/index &&
+	git add foo bar &&
+	git restore --staged foo &&
+	git diff --cached --name-only >actual &&
+	echo bar >expected &&
+	test_cmp expected actual
+'
+
+test_expect_success 'restore -p --staged' '
+	rm .git/index &&
+	git add foo bar &&
+	test_write_lines y n | git restore -p --staged >output &&
+	git diff --cached --name-only >actual &&
+	echo foo >expected &&
+	test_cmp expected actual &&
+	test_grep "Unstage" output
+'
+
+test_done
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] restore: allow --staged on unborn branch
  2024-02-06 23:03 [PATCH] restore: allow --staged on unborn branch Ghanshyam Thakkar
@ 2024-02-07 16:06 ` Junio C Hamano
  2024-02-07 16:39   ` Ghanshyam Thakkar
  0 siblings, 1 reply; 3+ messages in thread
From: Junio C Hamano @ 2024-02-07 16:06 UTC (permalink / raw)
  To: Ghanshyam Thakkar; +Cc: git

Ghanshyam Thakkar <shyamthakkar001@gmail.com> writes:

> Some users expect that being on an unborn branch is similar to having an
> empty tree checked out. However, when running "git restore --staged ."
> on unborn branch having staged changes, the follwing error gets printed,
>
>     fatal: could not resolve HEAD

Sounds like a sensible behaviour---there is no HEAD so there is
nothing to resolve.  With "git resetore --staged ." in such a state,
what did the user try to do?  "git reset" (no other arguments)?

BTW, "follwing" -> "following".

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] restore: allow --staged on unborn branch
  2024-02-07 16:06 ` Junio C Hamano
@ 2024-02-07 16:39   ` Ghanshyam Thakkar
  0 siblings, 0 replies; 3+ messages in thread
From: Ghanshyam Thakkar @ 2024-02-07 16:39 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

On Wed Feb 7, 2024 at 9:36 PM IST, Junio C Hamano wrote:
> Ghanshyam Thakkar <shyamthakkar001@gmail.com> writes:
>
> > Some users expect that being on an unborn branch is similar to having an
> > empty tree checked out. However, when running "git restore --staged ."
> > on unborn branch having staged changes, the follwing error gets printed,
> >
> >     fatal: could not resolve HEAD
>
> Sounds like a sensible behaviour---there is no HEAD so there is
> nothing to resolve.  With "git resetore --staged ." in such a state,
> what did the user try to do?  "git reset" (no other arguments)?

Yeah, I did "git reset" (I am that user btw). But I suppose this is a
case of UX. If a user is using "git restore --staged ." every time they
want to unstage something, then why would they expect it to fail on an
unborn branch when something similar (e.g "git reset") does not?

Also that HEAD, I suppose, is our assumption of the user's intent. And
intent of the user using "git restore --staged ." on unborn branch is
to unstage the changes relative to empty tree. Besides "git reset" already
does this so the matter of assuming empty tree on unborn, I suppose, would
already be settled. Therefore, wouldn't assuming empty tree on unborn
when also using "git restore --staged ." be reasonable and consistent?


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2024-02-07 16:39 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-02-06 23:03 [PATCH] restore: allow --staged on unborn branch Ghanshyam Thakkar
2024-02-07 16:06 ` Junio C Hamano
2024-02-07 16:39   ` Ghanshyam Thakkar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox