Home > Back-end >  Issue running git pull command from crontab on mac OS
Issue running git pull command from crontab on mac OS

Time:10-29

I am trying to run the git pull command automatically using crontab. I am on MacOs machine. Git pull is working fine when I use it without cron but giving error with cron. I have tried various solution given for it. Some of them are below. They all are working fine manually.

I have tried putting below command in a script automate.sh and then run it using cron.

  1. ssh-agent bash -c 'ssh-add /Users/{username}/.ssh/id_rsa; /usr/bin/git pull'

  2. eval `ssh-agent -s` && ssh-add ~/.ssh/id_rsa && ssh-add -l && git pull

But I am always getting below error,

fatal: could not read Username for 'https://git.{domain}.com': Device not configured

Why?

CodePudding user response:

I think the problem are the quotes where you need. Try it with double quotes around the variable without the brackets ({})

ssh-agent bash -c 'ssh-add /Users/'"$username"'/.ssh/id_rsa; /usr/bin/git pull'

Note: Same for the variable domain

Look at this question

CodePudding user response:

TL;DR: use an ssh URL if you can. (And: don't run git pull from scripts.)

The URL you show here, from your error message:

https://git.{domain}.com

is not an ssh (secure shell) URL. It is an HTTPS (HTTP-over-SSL) URL. These are two entirely different protocols. They normally operate on different IP ports (22 for ssh, 443 for https). Not all Git servers respond to both protocols, but if yours does, there are two crucial differences for your Git as a client:

  • Git as a client, connecting via https://, must provide two items to the server: a user name and a password. (The password need not be a literal password as it can be instead a PAT for instance.)

  • Git as a client, connecting via ssh://, must provide two items to the server: a user name and some kind of key.

Except for "key" vs "password", these look—and are, really—very similar, but https and ssh clients obtain these two items in completely different ways:

  • An https client generally reads the user name and the password from the user's keyboard directly, bypassing all attempts to redirect this.

  • An ssh client generally takes the user name as an argument, and reads the key from a public and/or private key-pair file and/or obtains the key from an agent.

The word generally in these two bullet points is doing a lot of heavy lifting, but is the reason for the error you see. When you run git pull from a cron job, there is no keyboard to read from. It's physically impossible for cron—which may be running while you're not even at the computer—to have you type in a user name and password. The attempt, on the Mac, to open /dev/tty results in the Device not configured error.

Having gotten that error, the libCURL library1 gives up and the entire pull fails.

Now, note that ssh gets the user name from an argument—not by having you type it in—and gets the keys from files and/or from an ssh agent, not by having you type it in. So ssh is already at a tremendous advantage here: it doesn't require that you be sitting at your keyboard, ready for some need to enter a user name and password. Hence, if you have Git use ssh,2 you're much more likely to be able to proceed.

This is not the end of the answer (although it is the beginning and hence the TL;DR above). When using https, you can tell libCURL not to read user name and password from a user. The specifics of how to do that depend on the OS, but in general, you can use a URL of the form:

https://user@host:password/path/to/repo.git

The drawback to doing this is that you've put your user name and password right there in cleartext for everyone to see. Avoid this unless it is your only option.

Alternatively, Git can feed the user name and password to libCURL using a credential helper. Here's the other big secret about Git: Git never does any authentication at all. If you want to claim to be Barack Obama,3 you can go ahead and do that, and Git will believe you.

It's other programs that do authentication. Git relies on these other programs—web servers and ssh servers in particular—to authenticate; this determines which repositories you can read and write on other machines. On your local machine, it's the local OS's permissions that determine which repositories you can read and write.

Since ssh has its own rather large and complicated methods for dealing with authentication (including the ssh agent), we won't cover that at all here, but I will talk a little bit about the credential helpers for using libCURL. Git always comes with two simple ones, store and cache: the store helper simply saves user names and passwords in a file (which it does not encrypt, so consider avoiding this or at the very least, carefully protecting this file). The cache helper doesn't store the credentials permanently, but rather only temporarily, so it's less dangerous, but it's meant to be stuck in front of some other helper. That other helper might demand a password, and to avoid having to type it in every time, you can stick the cache helper in between: the cache helper gets the password from the next-level helper if the cached entry has expired, and now you must type in a password; but otherwise, it passes back the cached entry so that you don't have to type it this time.

Git for various OSes comes with additional OS-specific helpers. On OSX in particular, there's a git-credential-osxkeychain helper that uses the OS X Keychain software. (I don't use this: I use ssh.)

For a full explanation of all of this, see the gitcredentials documentation. When and whether some particular helper will work for your particular https setup depends on too many factors to guess at here.


1Git doesn't have all of the https protocol built into it; instead, Git just links against libCURL. The libCURL for your OS is OS-dependent, so this helps Git avoid being quite so OS-dependent.

2When using ssh URLs, Git literally just runs ssh, too.

3If you really are Barack Obama, why are you reading this?


About git pull

The git pull command does two things:

  1. First, it runs—or tries to run—git fetch. This connects to some other system and obtains new commits, or, as in your case, fails to connect (which then stops git pull in its tracks).

  2. If all has gone well in step 1, git pull now runs a second Git command. You choose, in advance, whether this should be git rebase or git merge.

Command #2 is meant to work interactively. Regardless of which command you choose, Git will do its best to combine any work you have done, making new commits in your repository, with any new commits that came in during the fetch step (command #1). This may require user assistance. If it does, command #2 prints the messages as to what assistance is required, and terminates with an error status, leaving a mess in your Git repository. This mess must be cleaned up before you attempt further operations.

Because we don't know whether command #2 will succeed in the first place, it's always a bad idea to use git pull in an unattended script. We can guess whether command #1 is likely to succeed or not, and check for that, in a script, so it's OK to use git fetch in a script. It's never OK to use git rebase or git merge in any unattended script though, unless your script checks for failure and arranges for something useful to happen (alert a human, stop attempting further commands, and so on).

To do all this correctly in a script, you must break the git pull into its constituent steps, because a failure from git pull could mean:

  • the fetch failed: perhaps a temporary network glitch; no big deal; just try again later!
  • the second step failed: disaster! Do not proceed.

You need to know which of these occurred, so you can't use git pull.

  • Related