branch: support for shortcuts like @{-1}, completed

branch command with options "edit-description", "set-upstream-to" and "unset-upstream" expects a branch name. Since ae5a6c3684 (checkout: implement "@{-N}" shortcut name for N-th last branch, 2009-01-17) a branch can be specified using shortcuts like @{-1}. Those shortcuts need to be resolved when considering the arguments. We can modify the description of the previously checked out branch with: $ git branch --edit--description @{-1} We can modify the upstream of the previously checked out branch with: $ git branch --set-upstream-to upstream @{-1} $ git branch --unset-upstream @{-1} Signed-off-by: Rubén Justo <rjusto@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Rubén Justo committed Oct 11, 2022 at 01:24 UTC 0dc4e5c57498cc142cbcc9e8a5f0667368d7c860
2 files changed +58 -19
builtin/branch.c
+34 -19
@@ -791,31 +791,33 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
791 } else if (edit_description) {
792 const char *branch_name;
793 struct strbuf branch_ref = STRBUF_INIT;
794 + struct strbuf buf = STRBUF_INIT;
795 + int ret = 1; /* assume failure */
796
797 if (!argc) {
798 if (filter.detached)
799 die(_("Cannot give description to detached HEAD"));
800 branch_name = head;
799 - } else if (argc == 1)
800 - branch_name = argv[0];
801 - else
801 + } else if (argc == 1) {
802 + strbuf_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
803 + branch_name = buf.buf;
804 + } else {
805 die(_("cannot edit description of more than one branch"));
806 + }
807
808 strbuf_addf(&branch_ref, "refs/heads/%s", branch_name);
805 - if (!ref_exists(branch_ref.buf)) {
806 - strbuf_release(&branch_ref);
807 -
808 - if (!argc)
809 - return error(_("No commit on branch '%s' yet."),
810 - branch_name);
811 - else
812 - return error(_("No branch named '%s'."),
813 - branch_name);
814 - }
809 + if (!ref_exists(branch_ref.buf))
810 + ret = error(!argc
811 + ? _("No commit on branch '%s' yet.")
812 + : _("No branch named '%s'."),
813 + branch_name);
814 + else if (!edit_branch_description(branch_name))
815 + ret = 0; /* happy */
816 +
817 strbuf_release(&branch_ref);
818 + strbuf_release(&buf);
819
817 - if (edit_branch_description(branch_name))
818 - return 1;
820 + return ret;
821 } else if (copy) {
822 if (!argc)
823 die(_("branch name required"));
@@ -835,9 +837,15 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
837 else
838 die(_("too many arguments for a rename operation"));
839 } else if (new_upstream) {
838 - struct branch *branch = branch_get(argv[0]);
840 + struct branch *branch;
841 + struct strbuf buf = STRBUF_INIT;
842
840 - if (argc > 1)
843 + if (!argc)
844 + branch = branch_get(NULL);
845 + else if (argc == 1) {
846 + strbuf_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
847 + branch = branch_get(buf.buf);
848 + } else
849 die(_("too many arguments to set new upstream"));
850
851 if (!branch) {
@@ -854,11 +862,17 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
862 dwim_and_setup_tracking(the_repository, branch->name,
863 new_upstream, BRANCH_TRACK_OVERRIDE,
864 quiet);
865 + strbuf_release(&buf);
866 } else if (unset_upstream) {
858 - struct branch *branch = branch_get(argv[0]);
867 + struct branch *branch;
868 struct strbuf buf = STRBUF_INIT;
869
861 - if (argc > 1)
870 + if (!argc)
871 + branch = branch_get(NULL);
872 + else if (argc == 1) {
873 + strbuf_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
874 + branch = branch_get(buf.buf);
875 + } else
876 die(_("too many arguments to unset upstream"));
877
878 if (!branch) {
@@ -871,6 +885,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
885 if (!branch_has_merge_config(branch))
886 die(_("Branch '%s' has no upstream information"), branch->name);
887
888 + strbuf_reset(&buf);
889 strbuf_addf(&buf, "branch.%s.remote", branch->name);
890 git_config_set_multivar(buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
891 strbuf_reset(&buf);
t/t3204-branch-name-interpretation.sh
+24
@@ -133,4 +133,28 @@ test_expect_success 'checkout does not treat remote @{upstream} as a branch' '
133 expect_branch HEAD one
134 '
135
136 +test_expect_success 'edit-description via @{-1}' '
137 + git checkout -b desc-branch &&
138 + git checkout -b non-desc-branch &&
139 + write_script editor <<-\EOF &&
140 + echo "Branch description" >"$1"
141 + EOF
142 + EDITOR=./editor git branch --edit-description @{-1} &&
143 + test_must_fail git config branch.non-desc-branch.description &&
144 + git config branch.desc-branch.description >actual &&
145 + printf "Branch description\n\n" >expect &&
146 + test_cmp expect actual
147 +'
148 +
149 +test_expect_success 'modify branch upstream via "@{-1}" and "@{-1}@{upstream}"' '
150 + git checkout -b upstream-branch &&
151 + git checkout -b upstream-other -t upstream-branch &&
152 + git branch --set-upstream-to upstream-other @{-1} &&
153 + git config branch.upstream-branch.merge >actual &&
154 + echo "refs/heads/upstream-other" >expect &&
155 + test_cmp expect actual &&
156 + git branch --unset-upstream @{-1}@{upstream} &&
157 + test_must_fail git config branch.upstream-other.merge
158 +'
159 +
160 test_done