February 11, 2019
The most powerful, and sometimes powerfully frustrating, aspect of Git is the collaborative workflow it enables. In order to really learn Git workflow, you need to work through conflict, which means you need to work with a team. This tutorial introduces the centralized model for collaboration and is designed for two to work through together. If you’re just joining us, you may want to Learn Git Workflow Basics
You will learn:
You don’t necessarily need a partner to follow along, but you won’t be able to perform all of the operations without a collaborator unless you configure two profiles to switch between.
Can’t find a partner? Hit me up @jarednielsen
When you initialize a new repository, a master branch is created by default. A centralized workflow uses only the master branch. We will learn to use branches in the next article.
Go to GitHub.com and create a new repo named
Initialize it with a
Under Settings, select the Collaborators menu option.
In the field in the Collaborators panel, search for your partners GitHub account and click Add collaborators.
This will send an email to your partner. Alternatively, you can select the Copy invite link and send it by other means.
Accept the invitation.
From the command line:
git clone <URL-to-git-workflow-centralized> cd git-workflow-centralized
Verify that you both have the repository cloned locally.
Recall that the Git workflow model is EDIT, STAGE, COMMIT. Create an index.html file:
Add boilerplate HTML:
<!DOCTYPE html> <html> <head> <title>Git Workflow, Centralized</title> </head> <body> <h1>Git Workflow, Centralized</h1> </body> </html>
You should have ~9 lines of code. Save it. Then add, commit, and push to the remote origin:
git add . git commit -m “Created index.html” git push
Pull the repo after your partner’s push. Verify that you both have boilerplate
ls cat index.html
index.html and add this image tag directly below
<h1>, on line 8, replacing the
alt attribute with your name:
<img src=”https://gph.is/1nQGqSa” alt=”Jack” >
Save, then add, commit and push.
After your partner pushes the changes, without making a new pull, add this image tag directly below
<h1>, on line 8:
<img src="https://gph.is/191zeP3" alt=”Jill” >
Save, then add, commit and push.
Uh oh! Errors!
To github.com:<repo-owners-name>/git-workflow-centralized.git ! [rejected] master -> master (fetch first) error: failed to push some refs to 'email@example.com:<repo-owners-name>/git-workflow-centralized.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.
Git prevents you from overwriting official commits. You need to pull your partners’ updates into your repository, integrate them with your local changes, and then try again.
If we read the response from Git in the console, we get a hint at what we need to do. What is it?
Uh oh again! When we run
git pull, we get another error!
Auto-merging index.html CONFLICT (content): Merge conflict in index.html Automatic merge failed; fix conflicts and then commit the result.
You and your partner have conflicts! And you’re just getting to know each other…
Open index.html in your IDE. You will see something similar to this:
<<<<<<< HEAD <img src="https://gph.is/191zeP3" alt=”Jill” > ======= <img src=”https://gph.is/1nQGqSa” alt="Jack"> >>>>>>> edf14c1afac38dd473d5ff2a75da6ccdbcf7cacc
Where did that noise come from? Git. The angle brackets and equal signs demarcate the conflicting code. Here, it’s the two images you and your partner added.
HEAD is a reference to the last commit in the currently checked-out branch (in our case,
master). The last commit was the image Partner 2 added, so, as you can see, that is the
HEAD. That long string of numbers is a hash for the purposes of tracking.
index.html so both images will be rendered. Do this by deleting the angle brackets, HEAD, equal signs and hash. Save, then add, commit and push. Be sure to give your commit a useful message like, “Resolved conflict between images”. Your HTML should now look something like this:
<!DOCTYPE html> <html> <head> <title>Workflow Centralized</title> </head> <body> <h1>Workflow Centralized</h1> <img src=”https://gph.is/1nQGqSa” alt="First image"> <img src="https://gph.is/191zeP3" alt=”Second image” > </body> </html>
With great power comes great responsibility. It’s very easy to erase hours of work when resolving conflicts. What is the solution to this problem?
Update your local copy with the changes to the remote:
Add a link to an external stylesheet to
<title> in the
<head>, add a new line and this element:
<link rel="stylesheet" href="style.css">
Save, then add, commit and push.
From the command line, create two new files named, you guessed it,
touch app.js style.css
Add, commit and push the new files.
Git tells you that your local branch is out of sync with the remote. What do we do?
When you run git pull, your screen will change and you will be presented with something similar to this:
Merge branch 'master' of github.com:<repo-owners-name>/git-workflow-centralized # Please enter a commit message to explain why this merge is necessary, # especially if it merges an updated upstream into a topic branch. # # Lines starting with '#' will be ignored, and an empty message aborts # the commit. ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ "~/apps/git-workflow-centralized/.git/MERGE_MSG" 7L, 297C
Check out the bar at the top of your Terminal. It should read something like this:
git-workflow-centralized -- vi < git pull
If you haven’t already discovered it, built-in to your Terminal (or Git Bash) is a text editor, vi (also referred to as vim). This allows us to edit files from within the Terminal, rather than opening them in an IDE.
Note the readout at the bottom of your Terminal, something like this:
"~/apps/git-workflow-centralized/.git/MERGE_MSG" 7L, 297C
That is the absolute path to the git file you are currently editing.
You are being presented with this screen as an opportunity to add a message to the merge you are about to make. You are not required to add a message, but, if you recall, Linus Torvalds created Git. He is a character. Here he is announcing this ‘functionality’ many years ago:
Spreading the word about an upcoming ‘git’ UI change, since I’m largely to blame. This change hopefully makes people write merge messages to explain their merges, and maybe even decide not to merge at all when it’s not necessary. I’ve been using that git feature for the last few weeks now, and it has resulted in my merges from submaintainers having various notes in them (well, at least if the submainter gave me any). So I’m trying to lead by example. But if you don’t like explaining your merges, this might be annoying. Of course, if you don’t explain your merges, you are annoying, so it all evens out in the end. “Karmic balance”, so to say.
Bottom line? Write a useful message.
vi may be configured differently for everyone. So if you attempt to add a message and nothing happens, press
i. This is the vi keyboard shortcut for
INSERT, which you should now see at the bottom of your Terminal.
Add a message. When you are finished typing, press
ESC. You will notice that
INSERT disappeared. You are no longer in ‘edit’ mode. You now need to save your changes and exit the file. Enter the following:
The colon is required, it’s how you tell vi that you are entering commands. As you enter these commands, you will see them appear in the bottom of your Terminal. What do you think
q signify? Write and Quit.
Voila! You successfully merged a commit to your project without conflict.
Unless, of course, you and your partner are not so chummy.
Delete this repository or create a new one, swap roles, and go through this process again.
One of the most useful, but potentially confusing, aspects of git is the ability for developers to create branches of a project to test new features. In the next article, we will Learn Git Branch Workflow.
Want to level up your problem solving skills? I write a weekly newsletter about programming, problem solving and lifelong learning. Join now