Chapter 9

Exchanges between Repositories

Git is distributed. A repository can have many clones. Each developer has his or her own clone, maybe even several. Usually there is a project server with a central repository. This central repository represents the “official” status of a project and is also called the blessed repository. Often there are more clones, for example, for backups or on the server for continuous integration. Each clone by itself is an independent and full-fledged repository. In every clone, new commits and branches may be created. The exchange of information is therefore extremely important. For this purpose, there are fetch, pull and push commands.

Cloning A Repository

Repository cloning plays a major role in Git. There are many reasons to clone:

  • Every developer needs at least one clone to be able to work with Git.
  • Often, a clone is used as a central repository to represent the “official” status of the project.
  • In multi-site development, each site will have its main clone, which is regularly compared with the major clones in other locations.
  • For independent developments that take a different direction from the main project (for example, if you are planning major conversions) you often use your own clone. Such a clone is also called a fork.
  • When performing tricky work on the repository that could damage the project or repository, it is often useful to create a separate clone.
  • Tools for working with Git often use their own clone.
  • Clones are ideal as a backup for the main repository.

The clone command is very easy to use. You specify the location of the original repository as a parameter and Git will create a clone in the current working directory.

Normally, right after creating a clone, Git does a checkout in the workspace. If you do not want this, you can use the --bare option to create a repository without a workspace. This is useful for repositories on the server side, on which a developer works directly.

How to Tell Git Where the Other Repository Is

If the other repository is local, you can simply specify the path to the directory, eg /Users/stachi/git-book.git. For instance, the following command clones a local repository.

> git clone /Users/stachi/git-book.git 

However, if you are dealing with multiple repositories from different sources, the URL will look clearer if it is preceded by the protocol (in this case, file):

> git clone file:///Users/stachi/git-book.git 

In addition to file, other protocols can also be used to access non-local repositories. The ssh protocol is probably the most frequently used because it enables secure authentication and the infrastructure to do so is often already in place when working with Linux or Unix servers.

> git clone ssh://[email protected]:git-book.git 

On top of that, access is also made possible via the http, https, ftp, ftps, and rsync protocols or via a proprietary protocol called git.

Giving the Other Repository A Name

If you often access a repository, you may want to give it a name for easy access. You do this by using the remote add command followed by a nickname.

> git remote add myClone file:///tmp/git-book-clone.git

You can then use the short name, myClone in this example, instead of the repository URL with Git commands.

When cloning a repository, Git automatically stores the path to the original repository as its origin. If you call the remote command with the --verbose option, Git will list the links and show which paths were used for fetching or pushing the commits.

> git remote --verbose 

origin ssh://[email protected]:git-book.git (fetch) 
origin [email protected]:rpreissel/git-workflows.git (push) 
klon file:///tmp/git-book-clone.git (fetch) 
klon file:///tmp/git-book-clone.git (push)

You can delete a nickname using the remote rm command.

> git remote rm myClone

Fetching Data

If work continues after cloning, the original repository and the clone will drift apart. New commits as well as branches may be created in either repository.

The fetch command fetches commits from another repository. For each branch in the other repository, fetch transfers all commits that are not yet available locally,

> git fetch myClone

Figure 9.1: Before and after a fetch

Figure 9.1 shows what is happening here:

  • D and E. The fetch command fetches commits that are still missing locally from the remote repository.
  • A, B and C. Commits that are already present locally naturally are not transmitted.
  • F. The fetch command operates in one direction. Commits are only transmitted from the remote repository to the local repository. To transfer local commits to the remote repository, use the push command.

Note that fetch is unidirectional. In the example, commits were transferred from the clone repository to the local repository. None of the new local commits was transferred to the clone.

You can specify a branch as a parameter to pick changes from that particular branch only. If you do not specify a parameter, fetch will fetch commits from all branches in the repository of origin, which is the repository from which the local repository has been cloned.

Remote-Tracking Branches: Monitoring Other Repositories

Figure 9.2: Remote-tracking branches

There are two types of branches, local and remote-tracking. You have learned about local branches, and now you will learn about remote-tracking branches too.

With a fetch, Git sets bookmarks that point to the locations of the branches in the other repository. These bookmarks are called remote tracking branches. A remote-tracking branch consists of a short name for the other repository and the name of the branch in the other repository. In Figure 9.2, clone/feature-a and clone/master are remote-tracking branches. Use the -r option with the branch command to show remote-tracking branches.

> git branch -r 

clone/feature-a 
clone/master 
origin/HEAD -> origin/master 
origin/feature-a 
origin/master

You can compare your local branches with what other developers have done in the meantime. The diff command shows how the versions differ.

> git diff feature-a clone/feature-a 

Use the log command to show which commits were added from the remote repository.

> git log --oneline feature-a..klon/feature-a 

The next time you do a fetch, the remote-tracking branches will be updated again.

Note: Git treats remote-tracking branches differently from local branches. You can check out a remote-tracking branch just like a local one, but this puts you in a detached HEAD state (just like checking out an old commit). Instead, you should branch off a local branch from the remote- tracking branch, as described in the next section.

> git checkout -b feature-b clone/feature-b

Working with Local Branches from Other Repositories

You can also create a local branch with a fetch. To do this, use the colon (:). Specify the name of the branch from the other repository before the colon and the name of the local branch after the colon.

> git fetch clone feature-b:my-feature-b 

This command fetches branch feature-b from repository clone and branches thereof. A local branch named my-feature-b will be created if none exists or updated if it already exists.

Pull = Fetch + Merge

A fetch often causes conflicts, because new commits have been added locally or to the other repository. In most cases, a merge is appropriate.

Figure 9.3: Double heads after a fetch. The commit that did not get picked up is highlighted

The pull command does exactly that: it imports commits from a remote repository and if necessary does a merge on the current branch (see Figure 9.4).

> git pull

Figure 9.4: After a pull. The commit that did not get picked up and the merge commit are highlighted

For Diamond Haters: --rebase

Those who prefer a linear history can use the pull command with the --rebase option. Then, a rebasing instead of a merge will be performed (see Figure 9.5).

> git pull --rebase

Figure 9.5: After a pull. Highlighted is the shifted commit

Push, the Opposite of Pull

You use the push command to transfer commits from the local repository to a remote repository. For example, the following command transfers new local commits on the feature-a branch to a remote repository pointed by clone and updates the branch pointer to feature-a there.

> git push clone feature-a 

There are a few important differences between push and pull that you should consider:

  • Write access: push only works if you have write access on the other repository.
  • Fast-forward only: A push never leads to a merge (unlike the pull command). A push is only permitted in fast-forward settings, i.e., when no new commits have been added to the branch in the other repository.
  • No remote tracking branches
  • Calling push without parameters: Without parameters, push will only send those local branches for which there is match with the same name in the other repository. On the other hand, pull and fetch pick up all the branches.

Note that Git will refuse to push if fast-forward is not possible. You can, however, force it with the --force option. However, you should not do that, because this could result in a commit being lost in the other repository. It is always better to resolve conflicts locally, as described in the following step by step instructions.

Naming Branches

It is often advisable to agree on uniform branch names when working together in a software team.

Git gives the developer the freedom to name local branches. If you do this, you must use the colon in the parameters for fetch, pull or push. The word before the colon specifies the source branch and the word after the colon specifies the target branch. Consider the following example.

> git pull clone feature-a:favorite-feature 

Here, pull imports the feature-a branch in repository clone and locally names the branch favorite-feature.

Deleting a branch in a remote repository is a special case. In this case, you use the push command with a colon and leave the left side of the colon empty, implying setting the branch in question to nothing.

Summary

  • Repository URLs: The location of a remote repository can be specified in URL format, e.g. ssh://[email protected]:git-book.git. The following protocols are supported: file, ssh, http, https, ftp, ftps, rsync and git.
  • Nicknames: You can define a nickname for a repository with the remote command, so you do not have to specify the long URL every time you need to access the repository.
  • Fetch: The fetch command fetches commits on branches from a remote repository. Of course, it will only transfer commits that are not locally available yet.
  • Fetch without parameters: Retrieves the commits for all branches in the remote repository.
  • Fetch without moving local branches: This will only fetch commits and then set remote-tracking branches.
  • Remote-tracking branches: You indicate the location of branches in remote repositories, e.g. clone/feature-a. The fetch and pull commands update the remote tracking branches.
  • Pull = fetch + merge: The pull command is a combination of two operations. It first does a fetch. Thereafter, it merges the local changes in the currnet branch with changes that have been retrieved from the remote repository.
  • Push: The push command transfers commits in local branches to a remote repository.
  • Push transfers branches: Branch pointers are set in the remote repository. These are set to the state of the local repository.
  • Push fast-forward only! Git will reject a push if another developer has done a push on the same branch, such that fast-forward is not possible. In this case, the changes must first be brought together locally, for example by using a pull.
  • Push without parameters: In this case, only local branches with identically named matches in the remote repository will be transferred.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.216.27.251