4

I often find myself typing this:

git push remote1 branch1 branch2 tag1 tag2 tag3..
git push remote2 branch1 branch2 tag1 tag2 tag3..

I would prefer an alias where I can type this instead:

git pushall branch1 branch2 tag1 tag2 tag3 ..

Note: I am aware I could create a new remote "all" with multiple urls. Let's not discuss this here, but focus on the alias instead!

I am ok to hardcode the remote names, because I have a number of projects with the same multiple remote names (usually "drupal" and "github").

Progress so far

I already figured out a non-variadic version:

[alias]
pushall = "!git push github $1; git push drupal $1; #"

Two tricks here were

  • using double quotes to prevent ';' from having a special meaning in .ini files
  • # to ignore the rest of the line.

But this only pushes one branch (or tag) at a time. So I would have to type this:

git pushall branch1
git pushall branch2
git pushall tag1
git pushall tag2
git pushall tag3
...

I would prefer an alias where I can type this:

git pushall branch1 branch2 tag1 tag2 tag3 ..

Why not a new remote "all" with multiple push urls?

As said, let's focus on the aliases, so that readers find what they are looking for.

Anyway, here is why I am not creating a remote "all":

  • I would have to do this once per project, and could not do it globally. In my case, hardcoding the remote names in a global alias is actually fine!
  • Afaik, I would pollute my history with refs like "all/branch1" instead of or in addition to "remote1/branch1" and "remote2/branch1".

The correct place to discuss this would be here, pull/push from multiple remote locations

See also

The following are related, but they do not address variadic parameters:

The following might be helpful, but it addresses pure shell script, not specifically git aliases:

4
  • see stackoverflow.com/questions/3321492/… Commented Dec 29, 2016 at 4:09
  • @torek This link falls into the same category as the ones I already mentioned. I added it in the "See also" list for completeness. Commented Dec 29, 2016 at 7:14
  • The relevant piece of information I learn from the multiple answers is that $@ means variadic arguments in shell script, and this also works for git aliases. I was not aware of this. Now I don't know which of those answers I should accept.. I will see. Commented Dec 29, 2016 at 9:29
  • The overall trick is to define your alias as a shell function, which then takes as its parameters, all the arguments passed to the alias. Then you get to use shell script, which is a real (nominally Turing-complete) language. In some special cases you don't need to resort to the full-power mode (axiac's answer) but I usually go straight to functions anyway, they're not that complex. Commented Dec 29, 2016 at 18:04

4 Answers 4

2

This really is answered by the other questions which you linked to, but for clarity:

[alias]
    pushall = "!git push github \"$@\"; git push drupal \"$@\"; :"

Or setting from the command line:

git config --global alias.pushall '!git push github "$@"; git push drupal "$@"; :'
Sign up to request clarification or add additional context in comments.

3 Comments

I did not see the "$@" mentioned in the other answers. Or at least not explicitly. I was not aware of this construct. For the record, I just found that this will also insert options like -l or --version (for ls). But the --help option is passed to the git command instead, it appears.
In a little test run this worked without the double quotes around $@. What could possibly go wrong if I omit those?
In this case, probably not much because you cannot have branch names with spaces or other characters that might cause changes to the parameter list during word splitting.
2

The idiom to package an arbitrary script into a git alias is to put it inside a shell function:

pushall = "! f() { git push github \"$@\"; git push drupal \"$@\"; }; f"

I want to point out that the correct use of $@ is to place it inside double-quotes: "$@".

Comments

1

By extending your initial attempt:

[alias]
pushall = "!git push github $@; git push drupal"

This way, git pushall branch1 branch2 branch3 expands to:

git push github branch1 branch2 branch3; git push drupal branch1 branch2 branch3
#                  |               |                        |               |
#                  +-------+-------+                        +-------+-------+
# these arguments were     |                                        |
# expanded from $@ --------+                                        |
#                                                                   |
#                  these are the arguments of the original command -+

$@ expands to all command line arguments.
There is no need for # at the end of line; the fragment git pushall is replaced by the value of the alias, the rest of the argument

If you have a bigger list of remote repositories you can write it this way:

[alias]
pushall = "!for repo in github drupal bitbucket; do git push $repo $@; done #"
#                         |               |
#                         +-------+-------+
# put all your repos here         |
# separated by spaces ------------+

This time the # sign is required. It turns the original arguments into a comment; otherwise the command has syntax errors and it doesn't run.

If you want to push to all the remotes of the repository then you can write a smarter alias:

pushall = "! for repo in $(git remote); do git push $repo $@; done #"

It runs git remote to find all the remotes and uses command substitution to replace $(...) with the output of the git remote command before continuing.

You can define it as a global alias using:

$ git config alias.pusha '! for repo in $(git remote); do git push $repo $@; done #'

If you have some repos where you don't want to push to all remotes, you can define it as a local alias and customize the list of remotes in each repo using thi command while you are in the repository:

$ git config --local alias.pusha '! for repo in github drupal; do git push $repo $@; done #'

2 Comments

I suppose omitting the $@; # at the end saves a few characters. But it also makes the entire thing less "symmetric". So maybe I prefer the slightly longer version.
I prefer the for version; it is more versatile. You can squeeze more commands (terminated by ;) between do and done. For example, after push you can invoke a program (like notify-send on Ubuntu) that displays a desktop notification.
0

Just for the record, the following "cheat" does work. It is not really a complete answer but it might be good enough for many.

[alias]
pushall = "!git push github $1 $2 $3 $4 $5; git push drupal $1 $2 $3 $4 $5; :"

Yes this is not truly variadic, because it is limited to 5 parameters (or whichever number you choose when creating the alias). Also it cannot pass options like --key=value. But as said it might be just good enough for you.

In my specific use case, most of the time I just push one branch and one release tag, so two parameters ($1 $2) would be enough.

Note that : at the end seems to have the same effect as #. I learned this somewhere else here on stackoverflow.

I will not "accept" this answer, because I want to leave the opportunity for someone to come up with something better.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.