Reputation: 666
I have added github remote to my git repository using:
git remote add --mirror=push github repository_path.git
I am trying to fetch from remote using:
git fetch github
where, github
is remote I have added in previous step.
I tried to git fetch for two repositories, in case of first repo, it is able to fetch changes that are present in remote. But in case of second repo git fetch is not able to fetch changes that are present in remote.
The difference between both repositories is, the repository in which fetch is working is created by me, and repository in which fetch is not working is created by other user, but I have permission to do pull and push in that repository
Can anyone help me to solve this issue?
Upvotes: 0
Views: 1439
Reputation: 490068
--mirror=push
defeated youYou probably did not want that option. It's not at all clear what options, if any, you did want.
First (though not so important here), git fetch
fetches commits, not changes. The (Git-specific) difference between a commit and a "change" is that a commit is a snapshot: a complete copy of a work-tree (or more precisely, the parts of the work-tree that were in the index at the time the commit was made). To turn a snapshot into a change, you must compare (i.e., git diff
) it against some other snapshot. (And in fact, this is not quite accurate either: git fetch
fetches objects, which include commits, but also include annotated tags, trees, and blobs. In general, though, we're mostly concerned with the commits.)
The most important part here, though, is this: the set of commits (and other objects) that git fetch
fetches is controlled by refspecs. A refspec, in its second-simplest form, looks like this:
master:origin/master
refs/heads/*:refs/remotes/foo/*
These would be typical fetch refspecs for a remote named origin
or foo
. Yours is named github
, so you might want, e.g.:
refs/heads/*:refs/remotes/github/*
as your default refspec. This tells your Git that, when the other Git—the foreign Git you are calling up over the Internet-phone, at the URL you specified earlier—offers refs/heads/master
, refs/heads/branch
, and refs/notes/commits
, your Git should take it up on its master
and branch
branches, and ignore the commits
notes.
The left hand side of each colon-separated pair is the name you would like your Git to match. You have no control over what their Git offers, but you have complete control over what you take (i.e., match).
The right hand side is the name you would like your Git to use in your repository. As you can see here, you do not have to use the same name that the other Git uses. You can use the same name, if that's what you want, but you do not have to, and usually you do not want to. Usually, you want to take their branch names, such as their master
, and rename them to be your remote-tracking branch names: origin/master
, for instance.
I mentioned above that this is the second simplest form of refspec. The simplest is one without a colon, such as master
. If you use this colon-free form of refspec, git fetch
does not give the fetched objects any name in your repository. This is what you are seeing.
(This is once again not 100% accurate: any git fetch
writes to FETCH_HEAD
. However, FETCH_HEAD
is a remarkably temporary name. Specifically, the very next git fetch
overwrites it, since any git fetch
writes to FETCH_HEAD
. So it might as well be "no name": it's only good until the next fetch. That's all that the original git pull
script needed, back when git fetch
was merely plumbing for the user-oriented pull
script, before "remotes" were invented in the first place. But it's no good these days, when we want our remote-tracking branches updated.)
git fetch
needs some default refspecsIf you run git fetch remote
, you are running it with no refspec arguments. In this case, git fetch
looks up the default refspecs in your Git configuration. Normally, git remote add
sets these up for you:
$ git remote add foo ssh://host.dom.ain/path/to/repo.git
creates remote "foo"
with two configured items:
$ git config --get remote.foo.url
ssh://host.dom.ain/path/to/repo.git
$ git config --get-all remote.foo.fetch
refs/heads/*:refs/remotes/foo/*
(We should always use --get-all
here, in case there is more than one configured fetch
line, but in fact git remote add
only sets up one.)
You used git remote add --mirror=push
, though, and that changes what git remote add
sets up for the new remote. Instead of adding remote.foo.fetch
set to refs/heads/*:refs/remotes/foo/*
, it adds remote.foo.mirror
set to true
:
$ git config --get-regexp '^remote\.foo\.'
remote.foo.url ssh://host.dom.ain/path/to/repo.git
remote.foo.mirror true
In particular, there are no remote.foo.fetch
entries.
(This --get-regexp
lets us examine everything under a [remote "foo"]
section. It is an alternative to --get-all
that accepts an arbitrary regular expression, and we gave it one matching remote.foo.
with a left anchor ^
and the two dot characters quoted to make sure they match a literal dot rather than any single character. Note that regular expressions are different from, and more powerful than, shell style globs: the fetch
refspecs are shell-style globs, not regular expressions. None of this is stuff you need to know, it's just useful side information.)
git fetch
is hamstrungWithout either a command-line refspec:
git fetch github 'refs/heads/*:refs/remotes/github/*'
or a default remote.github.fetch
, git fetch
falls back on a weak and flimsy built-in default. It asks the other Git: "What's your most significant branch? Specifically, what commit is your HEAD
?" It then fetches that commit (and its history as needed), and calls that FETCH_HEAD
, in your repository:
From <url>
* branch HEAD -> FETCH_HEAD
You now have the time from now until your next git fetch
to do something with FETCH_HEAD
.
--mirror=push
, then come up with the option you really wantSetting remote.remote.mirror
to true
has the same effect as specifying --mirror
on the command line: it force-pushes all local refs to a ref of the same name on the remote, as if you used +refs/*:refs/*
.1 But if the remote is a push mirror when compared to the local repository, you probably never want to fetch from it at all. (In other words, this combination—push mirror, but fetch-able—makes no sense.)
1Note that push refspecs differ somewhat from fetch refspecs. Both use the same syntax: an optional force flag, a source ref name or single-asterisk glob pattern, a colon, and a destination ref name or similar glob pattern. The source and destinations are reversed, though: for fetching, the source is the remote repository / other Git, while for pushing, the source is the local repository / our Git. The meaning of a missing destination differs as well: for fetch, a missing destination means use only FETCH_HEAD
, but for push, a missing destination means use the same name, e.g., git push master
means push (our) master to (their) master. Finally, fetch does not allow an empty source, but push does: that means ask the remote Git to delete the reference entirely.
Upvotes: 1