0

Why do I want git push -d remotes/remote-name/topic/branch?
It's the format that you get in gitk, often I find remote branches in gitk that I want to delete. Right click the branch name in gitk, copy and do something like git nuke remotes/remote-name/topic/branch.

What I currently have:
echo remotes/origin/epic/T-12345 | awk '{gsub(/^remotes\/[^\/]*\//, "")}{print}' This works fine, prints epic/T-12345 - it chops the optional beginning of string ^remotes/.*?/ in terms of PCREs which are easier to read.

Problem: When I try to use it in a git alias like so (git-for-windows, running from git-bash):

test1 = "!f() { \
  echo ${1} | awk '{gsub(/^remotes\/[^\/]*\//, "")}{print}'; \
}; f"

I get fatal: bad config line 5 in file C:/Users/username/.gitmorealiases

The plan was to do something like:

test1 = "!f() { \
  REPLACED=`echo ${1} | awk '{gsub(/^remotes\/[^\/]*\//, "")}{print}'`; \
  git push -d origin $REPLACED;
}; f"

Two working git aliases from the accepted answer:

Replace echo with the actual command you need, e.g. git push -d origin

  • Using awk as originally asked for (can be useful in many situations):
v1_awk = "!f() { \
  replaced=$(echo "$1" | awk '{gsub(/^remotes\\/[^\\/]*\\//, \"\")}{print}'); \
  echo "$replaced"; \
}; f"
  • Using shell string substitutions (for those who can remember how it works):
v2_shell = "!f() { echo \"${1#remotes/*/}\"; }; f"
RavinderSingh13
  • 130,504
  • 14
  • 57
  • 93
Dmitry Avtonomov
  • 8,747
  • 4
  • 32
  • 45
  • Remove \ and remove newlines. Do one line. Also, check your scripts with shellcheck - do not use backticks. – KamilCuk Oct 05 '21 at 23:42
  • @KamilCuk `test3 = "!f() { echo ${1} | awk '{gsub(/^remotes\/[^\/]*\//, "")}{print}'; }; f"` same output: `bad config line...` – Dmitry Avtonomov Oct 05 '21 at 23:51
  • How will shellcheck help? `echo remotes/origin/epic/T-12345 | awk '{gsub(/^remotes\/[^\/]*\//, "")}{print}'` works just fine by itself. Same thing copied into a git alias function does not work. – Dmitry Avtonomov Oct 05 '21 at 23:53
  • 1
    I would consider `!f() { ... }; f` a pure anti-pattern from the scalability, maintainability and even sanity points of view. Simply create a `+x` script named `git-any-name-here` (note a dash after the word `git`), put it in your PATH, and then invoke it using `git any-name-here [args...]` (note a space after `git`). I'm almost sure it would also work under Windows + git bash. Also, no need to change Git configuration at all + it your favorite text editors don't need to be aware of the Git config escaping rules therefore providing full edit support for those scripts. – terrorrussia-keeps-killing Oct 06 '21 at 07:08
  • @fluffy With that instead of just one git-aliases file (which I copy between environments) I need: 1) multiple files 2) all are separate shell commands, they're not recognized as git sub-commands like aliases are. No scalability needed, I don't write big programs in git aliases, just want a way to sanitize input a bit. – Dmitry Avtonomov Oct 06 '21 at 19:51
  • @DmitryAvtonomov It does not really matter because you really faced with a core issue of escaping a script language in a git config having \/\/\/\/\/-like stuff + losing a lot of benefits because of that. When I said "sanity point of view", I meant what I meant: escaping shell scripts in aliases is madness (what if your script gets bigger in the future? what if you don't need to share all your config file (+ not only the alias section) but a part of it only? isn't copying two files instead of a single file worth it? etc-etc-etc). Well, I wish I could never maintain stuff like that. – terrorrussia-keeps-killing Oct 07 '21 at 05:18
  • 1
    @fluffy Ok, point taken. Nevertheless, the question was about doing it from a git alias file. Another thing you loose with your solution is git autocompletion in shell (like branch names etc). – Dmitry Avtonomov Oct 07 '21 at 06:39

1 Answers1

2

\/ is an unknown escape sequence, you have to escape \ inside ".

test1 = "!f() { replaced=$(echo "$1" | awk '{gsub(/^remotes\\/[^\\/]*\\//, \"\")}{print}') && git push -d origin \"$replaced\"; }; f"

From man git config: Inside double quotes, double quote " and backslash \ characters must be escaped: use \" for " and \\ for \.

As for shell: prefer to use lower case for local variable names, quote variable expansions to prevent word splitting, prefer to use $(...) instead of backticks.

Anyway, I think just:

test1 = "!f() { git push -d origin \"${1#remotes/*/}\"; }; f"
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • thank you, your edit of my original command worked. However your suggestion (which I guess uses string replacement baked into shell?) didn't work for me. I tried `test1 = "!f() { echo "${1#remotes/*/}"; }; f"` and it produces: `f() { echo ${1: -c: line 0: unexpected EOF while looking for matching `}'` – Dmitry Avtonomov Oct 06 '21 at 00:06
  • 1
    Lol, that sounds like `#` is getting parsed as a comment.. Och right, `"` should be `\"`... – KamilCuk Oct 06 '21 at 00:07
  • Ok, so that works: `test6 = "!f() { echo \"${1#remotes/*/}\"; }; f"`. I find bash string manipulation very hard to remember. – Dmitry Avtonomov Oct 06 '21 at 00:12
  • 1
    https://stackoverflow.com/questions/66421468/how-to-remember-which-expansion-var-var-work-from-which-end :D – KamilCuk Oct 06 '21 at 00:13