GIT Part-6


Remote repositories
Git, as we have seen in the introduction, is a distributed VCS. This means that, apart from the local, we can have a copy of the repository hosted in a remote server that, apart from making public the source code of the project, is used for collaborative development.

The most popular platform for Git repositories hosting is GitHub. Unfortunately, GitHub does not offer private repositories in its free plan. If you need a hosting platform with unlimited private repositories, you can use Bitbucket. And, if you are looking for hosting your repositories in your own server, the available option is GitLab.

For this section, we will need to use one of the options mentioned above.

Writing changes in the remote
The first thing we need to do in the remote hosting is to create a repository, for which a URL with the following format will be created:
https://hosting-service.com/username/repository-name
Once having a remote repository, we have to link it with our local repo. This is made with the remote add <remote-name> <repo-url> command:

git remote add origin https://hosting-service.com/username/repository-name

origin is which is named by default by Git, similarly to master branch, but it does not have to be necessarily.

Now, in our local repository, the remote repository is identified as origin. We can now start to “send” information to it, which is made with push option:

git push [remote-name] [branch-name | --all] [--tags]

Let’s see some examples of how it works:



git push origin --all      # Updates the remote with all the local branches
git push origin master dev # Updates remote's mater and dev branches
git push origin --tags     # Sends tags to remotes

This is an example output of a successful master branch update:




Counting objects: 3, done.
Writing objects: 100% (3/3), 235 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To https://hosting-service.com/username/repository-name.git
 * [new branch]      master -> master

What has Git internally with this?
Well, now, a directory .git/refs/remotes has been created, and, inside it, another directory, origin (because that’s the name we have given to the remote). Here, Git creates a file for each branch exiting in the remote repository, with a reference to it. This reference is just the SHA1 id of the last commit of the given branch of the remote repository. This is used by Git to know if in remote repo are any changes that can be applied to the local repository. We will cover this in detail later in the following sections.

Note: a repository can have as many remotes as we want. For example, we could have the remote of the same repository in both GitHub and Bitbucket:


git remote add github https://github.com/username/repository-name
git remote add bitbucket https://bitbucket.org/username/repository-name

Cloning a repository
The cloning of a repository is actually made once, when we are going to start to work with a remote repository.

For cloning remote repositories there’s no mystery, we just have to use the clone option, specifying the URL of the repository:

git clone https://hosting-service.com/username/repository-name

Which would create a local directory with the repository, with the reference to the remote it has been cloned from.

By default, when cloning a repository, only the default branch is created (master, generally). The way to create the other branches locally is making a checkout to them.
Remote branches can be shown with branch option with -r flag:


git branch -r

They will be shown with the format <remote-name>/<branch-name>. To create the local branch, is enough to make a checkout to <branch-name>.

Updating remote references: fetching
Fetching the remote repository means updating the reference of a local branch, to put it even with the remote branch.

Let’s consider a collaborative scenario where two developers are pushing changes to the same repo. In some moment, one of the developers wants to update its reference to master, to the last push of the other developer, as is shown in the following image.


The content of the .git/refs/remotes/origin/master file of Alice’s repository would be, before any update, the following:
5bfc81ce5f7a0b26b493be0c99f1966a1896c972

Bob’s, however, will be updated, since it has been him the last who has updated the remote repository:
37db4f82e346665f6048cc9e4b7cd48c83c6ebcb

Now, Alice wants to have in her local repository the changes made by Bob. For that, she has to fetch the master branch:

git fetch origin master
(Alternatively, she can fetch every branch with --all flag):
git fetch --all

The output of the fetch would be something similar to the following:





remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From https://hosting-service.com/alice/repository-name
 * branch            master     -> FETCH_HEAD
   5bfc81c..37db4f8  master     -> origin/master

And, now, the content of Alice’s .git/refs/remotes/origin/master file would be the same of remote’s:
37db4f82e346665f6048cc9e4b7cd48c83c6ebcb

With this, Alice has updated the reference to remote’s master branch, but the changes have not been applied in the repository.

fetch  does not apply changes directly to the local repository. Is the first of two steps that have to be made. The other step is to merge the remote branch, which has just been updated; with the local branch. This is just a merge as any other, but where the remote name has to be indicated:

git merge origin/master

Once the merge is finished, Alice will have the latest version of master branch.
Note: in this merge, we have not applied the no-fast forward. In this cases, would not have many sense to apply it, since we are merging the intrinsically same branch, but that is located somewhere else.

Fetching and merging remotes at once: pulling
Git has an option to apply remote changes at once, that is, fetching and merging the branch in one command. This option is pull.
Considering the exactly same scenario seen above, we could just execute:

git pull origin master

And would do the fetch, followed by the merge.
Use the way you fell more comfortable with. There’s no better way; actually, they do exactly the same, but expressed differently.

Conflicts updating remote repository
Let’s return to the scenario shown above. What would happen if, without updating her local repository, Alice would create a commit and push it to the remote repository? Well, she would receive an ugly message from Git:








! [rejected]        master -> master (fetch first)
error: failed to push some refs to 'https://hosting-service.com/alice/repository-name.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

The push would be rejected because Alice has not continued the history of the repository from a point that has been already registered in the remote. So, before writing changes in the remote repository, she would need first to fetch & merge, or pull, the remote with her changes.

A bad way to resolve conflicts
There’s still another way, which can not be exactly considered as resolving. Is about forcing pushes with --force flag.

Forcing a push is about, basically, one thing: overwrite the remote repository branch (or the whole repository) with the one that is being pushed. So, in the above scenario, if Alice forces a push of her repository, the 37db4f8 commit will disappear. This would leave Bob working in something similar to a “parallel universe” that cannot coexist with the current reality of the project, since his work is based on a state that no longer exist in the project.

In conclusion, don’t force pushes when you are working with other developers, at least if you don’t want to have an intense argument with them.

If you Google for “git force push” in the images section, you will see some memes that perfectly explain graphically what a forced push is considered as.


<< Previous                                                                                                                 Next >>



No comments:

Post a Comment