All Git Tales
July 31, 2026 Wilfried Nesensohn 5 min read

What comes around, goes around

Git's local model also powers collaboration. This tale follows commits through remotes, fetch, pull, tracking branches, and push.

Work Needs To Move

Understanding the Git basics is one thing, and working in a Git repository in isolation is certainly something you can - and probably should - do. Sometimes. And while Git is built on the assumption that you’re working locally in your repository, that’s not all there is to it. Interestingly, what makes Git shine in the local-first context also makes it shine in facilitating collaboration. But to collaborate, we somehow have to move changes in- and out of our repository.

Local

So how do we do that with Git? The answer is as simple and boring as it can be - commits. Yes, it’s that easy - we can just pack up a commit with all its referenced data (objects, identified by their content) and push those into another repository. There they happily live, and can be integrated where they need to be. To make moving these commits really easy, Git has the concept of remotes.

And Remote

A remote can be thought of as a pointer to another repository. The remote usually contains most, if not all of the data of your local repository. When you’re first cloning a repository, say from GitLab or GitHub, you’re essentially copying all the commits and branches from that repository to your local machine. Additionally, after this cloning step succeeds, Git will also add a pointer to the repository you’ve just cloned - a so-called remote. The remote you’ve cloned from is - by convention - called origin.

Now that we’ve established these terms, what useful things can we do with the remote and local repository which are linked together with a remote?

Fetch

Fetching from a remote is just a way to get the latest branches and commits from that repository. Essentially it copies all of the new data from the remote into your local repository. However, it doesn’t alter any of your local branches or commits, it just fetches them so you can do useful things with them later on.

Such a useful thing can be a merge, for example. If you want to merge changes from the remote into a local branch of yours, you can do so after fetching these changes. Often, you’ll be working on a branch which also exists on the remote, and your local branch will be somehow connected to this remote branch. When branches are connected in such a way, Git calls this tracking. You can say that your local branch tracks the remote branch. Now if you fetch the remote branch, you can then merge this remote branch into your local branch, essentially combining them.

Pull

Because that is such a useful thing to do, Git has its very own name for it. It’s called pull, which is a fetch of a branch, followed by a merge of the tracked branch into your local branch.

Git afficionados will probably cough a little right now, because I’ve left out an important part of the pull, namely the fetch-rebase pull. However, for brevities sake, let’s not get ahead of ourselves. Rebases, although simple in concept and important in practice, get their own stage.

Now that we’ve got our changes using fetch, and incorporated these changes using merge (or, as a one-step-operation, pull) we’re almost collaborating. Almost, since we need a way to put our changes on the remote repository again. It’s almost hard to explain this subject without using the proper Git term for this operation, which is called push.

Push

A push on a remote is just the act of copying the new commits into the remote repository, and adjusting the remote branch to match your local branch. It’s kind-of the reverse of a pull, but with no way of really doing a merge remotely, it’s a bit more limited. In a good way. By default, Git will only allow you to push changes onto a branch if they are provably compatible with your changes. And the easiest and safest way to prove compatibility is when all of your changes are based on the remote branch, which means that the remote branch is just advancing by a few commits, and never going backwards in history.

And It’s Safe!

The former also means that collaboration of multiple users on a single branch is a safe thing to do, as Git will reject a push if in the meantime someone else modified the remote branch. To get going again, just pull the remote changes into your repository and push again, resolving any conflicts that might’ve happened beforehand.

Especially in the beginning of your Git journeys, this behaviour of Git makes sure that you’re never going to lose data in your remote repository by pushing onto it. It’s a sensible default. There are ways to tell Git that you know better, and if you really want you can force-push your remote into oblivion, but you have to convince Git (sometimes very deliberately) to do so. Rest assured that this is not something that just happens. You not only have to aim onto your foot to shoot it. You have to fill out some paperwork before as well.

So now you have everything you need to collaborate with others, in a safe way. Nice.

RemotesFetch and pullPush safety