12

I want to ensure that my latest commit has the current date before I push. Since I always rebase to master before a merge + push, I made this alias:

[alias]
    sync = !git commit --amend --date=today && git rebase master

Problem is, it keeps launching my text editor asking for a new commit message. Is there a way to have an optional parameter, so that I can choose to use either:

git sync 'my commit message'

or

git sync

where the latter will simply use the existing commit message, whatever it happens to be?

ceramica
  • 123
  • 1
  • 4

2 Answers2

18

To apply the extra parameters to anything except the end of your alias’ “command line”, you will need to put your shell commands in a script. You can do it with an external script (like jdelStrother’s answer), or you can do it with an “inline” shell script.

You can use -m to feed git commit your new message or use the -C HEAD/--reuse-message=HEAD option to have it use the existing message and author (it would also reuse the author timestamp, but you are resetting that with --date=…). Using any of these options will prevent Git from opening an editor for your commit message.

Here it is as an “inline” shell script:

git config --global alias.sync '!sh -c '\''git commit --amend --date=today ${1+-m} "${1---reuse-message=HEAD}" && git rebase master'\'' -'

The core of this small script is the pair of conditional parameter expansions:

${1+-m} "${1---reuse-message=HEAD}"

When you call it with an extra parameter (i.e. your replacement log message), these expand to two shell words: -m "<your new log message>". When you do not supply the extra parameter, they expand to just a single word: "--reuse-message=HEAD".

The trailing dash is also important; it could be any shell word, the point is that something must be there because the shell will use it to initialize its $0 parameter (which usually has a default value, so it is useless for the conditional expansion itself).


If I misunderstood and you actually want to see the editor when you do not supply the extra parameter, then use the single expansion ${1+-m "$1"} instead of the pair of expansions.

Community
  • 1
  • 1
Chris Johnsen
  • 214,407
  • 26
  • 209
  • 186
  • --reuse-message=HEAD is just what I was looking for, however the script isn't working how I expected. The commit command seems to use the existing message regardless of whether I supply a parameter, and the rebase command always comes back with an error: When no parameter is supplied I get 'fatal: Needed a single revision invalid upstream master' When a parameter is supplied I get 'Usage: git rebase ...' – ceramica Jul 11 '11 at 02:34
  • @ceramica It works for me (both giving a new message and reusing the old message, as well as the subsequent rebase), but I have to use something besides `--date=today`, since that is not valid. I used `--date="$(date "+%s %z")"` instead — the exact command I used to create the alias (that is working for me) is `git config --global alias.sync '!sh -c '\''git commit --amend --date="$(date "+%s %z")" ${1+-m} "${1---reuse-message=HEAD}" && git rebase master'\'' -'`. – Chris Johnsen Jul 11 '11 at 03:04
  • I finally got it to work but I had to manually change the alias in my .gitconfig to: `"!sh -c 'git commit --amend --date=today ${1+-m} \"${1---reuse-message=HEAD}\" ; git rebase master' -"` I don't know why it needs the extra quotation marks, but the need for `;` to separate the commands suggests the first one is failing. Yet, it seems to work fine. – ceramica Jul 13 '11 at 04:53
6

When your aliases start getting more complex, it's probably easiest just to create a separate script for them. If you add a file 'git-sync' to your path, it will be automatically called when you do 'git sync'.

So, if you created that file with something along the lines of -

#!/bin/sh

if [ -z "$1" ]; then
  git commit --amend --date=today
else
  git commit --amend --date=today -m "$1"
fi
git rebase master

- that would probably work. It's typed off the top of my head though, so caveat lector.

Jonathan del Strother
  • 2,552
  • 19
  • 32