1

I'm trying to set up a service that will update my repository automatically when it detects changes on the remote branch. Before anyone mentions it, I'm aware that embedding the password in the URL is bad practice. I'm currently using:

git fetch https://<user>:<pass>@github.com/<org>/<repo>

Which gives an output of:

From https://github.com/<org>/<repo>
 * branch            development -> FETCH_HEAD

When I run git status after doing the fetch, it doesn't detect the most recent changes.

If I run a normal git fetch without the URL and supply the username and password manually, I get a different output:

From https://github.com/<org>/<repo>
   96353f7..e88782c  development -> origin/development

And then running git status works as predicted and detects that there are changes on the remote branch.

I'm not very experienced with Git and I feel like I'm missing something very obvious. Where is my error?

Edit

So it looks like the missing piece was for me to specify the local and remote branch after the URL:

git fetch https://<user>:<pass>@github.com/<org>/<repo> development:origin/development

As the accepted answer points out: if you don't specify the remote name, git puts the remote changes in the default FETCH_HEAD. This is resolved by specifying the local and remote branches explicitly.

I'm still a little confused as to why git fetch knows to grab from the origin remote by default, but specifying the URL changes this default. But it's working now in any case

halfer
  • 19,824
  • 17
  • 99
  • 186
user2437443
  • 2,067
  • 4
  • 23
  • 38
  • Yes, the obvious thing is that first command updates the index, but does not touch your branches. See how I use it: `# Sync up with the remotes, prune them, and update the local master branch\n echo "Update Remotes"\n git fetch --all --prune\n git fetch $(git config branch.master.remote) master:master\n`. In your case `master` would be replaced by `development`. – 0andriy Feb 18 '20 at 19:50
  • What do you mean when you say "run a normal git fetch"? Do you mean `git fetch origin`? – Schwern Feb 18 '20 at 20:06
  • Yes sorry that's what I meant. I just run `git fetch` but I think by default that grabs the origin remote – user2437443 Feb 18 '20 at 21:15
  • Same issue here. This is super annoying. Any solution? When doing git fetch https://:@bitbucket.org// master:master I get fatal: Refusing to fetch into current branch refs/heads/master of non-bare repository – Nathan B Oct 21 '22 at 13:10
  • @user2437443 your answer creates another (unwanted) local branch to me – Nathan B Oct 21 '22 at 13:27

2 Answers2

2

Git remotes are a name associated with a URL. The default name is origin and the URL is usually whatever you cloned from.

Git stores a snapshot of remote repositories in "remote tracking branches". These are of the form <remote-name>/<branch>. When you git fetch origin Git goes and fetches changes from the URL associated with origin and puts them into remote branches. development -> origin/development is telling you that it put the remote's development branch into your origin/development remote branch.

When you run git fetch https://<user>:<pass>@github.com/<org>/<repo> and give it just the URL, no remote name, Git doesn't have a name for its remote tracking branches. So it just sticks them in an ephemeral FETCH_HEAD which records your last git fetch. That's what development -> FETCH_HEAD is telling you.


Regardless of any of this, git status will show no change. git fetch never changes your local branches nor your index nor your checkout. It will only update your remote tracking branches. This makes it safe to habitually run git fetch to update your snapshot of the remote repository.

What you're looking for to update your local copy of a remote branch is git pull.


Finally, to avoid having to type in your username and password every time, or worse hard coding them into the URL, set up a Git credential helper to securely store your username and password.

Schwern
  • 153,029
  • 25
  • 195
  • 336
  • 1
    I'm still confused as to why it doesn't work the same way with the URL. In your answer, you say `git fetch origin` fetches changes from the URL associated with `origin`. So shouldn't specifying the URL instead of the remote name work the same way? I'm not trying to apply the changes to the local branch (yet), I'm just trying to use git status to see if the branch is up to date or not. How would I specify the remote name with the URL format? I've tried `git fetch origin`, `git fetch \origin`, `git fetch origin\development` and a few other formats with no luck – user2437443 Feb 18 '20 at 21:13
  • Never mind, I figured out the syntax and I'll update my question. Thanks for pointing me in the right direction! – user2437443 Feb 18 '20 at 21:16
  • @user2437443 "*So shouldn't specifying the URL instead of the remote name work the same way?*" Maybe, but for whatever reason it doesn't. If I had to guess why, the designers though that if you're manually specifying a URL you already have a remote for you probably don't want the remote's branches changed. Which leads to the question: if you already have a named remote with the same URL, why are you using the URL at all? Finally, `git fetch` doesn't change you local branches nor working tree and should never affect `git status`. – Schwern Feb 19 '20 at 00:04
  • Thanks for the explanation, but what is the answer? How to make the behaviour of git fetch with url *exactly* like the git fetch without the url? I can't seem to figure this out – Nathan B Oct 21 '22 at 13:24
  • @NathanB I don't know that you can, and I don't know that it's a good idea. You want Git to guess that when you say `git fetch ` it should search for a remote with the matching URL and if there is one you actually meant `git fetch `. Should it do URL canonicalization? What if the URL contains a username and password? What if you change the URL of the remote and suddenly that URL/name equivalency no longer holds? It's a lot of silent guessing for a situation already solved by remote names. You can write a little wrapper that does that guessing. – Schwern Oct 21 '22 at 19:01
  • @NathanB What's your need for this feature? – Schwern Oct 21 '22 at 19:03
  • To know how "far behind" is the local repository in respect to the remote repo. For example, if it is 1,2 or 3 commits behind the remote repo. – Nathan B Oct 23 '22 at 09:14
  • @NathanB And why is fetching with a URL, rather than a remote name, necessary to do that? – Schwern Oct 24 '22 at 19:45
  • @Schwern so you can specify the password – Nathan B Oct 26 '22 at 05:50
  • @NathanB Rather than hard coding it, can you use a [credential manager](https://git-scm.com/book/en/v2/Git-Tools-Credential-Storage)? – Schwern Oct 26 '22 at 17:03
  • I do use credentials manager, and even with credential manager you need to insert the password at the beginning and after the cache time expires, this is why it is needed in the full command line. The question is how to do git fetch, just with the credentials - that's it, clean and simple – Nathan B Oct 28 '22 at 09:40
  • @NathanB I'd imagine you'd config your credential storage so it never expires. Much more secure than embedding a password in a URL and putting the password on disk. You should ask your own question about this. – Schwern Oct 28 '22 at 15:56
  • private keys are always stored in disk, and ssh keys, etc. when servers communicate in order to fetch code they need passwords/keys, etc. How do you think the git credentials manager store the passwords? In the air? – Nathan B Oct 29 '22 at 16:46
  • @NathanB A good credential manager will store it in memory ("cached" mode), or *encrypted* in the OS's credential store such as the MacOS keychain. Only "stored" mode puts it unencrypted on disk which should be avoided. See [Credential Storage](https://git-scm.com/book/en/v2/Git-Tools-Credential-Storage) for more. Putting the username and password in the URL risks having the password *unencrypted* on disk in .git/config and in your command history. – Schwern Oct 31 '22 at 03:56
  • It does not matter, since I am referring to a server, which it's access ssh is controlled by private/public key anyhow. – Nathan B Nov 01 '22 at 07:28
0

Since no matter how hard I tried to make git fetch with url behave exactly like git fetch with no url, the only solution I have is this: First cache the password by using some dummy command (git ls-remote), and then run the regular git fetch as follows (assuming there is some non zero timeout for the git credential manager):

git ls-remote --heads https://<user>:<pass>@bitbucket.org/<org>/<repo>

git fetch
Nathan B
  • 1,625
  • 1
  • 17
  • 15