Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

How do git branches work?

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

Git cheatsheets

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

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.

We reviewed paths and how cd works to start. The key points of the review is that

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)

cd Documents/inclass/systems/gh-inclass-fa25-brownsarahm/

Let’s check where we left off

git status
On branch 1-add-a-readme
Your branch is ahead of 'origin/1-add-a-readme' by 1 commit.
  (use "git push" to publish your local commits)

nothing to commit, working tree clean

We had made a commit, but not yet sent it to GitHub. This commit was only on our local systems, but not on GitHub.

To send it there we use git push

git push
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 16 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 311 bytes | 311.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
To https://github.com/compsys-progtools/gh-inclass-fa25-brownsarahm.git
   c8f4926..99f86bf  1-add-a-readme -> 1-add-a-readme

Now we check status again

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

nothing to commit, working tree clean

and it says it is all up to date

Fixing the fork

Next, we will look at the repo in the browser and work with it from there. We can navigate normally or using gh to open in the browser.

gh repo view
X No default remote repository has been set. To learn more about the default repository, run: gh repo set-default --help

please run `gh repo set-default` to select a default remote repository.

Since GitHub classroom works by making a fork, gh does not know if we want to go to our individual repos or the base they were all forked from.

To review how to use the command, we will use its --help

gh repo set-default --help
This command sets the default remote repository to use when querying the
GitHub API for the locally cloned repository.

gh uses the default repository for things like:

 - viewing and creating pull requests
 - viewing and creating issues
 - viewing and creating releases
 - working with GitHub Actions

### NOTE: gh does not use the default repository for managing repository and environment secrets.

USAGE
  gh repo set-default [<repository>] [flags]

FLAGS
  -u, --unset   Unset the current default repository
  -v, --view    View the current default repository

INHERITED FLAGS
  --help   Show help for command

EXAMPLES
  # Interactively select a default repository
   gh repo set-default

  # Set a repository explicitly
   gh repo set-default owner/repo

  # View the current default repository
   gh repo set-default --view

  # Show more repository options in the interactive picker
   git remote add newrepo https://github.com/owner/repo
   gh repo set-default

LEARN MORE
  Use 'gh <command> <subcommand> --help' for more information about a command.
  Read the manual at https://cli.github.com/manual
  Learn about exit codes using 'gh help exit-codes'
  Learn about accessibility experiences using 'gh help accessibility'

This tells us to use the command with the owner/repo form of the repo name for the one we want to use. For me this means:

gh repo set-default compsys-progtools/gh-inclass-fa25-brownsarahm

Your part after the / would be your own repo name, instead of mine.

✓ Set compsys-progtools/gh-inclass-fa25-brownsarahm as the default repository for the current directory

Now we can use the original command

gh repo view
compsys-progtools/gh-inclass-fa25-brownsarahm
compsys-progtools-fall25-gh-inclass-template-gh-inclass created by GitHub Classroom

This repository does not have a README

View this repository on GitHub: https://github.com/compsys-progtools/gh-inclass-fa25-brownsarahm

or with its --web option we can get it to open in the system default browser.

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

Branches do not sync automatically

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

We made a PR for the about branch and merged it in browser.

Then in the browser the about.md file exists on the main branch.

Back on our local computer, we will go back to the main branch, using git checkout

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

now we look at the status of our repo:

ls

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.

Let’s check in with git again

git status
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean

It thinks it is up to date, but it is not because git does not sync automatically.

This manual control means that someone can break something in one place and you can fix it from another copy, it is an advantage but we have to do a bit of work.

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), 913 bytes | 456.00 KiB/s, done.
From https://github.com/compsys-progtools/gh-inclass-fa25-brownsarahm
   c8f4926..11017a5  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 c8f4926..11017a55”).

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.

We can see that with status

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

nothing to commit, working tree clean

It tells us the the branch can be fast forwarded, this is one of the ways that branches can be updated from another branch.

Fast Forward

Before

After:

Fast forward can only happen where there are stictly more commits on the incoming branch. (here the remote branch that we have fetched)

Git Rebase

Rebase changes the base commit of a branch. It works by changing the parent of the first commit that is unique to the current branch and then making new versions of the previous commits on the branch.

Before
After

Git Merge

is one the third option for how to handle it, if we choose --no-rebase it will use merge. Merge instead adds as new commit that contains all of the changes to the new base branch

We can use the fast forward option, so we will with pull

git pull
Updating c8f4926..11017a5
Fast-forward
 README.md | 3 +++
 1 file changed, 3 insertions(+)
 create mode 100644 README.md

This tells us:

Now we can check our local folder

ls
README.md

the file is there!

With no options or inputs, git branch will list the branches that exist.

git branch
  1-add-a-readme
  main
* my_branch
  mybranchcheckedoutb

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.

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

we can view the commit history with git log

git log

branches are like pointers, they point to a commit.

commit 11017a59088d4a0b880f770f15fab8c9e086a789 (HEAD -> fun_fact, origin/main, origin/HEAD, mybranchcheckedoutb, my_branch, main)
Merge: c8f4926 99f86bf
Author: Sarah Brown <brownsarahm@uri.edu>
Date:   Tue Sep 16 19:51:36 2025 +0300

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

commit 99f86bf7112debc934e7fa4504232a48266d90e4 (origin/1-add-a-readme, 1-add-a-readme)
Author: Sarah M Brown <brownsarahm@uri.edu>
Date:   Thu Sep 11 13:41:24 2025 -0400

    create a readme closes #1

commit c8f4926313ba8f6c5bfad3857b7479a666328e6d
Author: github-classroom[bot] <66690702+github-classroom[bot]@users.noreply.github.com>
Date:   Thu Sep 11 14:49:01 2025 +0000

we can use 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.

nano about.md

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.

++{“lesson_part”: “main”}

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
# About me

my major was EE
git status
On branch fun_fact
Untracked files:
  (use "git add <file>..." to include in what will be committed)
	about.md

nothing added to commit but untracked files present (use "git add" to track)

This is very similar to when we checked after creating the file before, but, notice a few things are different.

We will add it to stage

git add about.md

then check the status again

git status

we see that it is staged and git tells us how to undo this if we want

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

and commit:

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

git commit

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

then it will tell us we made a commit

[fun_fact 216b5d4] start about file
 1 file changed, 4 insertions(+)
 create mode 100644 about.md

Now we can look again at where our branch pointers are.

git log

Now only the HEAD pointer and fun_fact branch moved foward

commit 216b5d4d8a7630626ce0e7997aa89678d340d680 (HEAD -> fun_fact)
Author: Sarah M Brown <brownsarahm@uri.edu>
Date:   Tue Sep 16 13:13:38 2025 -0400

    start about file

commit 11017a59088d4a0b880f770f15fab8c9e086a789 (origin/main, origin/HEAD, mybranchcheckedoutb, my_branch, main)
Merge: c8f4926 99f86bf
Author: Sarah Brown <brownsarahm@uri.edu>
Date:   Tue Sep 16 19:51:36 2025 +0300

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

commit 99f86bf7112debc934e7fa4504232a48266d90e4 (origin/1-add-a-readme, 1-add-a-readme)
Author: Sarah M Brown <brownsarahm@uri.edu>
Date:   Thu Sep 11 13:41:24 2025 -0400

    create a readme closes #1

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.

git stores its list of remotes in a .git/config file

cat .git/config 
[core]
	repositoryformatversion = 0
	filemode = true
	bare = false
	logallrefupdates = true
	ignorecase = true
	precomposeunicode = true
[remote "origin"]
	url = https://github.com/compsys-progtools/gh-inclass-fa25-brownsarahm.git
	fetch = +refs/heads/*:refs/remotes/origin/*
	gh-resolved = base
[branch "main"]
	remote = origin
	merge = refs/heads/main
[branch "1-add-a-readme"]
	remote = origin
	merge = refs/heads/1-add-a-readme

we can see our other branches have remote = origin but our new branch is not there.

To fix it, we do as git said.

git push --set-upstream origin fun_fact
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 16 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 340 bytes | 340.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
remote: 
remote: Create a pull request for 'fun_fact' on GitHub by visiting:
remote:      https://github.com/compsys-progtools/gh-inclass-fa25-brownsarahm/pull/new/fun_fact
remote: 
To https://github.com/compsys-progtools/gh-inclass-fa25-brownsarahm.git
 * [new branch]      fun_fact -> fun_fact
branch 'fun_fact' set up to track 'origin/fun_fact'.

This time the returned message from the remote includes the link to the page to make a PR. We are not goign to make the PR though

and we can see that now our config has changed:

cat .git/config
[core]
	repositoryformatversion = 0
	filemode = true
	bare = false
	logallrefupdates = true
	ignorecase = true
	precomposeunicode = true
[remote "origin"]
	url = https://github.com/compsys-progtools/gh-inclass-fa25-brownsarahm.git
	fetch = +refs/heads/*:refs/remotes/origin/*
	gh-resolved = base
[branch "main"]
	remote = origin
	merge = refs/heads/main
[branch "1-add-a-readme"]
	remote = origin
	merge = refs/heads/1-add-a-readme
[branch "fun_fact"]
	remote = origin
	merge = refs/heads/fun_fact

Merge conflicts

We are going to intentionally make a merge conflict here.

This means we are learning two things:

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.

Make conflicting edits

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

Then edit it locally to also have 2 fun facts.

nano about.md

Now, we can visually compare, the local content:

cat about.md
# About me

my major was EE
i started at URI in 2020

And on GitHub:

about.md
# About me

my major was EE
i skied competively in HS

Git won’t let us lose work

now that we have edited in both places let’s pull.

git pull
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (1/1), done.
remote: Total 3 (delta 1), reused 1 (delta 1), pack-reused 2 (from 1)
Unpacking objects: 100% (3/3), 964 bytes | 321.00 KiB/s, done.
From https://github.com/compsys-progtools/gh-inclass-fa25-brownsarahm
   216b5d4..4f8c753  fun_fact   -> origin/fun_fact
Updating 216b5d4..4f8c753
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 'another fun fact'

Pull to combine

[fun_fact 37d36fa] another fun fact
 1 file changed, 1 insertion(+), 1 deletion(-)

so we try 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.

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.

Solve divergent branches

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 37d36fa... another 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 set advice.mergeConflict false"
Could not apply 37d36fa... another fun fact

Now it tells us there is a conflict.

We have to fix the conflict manually because there were 2 different edits to the same line of the same file, git cannot tell which one we want.

We do that using a text editor:

nano about.md

When we first open it has some added lines (as highlighted below):

about.md
1
2
3
4
5
6
7
8
# About me

my major was EE
<<<<<<< HEAD 
i skied competively in HS
=======
i started at URI in 2020
>>>>>>>

to fix, in this case, we want all of the lines so we edit that way. Otherwise you could manually edit to choose one or the other.

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, I want both so my file looks like this when I am done, then I close and save.

# About me

my major was EE
i skied competively in HS
i started at URI in 2020

now we check with git again

git status
interactive rebase in progress; onto 4f8c753
Last command done (1 command done):
   pick 37d36fa another fun fact
No commands remaining.
You are currently rebasing branch 'fun_fact' on '4f8c753'.
  (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 add and commit, with a message doing both options at once.

git commit -a -m 'resolve conflict'
[detached HEAD 634c217] resolve conflict
 1 file changed, 1 insertion(+)

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.

One more check in with git

git status
On branch fun_fact
Your branch is ahead of 'origin/fun_fact' by 1 commit.
  (use "git push" to publish your local commits)

nothing to commit, working tree clean

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 16 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 330 bytes | 330.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.
To https://github.com/compsys-progtools/gh-inclass-fa25-brownsarahm.git
   4f8c753..634c217  fun_fact -> fun_fact

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 the prepare 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 active mature open source project, meaning a project with recent commits, over 50 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 any you are familiar with:

Badges

Review
Practice
  1. Create a merge conflict in your KWL repo on the branch for this badge 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) You can put content in the file for this step for the purpose of making the merge conflicts for this exercise.

  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.

Experience Report Evidence

use the following to add the log of your gh-inclass repo to your experience badge (you need to pull and work on it locally after you run the action to make it up)

git log >> ../<yourkwlrepo>/experiences/2025-09-16.md

Questions After Today’s Class

Will we be using these merge resolution strategies in the future?

Almost every student who takes this class ends up needing to resolve a merge conflict organically, yes.

Also, the --rebase option will be used a lot.

How can you commit multiple things and push them to the web but not the whole repostiory?

You always push the whole repository, but git does it smart, it compressess and only sends the new things to avoid slow uploads

Is it possible to undo a created branch or pull request.

You can delete a branch, both in GitHub.com and locally, PRs can only be closed.

is there a way to delete a repo or file through bash

Yes! rm can delete a file. To delete a folder, you need to use extra flags r for recursive and sometimes if you are really sure, f for force.

where do I go if I think I need more help

Read the notes as a starting point and the links, and if those are not enough, office hours

How are merge conflicts handled when they are entirely in GitHub?

This is today’s practice badge for you to try that interface out. The basic answer is that for simple merge conflicts it’s basically the same as what we did today. For complex merge conflicts (typically relating to deleted files) you have to work offline and cannot do it in browser.

Footnotes
  1. See, for example ChatGPT is Bullshit in Ethics and Information Technology. If you find this interesting you could do a discussion community badge

References
  1. Hicks, M. T., Humphries, J., & Slater, J. (2024). Correction: ChatGPT is bullshit. Ethics and Information Technology, 26(3). 10.1007/s10676-024-09785-3