On Wed, 2 Oct 2013 12:04:28 -0700 (PDT)
dkoleary <dkole...@olearycomputers.com> wrote:

> Apologies for replying to my own post, but I did just find the "git
> --bare fetch".  While that seems to have worked, 

That's odd: `git fetch` does not support "--bare", only `git clone`
does.  If `git fetch` doesn't fail on this option, it's a bug, I think.

> # git --bare fetch ${prod}:/opt/app/git/filemover
> From ${prod}:/opt/app/git/filemover
>  * branch            HEAD       -> FETCH_HEAD
> how do I go about getting those changes into the bare repo?  A git
> log isn't showing the new commits yet...

Well, it's all in "the refspecs".  The refspec if short for "ref
specification" and "ref" is a short form of "reference" in Git's
parlance.  A ref is a symbolic name pointing to an object in the Git
database; branches, tags and notes are all example of refs.

Refspecs tell certain Git commands on which refs to operate, and how.
For instance, the full form of the `git fetch` call is

git fetch [OPTIONS] [<remote> [<refspec> ...]]

where <remote> is either an URL or the name of a named remote (those
managed with the `git remote` command).

Now let's cite the `git fetch` manual:


    The format of a <refspec> parameter is an optional plus +, followed
    by the source ref <src>, followed by a colon :, followed by the
    destination ref <dst>.

    The remote ref that matches <src> is fetched, and if <dst> is not
    empty string, the local ref that matches it is fast-forwarded using
    <src>. If the optional plus + is used, the local ref is updated even
    if it does not result in a fast-forward update.

and earlier there:

    The ref names and their object names of fetched refs are stored
    in .git/FETCH_HEAD. This information is left for a later merge
    operation done by git merge.

The missing bit of information is that if Git fails to obtain a refspec
-- there's no refspec on the command line and none can be obtained from
the local repo configuration (more on this later) it assumes you want
to get whatever HEAD ref points in the remote repo, that is, if no
refspec is available Git uses HEAD, literally.

Now let's put the parts of "the puzzle" together: a call

git fetch <URL>

is turned out to be

git fetch <URL> HEAD

since no refspec is available.  Now Git contacts the repository at
<URL>, fetches whatever HEAD points there (in bare repos it's usually
refs/heads/master), writes all the objects fetched into the local Git
database and then writes the SHA-1 name of the fetched tip commit into
a special ref FETCH_HEAD.  No local branches are updated as the result
as there's nothing in the default refspec which tells Git to do so.

Now if you want to fetch all tags and branches from the remote repo and
update everything with matching names in a local repo, you'll have to
be clear about this:

git fetch <URL> '+refs/*:refs/*'

which means "grab every ref from the remote side and update
corresponding refs locally with the fetched data".  I used single
quotes deliberately as you had to protect asterisks from being expanded
by the Unix shell.  A plus sign is there to force owerwriting the
local refs if the remote history changed in a non-linear way since the
last fetch.  If you only need branches (called "heads" in Git lingo) and
tags (but not notes, for instance), use several refspecs:

git fetch <URL> '+refs/heads/*:refs/heads/*' '+refs/tags/*:refs/tags/*'

This information by itself is already a solution to your problem, but
let's dig deeper.

A part of "the magic" `git clone` does is to set up a single named
remote called "origin".  Setting up a named remote means creating a
special section in the configuration of a local repository -- in the
file named ".git/config" (or just "config" in a bare repository).
This section looks like this:

[remote "origin"]
        fetch = +refs/heads/*:refs/remotes/origin/*

Notice the "fetch" variable there which defines a refspec for
`git fetch` (and, by definition, for `git pull` as well).
I copied this section from the configuration of a non-bare repo so you
might notice that the right-hand side of the refspec ("what to update")
speficies "refs/remotes/origin/*" and not just "refs/heads/*".  That's
because in non-bare repos `git fetch` by default updates the so-called
remote branches, and not your own local branches you're working on.

Now when you call `git fetch origin` (or just `git fetch`) in a
repository set up like this, Git sees no refspec passed to it on the
command line and so it looks up the <remote>.fetch configuration
variable in the local repo (in this case it will be origin.fetch), and
if it's found, uses the refspec it defines.  Note that contrary to the
default refspec, HEAD, this one set up by `git clone` actually
specifies what to update with the fetched data.

Now let's turn to `git clone --bare`.  As specified in its manual page,


    Make a bare GIT repository. That is, instead of creating
    <directory> and placing the administrative files in
    <directory>/.git, make the <directory> itself the $GIT_DIR. This
    obviously implies the -n because there is nowhere to check out the
    working tree. Also the branch heads at the remote are copied
    directly to corresponding local branch heads, without mapping them
    to refs/remotes/origin/. When this option is used, neither
    remote-tracking branches nor the related configuration variables are

IOW, if you do `git clone --bare <URL>` Git will set up the remote
"origin" like this

[remote "origin"]
        url = <URL>

Note that there's *no* variable "fetch" created in this section (at
least with Git 1.8.1).  I'm not sure why Git won't create one but no
one preventing us from doing this:

git config --add remote.origin.fetch '+refs/*:refs/*'

Now let's see what happens:

$ git fetch -v
>From git.domain.local:my-repo
 = [up to date]      flag       -> flag
 = [up to date]      master     -> master
 = [up to date]      dump-to-files -> dump-to-files

There were no updates in my case but should the remote repo have
something updated or created, Git would update/create the corresponding
refs locally.

So let's recap: the way to go in your case would be:

1) Run `git clone --bare <URL>` to create an initial clone.

2) Run `git fetch origin +refs/*:refs/*` for syncing
   Run `git config --add remote.origin.fetch +refs/*:refs/*` once
   after cloning and then sync using plain `git fetch`.

Hope this helps.  You might be interested to read [1] as well which
explains essentially the same things but at a slightly different

1. http://stackoverflow.com/a/18787744/720999

You received this message because you are subscribed to the Google Groups "Git 
for human beings" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to git-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to