Commands used in this section:
- git clone
- git fetch
- git merge
- git branch
Git and Remotes: The Config file
In previous sections you’ve seen how to create and remove shared repositories and their branches, what really happens when you do a git clone/push/pull/fetch, etc.
Here is where you get dirty and find out what is really going on in the .git/config file when you use git remote-related commands.
“git clone” And The Config File
Let’s look at the config file for the git client that did the
$ git clone git://repohost/project1.git
in the Git Remotes Up Close: “Tracking Branches” and “Remote-Tracking Branches” section.
After the git clone git://repohost/project1.git command, the git config file looks something like this:
$ cat .git/config [core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true [remote "origin"] url = git://repohost/project1.git fetch = +refs/heads/*:refs/remotes/origin/* [branch "master"] remote = origin merge = refs/heads/master
The above config file has 3 sections:
- [remote “origin”]
- [branch “master”]
The [core] section is unrelated to git remotes, so we’ll ignore that for now.
The [remote “origin”] and [branch “master”] sections are related to how git will interact with remote repositories and will be the focus of this section.
The “remote” section
We’ll start with the remote section:
[remote "origin"] url = git://repohost/project1.git fetch = +refs/heads/*:refs/remotes/origin/*
Let’s take it a line at a time:
- This begins a definition of a remote repository named origin.The details of the remote repository named origin are defined in the lines after the [remote “origin”] line. The origin remote repository can be referred to in commands such as git fetch and git pull in addition to being referred to in the [branch … ] configuration file section we’ll discuss later.For example, we can add another name to the same remote git repository (which we normally would do only if we were writing a git tutorial), by adding the following lines to the end of the .git/config file:
[remote "france"] url = git://repohost/project1.git fetch = +refs/heads/*:refs/remotes/origin/*
The above lines define a the new remote repository named france, so we can type:
$ git fetch france
The above command copies the latest commits from the repository we just defined and called france at the url git://repohost/project1.git. (No, it does not fetch Paris, France and move it to your backyard. That feature will have to wait for a future version of git.)
We don’t have a germany repository defined in the config file, so this will fail:
$ git fetch germany fatal: 'germany' does not appear to be a git repository fatal: The remote end hung up unexpectedly
Next is this line:
url = git://repohost/project1.git
The url line of a [remote …] section specifies the location (the URL) of the repository.
Since we are inside the [remote “origin”] section, the origin remote repository is configured to be at the URL git://repohost/project1.git
The diagram below shows 2 remote repositories defined in the git config file: 1) origin which has a url of git://repohost/project1.git and 2) saturn which has a url of git://vault/nasa.git.
After the git remote repositories are defined in the git config file, you can then reference them with git commands. For example git fetch saturn would attempt to fetch the latest commits from the repository named saturn.
fetch = +refs/heads/*:refs/remotes/origin/*
The fetch line is a little more exciting than the other ones we’ve looked at so far, though maybe not as exciting as it first appears.
The fetch line specifies:
- Which branches we’d like fetched from the remote repository, and
- What to call those branches in the local git repository after we’ve fetched them when we use the git fetch and git pull commands.
The “+refs/heads/*:refs/remotes/origin/*” part of the line is referred to as a refspec. A refspec uses the format: [+]source:destination. The + is optional and we’ll ignore it for now.
The above refspec means branches from the remote repository (the “source”):
are mapped to the local branches (on the local repository) in:
If you haven’t explored the .git directory yet, it’s a good time to do that now. In particular, note that the local branch names are found in refs/heads/branch-name and remote-tracking branch names are stored in refs/remotes/remote-name/remote-BRANCH-name.
For example a typical git repository would have refs/heads/master pointing to the most recent commit of the master branch and refs/remotes/origin/master would point to the most recent commit of the remote-tracking branch from the origin remote repository’s master branch.
The diagrams below begin with a new repository and no remote repositories defined in the .git/config file. As we add more lines to the .git/config file, we can specify less when using git commands.
Click on the thumbnails in the lower right hand corner to select the diagram:
Don’t Do The Above Branch Naming At Home
The example sessions above, use different branch names to better illustrate the flow of commits when using git commands. For example, the above example maps a remote repository’s master branch to a remote-tracking branch named origin/remtracker which as then merged into a working branch named locbranch.
The origin/remtracker and locbranch names aren’t recommended.
Typically the branch names would be related to the branch name on the remote repository. For example, normally the branches would be named:
- Remote repository: master
- Remote-tracking branch: origin/master
- Local working branch: master
Git configures this type of consistent branch naming by default through the fetch refspec with wildcards (refs/heads/*:refs/remotes/origin/*), etc.
Git Looks Around For Branch Names
Note that when you refer to a branch like master or origin/master, git will search for branches by those names in a number of places including:
So when you type git fetch origin it might find that branch information in .git/refs/heads/origin. When you type git merge origin/remtracker it might find that in .git/refs/remotes/origin/remtracker.
Using “git remote add” To Add To The Config File
When you want to add a new remote configuration to git, you can dive in and add to the .git/config file, as we did above. An alternative is to use git remote add NEWNAME URL. For example, if we want to access a git repository at the URL git://repohost/foodproject.git and be able to refer to the remote repository as toast, we could type:
$ git remote add toast git://repohost/foodproject.git $ cat .git/config [core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true [remote "toast"] url = file:///home/gitadmin/project1.git fetch = +refs/heads/*:refs/remotes/toast/*
The git remote add command added a default fetch line that results in git fetch fetching all branches (+refs/heads/*) from the remote host and mapping them to remote-tracking branches under refs/remotes/toast.
For example, a remote branch at refs/heads/master would then be mapped to a local remote-tracking branch at refs/remotes/toast/master and we could refer to this branch as toast/master.