DEV Community

Cover image for Git for grad students (part 2)
TuanNQ
TuanNQ

Posted on • Edited on

Git for grad students (part 2)

In the first article I talk about the basic of Git versioning.

In this article we'll talk about a revolutionary feature of Git: branch.

What problem does Git branch solves?

Back to our Google Slides example.

Make a copy of group's file

Leader review changes and then merge

To solve the accidentally changed problem, anyone want to the edit group's slide would have to do this:

  • Create a copy of the group's Google Slides file
  • Work on that copied file
  • Ask the leader to review
  • Only when the leader agree that changes are merged into the group's file

In order to preserve the original file, anyone wants to work on that file must create a copy of it. In the Git world, it's everyone must create a new branch.

Make a copy equivalent to new Git branch

Wait, you said. If 1 people create a copy, working on it, and then the leader upload that into Google Drive is fine, but what if 3 people do it at the same time?

3 people make copies at the same time

Does the leader have to meticulously copy and paste all changes of each file into a new file and then upload?

Am I have to manually copy each change?

In the development world, don't worry, Git will handle that for us!

Git automatically merge changes into one file

Call git merge and Git will automatically merge all changes for us!

Git merge explain

If 2 people accidentally make change in the same line of the same file, Git will notify you about that "conflict".

Git resolve conflicts explain

To recap:

  • Create a copy = create a new branch
  • Merge into one file = merge branch
  • 2 people change the same place = conflict (and then have to resolve conflict)

Let's learn how to do all of that with Git in this article.

Basic workflow

In this section, let's talk about what would you do when leader assign you a new task (aka basic workflow).

By default, you're on branch master. For now let's imagine the master branch is like the original file that shares to the whole group.

If you have a new task, here's what you need to do:

  • Create a new branch (= copy to a new file)
  • Do the task then git add and git commit -m (= create a new version)
  • Merge back into the master branch (= merge back into the original file)

Git simple local workflow

Let's apply that workflow with the previous project in part 1.

View, create, merge branch

In part 1, we created a small project to learn about Git. Here's the current state of that project.

Git project explain so far

To see what branch that we're on, use the following command:

git branch
Enter fullscreen mode Exit fullscreen mode

Here's the result of mine:

  * master
Enter fullscreen mode Exit fullscreen mode

This meant that I'm in branch master.

Git explain so far with master branch

Imagine you have a new task: add to index.js a console.log("bye there").

Following the workflow, here are steps to take:

  • Create a new branch (= copy to a new file)
  • Add to index.js a console.log("bye there") (do the job)
  • git add and git commit -m (= create a new version)
  • Merge back into the master branch (= merge back into the original file)

Git plan to complete new task

Step 1, let's create a new branch. To create a new branch, use git checkout -b and then name of the branch.

I'll call this branch feature/bye_there.

git checkout -b feature/bye_there
Enter fullscreen mode Exit fullscreen mode

Create new branch feature/bye_there

It's easy to get lost on which branch are we on so let's create a good habit to check what branch are we currently on:

git branch
Enter fullscreen mode Exit fullscreen mode

Here's mine:

* feature/bye_there
  master
Enter fullscreen mode Exit fullscreen mode

This meant that currently I have 2 branch master and feature/bye_there and I'm in branch feature/bye_there.

Create new branch feature/bye_there

In index.js, add a console.log("bye there"):

console.log("hello there");
console.log("bye there");
Enter fullscreen mode Exit fullscreen mode

Now let's commit it:

git add index.js
Enter fullscreen mode Exit fullscreen mode

then

git commit -m "[feature] add bye there"
Enter fullscreen mode Exit fullscreen mode

Here's a diagram explain what we did so far:

Git commit in branch feature/bye_there

Great! We complete this feature and then commit it. Next, let's merge it into the master branch. In order to do that, we have to take 2 steps:

  • Switch to master branch: git checkout master
  • Merge feature/bye_there into master: git merge feature/bye_there

So first, let's switch back to the master branch:

git checkout master
Enter fullscreen mode Exit fullscreen mode

Checkout to master branch

Next, let's merge the feature/bye_there branch into master:

git merge feature/bye_there
Enter fullscreen mode Exit fullscreen mode

Git branch feature/bye_there merge with master branch

If you open index.js you'll see:

console.log("hello there");
console.log("bye there");
Enter fullscreen mode Exit fullscreen mode

We're successfully merge feature/bye_there into master. Here's a little more explanation about git merge.

When you tell git to merge feature/bye_there into master, git will apply all the changes you made in feature/bye_there into master.

What changes are we made in feature/bye_there? It's:

  • In index.js add line 2 writing console.log("bye there")

So here's what git does:

  • Apply change: in index.js add line 2 writing console.log("bye there")
  • Add and commit on master branch

Git merge explain

To recap, here's 5 git commands step-by-step to complete a new task:

  • git checkout -b [new branch]
  • git add [file name]
  • git commit -m [message]
  • git checkout master
  • git merge [new branch]

Conflict and resolve conflict

Now you get the basic idea of what to do when having a new task, let's talk about conflict. When do conflict happen and how to resolve conflict? In this section we'll create a situation when conflict occurs and then resolve it.

Imagine you have 2 people that receive 2 new tasks at the same time:

  • Task #1: Add console.log(1) in main.js file
  • Task #2: Add console.log(2) in main.js file

This 2 people will create new branch at the same time and do their work at the same time instead of one after another. Here's a diagram explains the different between doing multiple tasks at the same time versus to do it sequentially:

Git do multiple tasks at the same time vs sequential

To simulate this, we'll create new branch feature/print_1, do the task and then git add and git commit -m, but not immediately merge into master, instead from master create feature/print_2, do the task and commit on that branch, and only then merge feature/print_1 and feature/print_2 into master.

If that's a little bit... hard to understand, below it's a diagram explain what we're going to do:

Git do 2 tasks simultaneously plan

Let's tackle task #1 first. Here are the steps we need to take:

  • Create a new branch
  • Add file main.js with console.log(1)
  • git add and git commit -m

First, let's create a good habit of checking which branch we're on:

git branch
Enter fullscreen mode Exit fullscreen mode

Here's my result:

  feature/bye_there
* master
Enter fullscreen mode Exit fullscreen mode

This means that I'm on the master branch. Make sure you're on the master branch before continue.

Git branch feature/bye_there merge with master branch

Next, let's create a new branch called feature/print_1.

git checkout -b feature/print_1
Enter fullscreen mode Exit fullscreen mode

Git with new branch feature/print_1

Let's check what branch are we on:

git branch
Enter fullscreen mode Exit fullscreen mode

Here's my result:

  feature/bye_there
* feature/print_1
  master
Enter fullscreen mode Exit fullscreen mode

This means that we have 3 branches and I'm on branch feature/print_1.

Git with new branch feature/print_1

Now, complete task #1 by create main.js file with the following content:

console.log(1)
Enter fullscreen mode Exit fullscreen mode

Now, let's commit this file:

git add main.js
Enter fullscreen mode Exit fullscreen mode

then

git commit -m "[feature] add console log 1"
Enter fullscreen mode Exit fullscreen mode

Complete task print 1

Normally the last step is to merge feature/print_1 into the master branch but as we're not going to do it right now. We're simulating 2 people create new branch at the same time and working at the same time, remember?

We've already complete task #1. Let's tackle the task #2.

Here are the steps we need to take:

  • Switch to master branch
  • Create a new branch
  • Add file main.js with console.log(2)

First, let's switch to the master branch:

git checkout master
Enter fullscreen mode Exit fullscreen mode

Checkout to master

Now you'll see the main.js file disappear because in master branch that file does not exist yet.

Let's create a new branch called feature/print_2:

git checkout -b feature/print_2
Enter fullscreen mode Exit fullscreen mode

Git create new branch feature/print_2

Let's create a good habit of checking what branch are we on:

git branch
Enter fullscreen mode Exit fullscreen mode

Here's my result:

  feature/bye_there
  feature/print_1
* feature/print_2
  master
Enter fullscreen mode Exit fullscreen mode

This means that we have 4 branches and I'm on branch feature/print_2.

Git create new branch feature/print_2

Now, let's do the task #2 by create main.js file with the following content:

console.log(2)
Enter fullscreen mode Exit fullscreen mode

Next, let's commit this file:

git add main.js
Enter fullscreen mode Exit fullscreen mode

then

git commit -m "[feature] add console log 2"
Enter fullscreen mode Exit fullscreen mode

Complete task print 2

That's great! We've complete task #2.

Now let's head back to the master branch and merge feature/print_1 and feature/print_2 into it.

git checkout master
Enter fullscreen mode Exit fullscreen mode

Checkout to master

Let's merge feature/print_1 into master:

git merge feature/print_1
Enter fullscreen mode Exit fullscreen mode

Merge branch feature/print_1 into master

Next, let's merge feature/print_2 into master:

git merge feature/print_2
Enter fullscreen mode Exit fullscreen mode

Merge branch feature/print_2 into master

This is when conflict occurs. You'll see the following in the command line:

Auto-merging main.js
CONFLICT (add/add): Merge conflict in main.js
Automatic merge failed; fix conflicts and then commit the result.
Enter fullscreen mode Exit fullscreen mode

We have a conflict in main.js. If you open main.js, you'll see this:

<<<<<<< HEAD
console.log(1);
=======
console.log(2);
>>>>>>> feature/print_2
Enter fullscreen mode Exit fullscreen mode

If you using VSCode, here's what you see:

Git conflicts show in VSCode

Git marks which place have conflict for us by <<<< HEAD, ======, >>>>> feature/print_2. Our job is to make the file correct according to what we're assigned.

But first let's explain why do we have conflict in main.js, what is "HEAD (current change)" and "incoming change" means.

In short, conflict happened because both feature/print_1 and feature/print_2 in the same main.js file in the same line have different content (more exactly is changed differently). In feature/print_1 is console.log(1). In feature/print_2 is console.log(2).

The HEAD refer to which branch we're now: master branch, while "Incoming change" refer to the branch we want to merge into master: feature/print_2.

Here's a more detailed explanation:

First, when we merge feature/print_1 into master, git will apply the changes in feature/print_1 into master. So here's what git does:

  • Create a new main.js file
  • On that file main.js on line 1 write console.log(1)
  • Add and commit (in master branch)

Merge branch feature/print_1 into master explain

Next, when we merge feature/print_2 into master, git will also apply the changes in feature/print_2 into master. So here's what git tried to do:

  • Create a new file main.js (already done!)
  • On main.js on line 1 write console.log(2)
  • Add and commit (in master branch)

But on main.js line 1 already have console.log(1). This is why conflict happened.

Merge branch feature/print_2 into master conflict explain

So how do we resolve this conflict? In this situation, we have to do both tasks so we should keep both console.logs.

In main.js remove the <<<<< HEAD, =====, >>>>> feature/print_2 added by git:

console.log(1);
console.log(2);
Enter fullscreen mode Exit fullscreen mode

Now the main.js file have both console.log, which is correct for we have to do both task #1 and task #2. Now that we resolve conflict, let's add and commit the main.js file:

git add main.js
Enter fullscreen mode Exit fullscreen mode

then

git commit -m "Merge branch 'feature/print_2'"
Enter fullscreen mode Exit fullscreen mode

That's it! That's how we resolve conflict!

Explain strange commands from part 1

In part 1, I told you about 2 strange command git checkout master and git switch -c. Now I'll explain it.

By now you probably know that first command git checkout master is to switch to master branch. But not only you can use it to switch from one branch to another but also to escape preview mode too. If you're on feature/print_1 branch and using git checkout [version hash] to preview previous, you can use git checkout feature/print_1 to escape it!

The command git switch -c is to create a new branch from that commit and switch to that branch. That way, you don't have to use git reset --hard which lose all commits after that.

Git switch -c explain

A fun thought experiment

So that's it for part 2. You've done a great job learning all the basic workflow and commands of git! You can reward yourself a good cup of coffee now!

But I have a bonus thought exercise to get you more familiar with the concept of branch and basic commands of git.

Have you ever seen this meme?

Photoshop designer meme

Have you ever heard your designer friend complains about he spend hours to change his design for his customer just to be told: "Hey, I changed my mind, I think the original design is better"? Worse, he had to edit it back into the original design because the amount Ctrl + Z 's are limited.

Now you're a developer and you know Git, what would you hypothetically do if you're in this situation:

  • The customer asks you to edit her photo
  • Then she asks you to add more dramatic lighting
  • Then she asks you to use Liquidfy to make her look thinner
  • Then she kind of regret it and asks you to revert it (oh no it looks so fake!)
  • Then she asks you to make her hair pink
  • Then she asks you to make her hair blue to see which one is better
  • Then she says she like pink hair
  • Then she asks you to make her eyes look bigger
  • She satisfies now, pays you and thanks for your service

If you don't know what Liquidfy does, I have this image which will explain for you:

Liquidfy explain

So with that little bit of Liquidfy technical detail out of the way, hypothetically how can we solve this using git?

Here's a diagram explains what we're going to do:

Git photoshop plan

Assume we have a Photoshop file called cute-photo.psd:

  • The customer asks you to edit her photo
    • git init
    • git add cute-photo.psd
    • git commit -m "initial commit"
  • Then she asks you to add more dramatic lighting
    • git checkout -b feature/dramatic_lighting
    • git add cute-photo.psd
    • git commit -m "[feature] add dramatic lighting"
    • git checkout master
    • git merge feature/dramatic_lighting
  • Then she asks you to use Liquidfy to make her look thinner
    • git checkout -b feature/liquidfy
    • git add cute-photo.psd
    • git commit -m "[feature] liquidfy thinner"
    • git checkout master
    • git merge feature/liquidfy
  • Then she kind of regret it and asks you to revert it (oh no it looks so fake!)
    • git reset --hard [commit-hash]
  • Then she asks you to make her hair pink
    • git checkout -b feature/hair_pink
    • git add cute-photo.psd
    • git commit -m "[feature] change hair to pink"
  • Then she asks you to make her hair blue to see which one is better
    • git checkout master
    • git checkout -b feature/hair_blue
    • git add cute-photo.psd
    • git commit -m "[feature] change hair to blue
  • Then she says she like pink hair
    • git checkout master
    • git merge feature/hair_pink
  • Then she asks you to make her eyes look bigger
    • git checkout -b feature/eyes_bigger
    • git add cute-photo.psd
    • git commit -m "[feature] make eyes bigger"
    • git checkout master
    • git merge feature/eyes_bigger
  • She satisfy now, pays you and thanks for your service

You might ask why don't people use Git in design space like Photoshop, Illustrator, Blender, Maya,... Is git only works for text files or something?

No it's not. You can definitely version control a .psd or an .ai,... file. If you git add, git commit -m,... it works! The reason people don't do it is that if conflict happen, you can't fix it. Photoshop file is a binary file, which is a bunch of 0's and 1's, you can't read and understand it, let alone resolve conflict.

Conclusion

Let's recap what we've learned so far:

  • git branch: view current branch we're in
  • git checkout [branch name]: switch to that branch
  • git checkout -b [new branch]: create new branch
  • git merge [branch name]: merge that branch into current branch we're in
  • Conflict and how to resolve conflict

In part 3 we'll learn about how to work with remote repository like Github, Gitlab: git push, git pull, git clone,...

Credits

If you like the cute fish that I'm using, check out: https://thenounproject.com/browse/collection-icon/stripe-emotions-106667/.

Cute fish

Top comments (0)