4. How do git branches work?#

Today we are going to work with branches offline to begin to understand them better.

4.1. Git cheatsheets#

High quality, correct refrences are important to gaining an understanding and being able to use tools well.

Important

Checking for factual information is not reliable in LLMs. They can be a helpful coding assistant when you know what you want, buut they generate text that cannot be fact checked.

We are going to work between the browser and locally in order to simulate scenarios that most often occur in collaboration, but can also occur working alone as well.

4.2. Back to the gh-inclass repo#

Recall, We can move around and examine the computer’s file structure using shell commands.

Open a new terminal window and navigate to your folder for the course (the one that contains other folders)

To confirm our current working directory we print it with pwd

pwd
/Users/brownsarahm

now change the path

cd Documents/inclass/systems/

then we can see what is there

ls
gh-inclass-brownsarahm

and finally go into the gh-inclass repo

cd gh-inclass-brownsarahm/

this confirms what we expect

Now let’s see what is in our folder:

ls
README.md	about.md

and check in with git

git status
On branch 1-create-a-readme
Your branch is up to date with 'origin/1-create-a-readme'.

nothing to commit, working tree clean

4.3. Branches do not sync automatically#

Now we will look in GitHub and see what is there.

getting to GitHub from your local system

the step below requires that you have the gh CLI.

gh repo view --web
Opening github.com/compsys-progtools/gh-inclass-brownsarahm in your browser.

Once we are in the browser, we created a PR for the readme branch then merged it.

Once we merge the PR, the closing keyword that was in our commit message applies. The closinng keyword did not apply on the non default branch, but it does once that commit is added to the default branch, which, in this repo is main.

git  status
On branch 1-create-a-readme
Your branch is up to date with 'origin/1-create-a-readme'.

nothing to commit, working tree clean

Now we go back to the main branch

git checkout main
Switched to branch 'main'
Your branch is up to date with 'origin/main'.

It thinks that we are up to date because it does not know about the changes to origin/main yet.

ls
about.md

the file is missing. It said it was up to date with origin main, but that is the most recent time we checked github only. It’s up to date with our local record of what is on GitHub, not the current GitHub.

Next, we will update locally, with git fetch

git fetch
remote: Enumerating objects: 1, done.
remote: Counting objects: 100% (1/1), done.
remote: Total 1 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
Unpacking objects: 100% (1/1), 911 bytes | 455.00 KiB/s, done.
From https://github.com/compsys-progtools/gh-inclass-brownsarahm
   0e7c990..0c12714  main       -> origin/main

Here we see 2 sets of messages. Some lines start with “remote” and other lines do not. The “remote” lines are what git on the GitHub server said in response to our request and the other lines are what git on your local computer said.

So, here, it counted up the content, and then sent it on GitHub’s side. On the local side, it unpacked (remember git compressed the content before we sent it). It describes the changes that were made on the GitHub side, the main branch was moved from one commit to another. So it then updates the local main branch accordingly (“Updating 6a12db0…caeacb5”).

We can see that if this updates the working directory too:

ls

no changes yet. fetch updates the .git directory so that git knows more, but does not update our local file system.

about.md

4.3.1. Git Merge#

When branches need to be merged they could look like this:

gitGraph commit id:"D" commit id:"E" branch origin/main checkout origin/main commit id:"A" checkout main commit id:"F" checkout origin/main commit id:"B" checkout main commit id:"G" checkout origin/main commit id:"C"

After merge, it looks like this:

gitGraph commit id:"D" commit id:"E" branch origin/main checkout origin/main commit id:"A" checkout main commit id:"F" checkout origin/main commit id:"B" checkout main commit id:"G" checkout origin/main commit id:"C" checkout main merge origin/main id:"H (contains A,B,C)"

There is a new commit with the content.

In our case it is simpler:

gitGraph commit id:"D" commit id:"E" branch origin/main checkout origin/main commit id:"A"

so it will fast forward

gitGraph commit id:"D" commit id:"E" commit id:"A"

4.3.2. git rebase#

If a repo is like this:

gitGraph commit id:"D" commit id:"E" branch topic checkout topic commit id:"A" checkout main commit id:"F" checkout topic commit id:"B" checkout main commit id:"G" checkout topic commit id:"C" checkout main %% merge topic id:"H (contains A,B,C)"

after:

gitGraph commit id:"D" commit id:"E" commit id:"F" commit id:"G" branch topic checkout topic commit id:"A'" commit id:"B'" commit id:"C'" checkout main

4.4. Git Pull#

remember git pull does:

  1. git fetch

  2. git merge (default, if possible) or git rebase (if settings or with option)

git pull
Updating 0e7c990..0c12714
Fast-forward
 README.md | 3 +++
 1 file changed, 3 insertions(+)
 create mode 100644 README.md

Now, we can check again

ls
README.md	about.md

and it looks as expected

4.5. Viewing Commit History#

We can see commits with git log

git log
commit 0c1271483e62e69b8b3fc329203617b7093413df (HEAD -> main, origin/main, origin/HEAD)
Merge: 0e7c990 c7375fa
Author: Sarah Brown <brownsarahm@uri.edu>
Date:   Tue Sep 17 12:50:51 2024 -0400

    Merge pull request #4 from compsys-progtools/1-create-a-readme
    
    create readme closes #1

commit c7375faca0043cf3c233d705201851a10e4e53ac (origin/1-create-a-readme, 1-create-a-readme)
Author: Sarah M Brown <brownsarahm@uri.edu>
Date:   Thu Sep 12 13:42:56 2024 -0400

    create readme closes #1

commit 0e7c990886ec282ba570b3400908ff46698e7dc0
Author: Sarah Brown <brownsarahm@uri.edu>
Date:   Thu Sep 12 13:21:42 2024 -0400

    start about file closes #3

commit 03733421ad69f816094fa62e3031a7703aa308e3
Author: Sarah Brown <brownsarahm@uri.edu>
Date:   Thu Sep 12 12:57:58 2024 -0400

    Initial commit

this is a program, we can use enter/down arrow to move through it and then q to exit.

4.6. making a new branch locally#

We’ve used git checkout to switch branches before. To also create a branch at the same time, we use the -b option.

A few examples:

If we use checkout without -b and an unkown branch name,

git checkout my_branch_checkedout
error: pathspec 'my_branch_checkedout' did not match any file(s) known to git

it give us an error, this does not work

but with -b we can make the branch and switch at the same time.

git checkout -b my_branch_checkedoutb
Switched to a new branch 'my_branch_checkedoutb'

so we see it is done!

create does not exist

git branch create my_branch_create
fatal: not a valid object name: 'my_branch_create'

so it tried to treate create as a name and finds that as extra

This version gives us two new observations

git branch my_branch; git checkout my_branch
Switched to branch 'my_branch'

It switches, but does not say it’s new. That is because it made the branch first, then switched.

The ; allowed us to put 2 commands in one line.

We can view a list of branches:

git branch
  1-create-a-readme
  main
* my_branch
  my_branch_checkedoutb

or again look at the log

git log
commit 0c1271483e62e69b8b3fc329203617b7093413df (HEAD -> my_branch, origin/main, origin/HEAD, my_branch_checkedoutb, main)
Merge: 0e7c990 c7375fa
Author: Sarah Brown <brownsarahm@uri.edu>
Date:   Tue Sep 17 12:50:51 2024 -0400

    Merge pull request #4 from compsys-progtools/1-create-a-readme
    
    create readme closes #1

commit c7375faca0043cf3c233d705201851a10e4e53ac (origin/1-create-a-readme, 1-create-a-readme)
Author: Sarah M Brown <brownsarahm@uri.edu>
Date:   Thu Sep 12 13:42:56 2024 -0400

    create readme closes #1

commit 0e7c990886ec282ba570b3400908ff46698e7dc0
Author: Sarah Brown <brownsarahm@uri.edu>
Date:   Thu Sep 12 13:21:42 2024 -0400

    start about file closes #3

commit 03733421ad69f816094fa62e3031a7703aa308e3
Author: Sarah Brown <brownsarahm@uri.edu>

branches are pointers, so each one is located at a particular commit.

the -r option shows us the remote ones

git branch -r
  origin/1-create-a-readme
  origin/HEAD -> origin/main
  origin/main

First we’ll go back to main

git checkout main
Switched to branch 'main'
Your branch is up to date with 'origin/main'.

We will make a branch for our next task.

git chckeout fun_fact
git: 'chckeout' is not a git command. See 'git --help'.

The most similar command is
	checkout

I made a typo, but it offers a hint.

then it works when we fix the typo

git checkout -b fun_fact
Switched to a new branch 'fun_fact'

4.7. Creating a Merge Conflict#

nano about.md 

we used the nano text editor. nano is simpler than other text editors that tend to be more popular among experts, vim and emacs. Getting comfortable with nano will get you used to the ideas, without putting as much burden on your memory. This will set you up to learn those later, if you need a more powerful terminal text editor.

this opens the nano program on the terminal. it displays reminders of the commands at the bottom of th screen and allows you to type into the file right away.

Add any fun fact on the line below your content. Then, write out (save), it will prompt the file name. Since we opened nano with a file name (about.md) specified, you will not need to type a new name, but to confirm it, by pressing enter/return.

cat about.md 
# Sarah Brown

tenure year: 2027
- i skied competiively in hs 
git status
On branch fun_fact
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   about.md

no changes added to commit (use "git add" and/or "git commit -a")
git add about.md 

git status
On branch fun_fact
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   about.md

we are going to do it without the -m on purpose here to learn how to fix it

git commit
[fun_fact 70759fd] add fun fact
 1 file changed, 1 insertion(+)

without a commit message it puts you in vim. Read the content carefully, then press a to get into ~insert~ mode. Type your message and/or uncomment the template.

When you are done use escape to go back to command mode, the ~insert~ at the bottom of the screen will go away. Then type :wq and press enter/return.

What this is doing is adding a temporary file with the commit message that git can use to complete your commit.

git log
commit 70759fda93a0b9c714a81f9de79df7fdfec3ab88 (HEAD -> fun_fact)
Author: Sarah M Brown <brownsarahm@uri.edu>
Date:   Tue Sep 17 13:21:33 2024 -0400

    add fun fact

commit 0c1271483e62e69b8b3fc329203617b7093413df (origin/main, origin/HEAD, my_branch_checkedoutb, my_branch, main)
Merge: 0e7c990 c7375fa
Author: Sarah Brown <brownsarahm@uri.edu>
Date:   Tue Sep 17 12:50:51 2024 -0400

    Merge pull request #4 from compsys-progtools/1-create-a-readme
    
    create readme closes #1

commit c7375faca0043cf3c233d705201851a10e4e53ac (origin/1-create-a-readme, 1-create-a-readme)
Author: Sarah M Brown <brownsarahm@uri.edu>
Date:   Thu Sep 12 13:42:56 2024 -0400

    create readme closes #1

commit 0e7c990886ec282ba570b3400908ff46698e7dc0
Author: Sarah Brown <brownsarahm@uri.edu>

Now we will push to github.

git push
fatal: The current branch fun_fact has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin fun_fact

To have this happen automatically for branches without a tracking
upstream, see 'push.autoSetupRemote' in 'git help config'.

It cannot push, because it does not know where to push, like we noted above that it did not comapre to origin, that was beecause it does not have an “upstream branch” or a corresponding branch on a remote server. It does not work at first because this branch does not have a remote.

To fix it, we do as git said.

git push --set-upstream origin fun_fact
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 317 bytes | 317.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
remote: 
remote: Create a pull request for 'fun_fact' on GitHub by visiting:
remote:      https://github.com/compsys-progtools/gh-inclass-brownsarahm/pull/new/fun_fact
remote: 
To https://github.com/compsys-progtools/gh-inclass-brownsarahm.git
 * [new branch]      fun_fact -> fun_fact
branch 'fun_fact' set up to track 'origin/fun_fact'.

4.8. Merge conflicts#

We are going to intentionally make a merge conflict here.

This means we are learning two things:

  • what not to do if you can avoid it

  • how to fix it when a merge conflict occurs

Merge conflicts are not always because someone did something wrong; it can be a conflict in the simplest term because two people did two types of work that were supposed to be independent, but turned out not to be.

First, in your browser edit the about.md file to have a second fun fact.

Then edit it locally to also have 2 fun facts.

nano about.md 

cat about.md 
# Sarah Brown

tenure year: 2027
- i skied competiively in hs 
- i went to Northeastern
git pull
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 1), reused 0 (delta 0), pack-reused 0 (from 0)
Unpacking objects: 100% (3/3), 973 bytes | 324.00 KiB/s, done.
From https://github.com/compsys-progtools/gh-inclass-brownsarahm
   70759fd..462402f  fun_fact   -> origin/fun_fact
Updating 70759fd..462402f
error: Your local changes to the following files would be overwritten by merge:
	about.md
Please commit your changes or stash them before you merge.
Aborting

It does not work because we have not committed.

This is helpful beacause it prevents us from losing any work.

git status
On branch fun_fact
Your branch is behind 'origin/fun_fact' by 1 commit, and can be fast-forwarded.
  (use "git pull" to update your local branch)

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   about.md

no changes added to commit (use "git add" and/or "git commit -a")

we can add and commit at the same time using the -a option from the git commit

git commit -a -m 'local second fun fact'
[fun_fact 62dcf61] local second fun fact
 1 file changed, 1 insertion(+)

Now we try to pull again

git pull
hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint:
hint:   git config pull.rebase false  # merge
hint:   git config pull.rebase true   # rebase
hint:   git config pull.ff only       # fast-forward only
hint:
hint: You can replace "git config" with "git config --global" to set a default
hint: preference for all repositories. You can also pass --rebase, --no-rebase,
hint: or --ff-only on the command line to override the configured default per
hint: invocation.
fatal: Need to specify how to reconcile divergent branches.

Now it cannot work because the branches have diverged. This illustrates the fact that our two versions of the branch fun_fact and origin/fun_fact are two separate things.

gitGraph commit commit branch fun_fact checkout fun_fact commit branch origin/fun_fact checkout origin/fun_fact commit checkout fun_fact commit

git gave us some options, we will use rebase which will apply our local commits after the remote commits.

git pull --rebase
Auto-merging about.md
CONFLICT (content): Merge conflict in about.md
error: could not apply 62dcf61... local second fun fact
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
hint: Disable this message with "git config advice.mergeConflict false"
Could not apply 62dcf61... local second fun fact

it gets most of it, but gets stopped at a conflict.

git status
interactive rebase in progress; onto 462402f
Last command done (1 command done):
   pick 62dcf61 local second fun fact
No commands remaining.
You are currently rebasing branch 'fun_fact' on '462402f'.
  (fix conflicts and then run "git rebase --continue")
  (use "git rebase --skip" to skip this patch)
  (use "git rebase --abort" to check out the original branch)

Unmerged paths:
  (use "git restore --staged <file>..." to unstage)
  (use "git add <file>..." to mark resolution)
	both modified:   about.md

no changes added to commit (use "git add" and/or "git commit -a")

this highlights what file the conflict is in

we can inspect this file

nano about.md 
# Sarah Brown

tenure year: 2027
- i skied competiively in hs 
<<<<<<<< HEAD
- i started at uri in 2020
=======
- i went to Northeastern
>>>>>>>> "local fun fact"

We have to manually edit it to be what we want it to be. We can take one change the other or both.

In this case, we will choose both, so my file looks like this in the end.

# Sarah Brown

tenure year: 2027
- i skied competiively in hs 
- i started at uri in 2020
- i went to Northeastern
git status
interactive rebase in progress; onto 462402f
Last command done (1 command done):
   pick 62dcf61 local second fun fact
No commands remaining.
You are currently rebasing branch 'fun_fact' on '462402f'.
  (fix conflicts and then run "git rebase --continue")
  (use "git rebase --skip" to skip this patch)
  (use "git rebase --abort" to check out the original branch)

Unmerged paths:
  (use "git restore --staged <file>..." to unstage)
  (use "git add <file>..." to mark resolution)
	both modified:   about.md

no changes added to commit (use "git add" and/or "git commit -a")

Now, we do git add and commit

git commit -a -m 'keep both changes'
[detached HEAD c3e68a0] keep both changes
 1 file changed, 2 insertions(+)

and check again

git status
interactive rebase in progress; onto 462402f
Last command done (1 command done):
   pick 62dcf61 local second fun fact
No commands remaining.
You are currently editing a commit while rebasing branch 'fun_fact' on '462402f'.
  (use "git commit --amend" to amend the current commit)
  (use "git rebase --continue" once you are satisfied with your changes)

nothing to commit, working tree clean

Now, we follow the intructions again, and continue the rebase to combine our branches

git rebase --continue
Successfully rebased and updated refs/heads/fun_fact.

Once we rebase and everything is done, we can push.

git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 309 bytes | 309.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
To https://github.com/compsys-progtools/gh-inclass-brownsarahm.git
   462402f..c3e68a0  fun_fact -> fun_fact

4.9. Summary#

  • branches do not synch automatically

  • branches are pointers to commits

  • every commit knows its parents

  • if two different commits have the same parent, when we try to merge we will have divergent branches

  • divergent branches can be merged by different strategies

  • a merge conflict occurs if, when merging branches, a single file has been edited in two different ways

We often visualize git using graphs like subway maps:

gitGraph commit id:"A" commit id:"B" branch fun_fact checkout fun_fact commit id:"C" commit id:"D'" checkout fun_fact commit id:"E"

However you can also think of what we learned today like this:

flowchart LR cA[ A <br> commit] cB[ B <br> commit] cB --> |knows its parent| cA cC[ C <br> commit] --> |knows its parent| cB blocal[fun_fact <br> branch] --> |is a pointer to| cC bremote[origin/fun_fact <br> branch] --> |is a pointer to| cB

Over the next few weeks we will keep refining this understanding.

4.9.1. New bash commands#

command

explanation

cat

concatenate a file to standard out (show the file contents)

4.9.2. New git commands#

command

explanation

git log

show list of commit history

git branch

list branches in the repo

git branch new_name

create a new_name branch

git checkout -b new_Name

create a new_name branch and switch to it

git pull

apply or fetch and apply changes from a remote branch to a local branch

4.10. Prepare for Next Class#

Examine an open source software project and fill in the template below in a file called software.md in your kwl repo on a branch that is linked to this issue. You do not need to try to understand how the code works for this exercise, but instead focus on how the repo is set up, what additional information is in there beyond the code. You may pick any mature open source project, meaning a project with recent commits, active PRs and issues, multiple contributors. In class we will have a discussion and you will compare what you found with people who examined a different project. Coordinate with peers (eg using the class discussion or in lab time) to look at different projects in order to discuss together in class.

## Software Reflection

Project : <markdown link to repo>

## README

<!-- what is in the readme? how well does it help you  -->

## Contents 

<!-- denote here types of files (code, what languages, what other files) -->


## Automation

<!-- comment on what types of stuff is in the .github directory -->

## Documentation

<!-- what support for users? what for developers? code of conduct? citation? -->

## Hidden files and support
 <!-- What type of things are in the hidden files? who would need to see those files vs not? -->

Some open source projects if you do not have one in mind:

4.11. Badges#

  1. Create a merge conflict in your github in class repo and resolve it using your favorite IDE,. Describe how you created it, show the files, and describe how your IDE helps or does not help in ide_merge_conflict.md. Give advice for when you think someone should resolve a merge conflict manually vs using an IDE. (if you do not regulary use an, IDE, try VSCode)

  2. Read more details about git branches(you can also use other resources) add branches.md to your KWL repo and describe how branches work, in your own words. Include one question you have about branches or one scenario you think they could help you with.

  1. Create a merge conflict in your KWL repo on the branch for this issue and resolve it using your favorite IDE, then create one and resolve it on GitHub in browser (this requires the merge conflict to occur on a PR). Describe how you created it, show the files, and describe how your IDE helps or does not help in merge_conflict_comparison.md. Give advice for when you think someone should resolve a merge conflict in GitHub vs using an IDE. (if you do not regulary use an, IDE, try VSCode) You can put content in the file for this step for the purpose of making the merge conflicts for this exercise.

  2. Learn about GitHub forks and more about git branches(you can also use other resources)

  3. In branches-forks.md in your KWL repo, compare and contrast branches and forks; be specific about their relationship. You may use mermaid diagrams if that helps you think through or communicate the ideas. If you use other resources, include them in your file as markdown links.

4.12. Experience Report Evidence#

4.13. Questions After Today’s Class#

4.13.1. How do I know if everything I submitted was done properly, or see a grade of somesort. I know comments are left but sometimes when I check I don’t really know if I did everything right.#

If it’s approved you completed the badge, if revisions are requested, then you need to revise.

Starting next week, we will learn how to produce a progress report.

4.13.2. Why wouldnt you just use vs code or git hub directly?#

Using the terminal is generally faster once you learn it. It also allows you to write scripts.

Some things cannot be done in browser, plus when you are writing code you would be working outside of the browser.

4.13.3. How common are merging issues?#

Merge conflicts are very common. It happens whenever a branch is edited in two places.

4.13.4. How can I merge the new branch locally, not from the website?#

the git merge command

4.13.5. Is it possible to have more than one merge conflict on a line?#

on a single line it will count it as a single conflict, because it counts by lines

4.13.6. What is the order of merge and rebase?#

THey are two options for the same thing, but they put commits in a different order.