跳转至

Git for a Developer

It's a review and supplementary material for Git as a programmer.

bxhu saying

Once I thought I had mastered the practical usage of Git, until I saw this tutorial from Berkeley.

I believe going through this content will be super helpful for large project development especially in synced workflow.

  • bxhu 2024-10-01, at moffit library, UCB

Basic Skills

Here we follow the tutorial reference - UCB.

Please follow this book and jump back here after finishing it.

We will ignore most part of the book (as it's super easy) and focus on some important concepts and their usage.

restore

What if we want to restore changes from a previous version of our program? We can use git restore! There are a couple ways to do this.

If we want to restore files to the versions in the most recent commit, then we can run git restore without specifying a commit id:

Bash
1
git restore [path_to_file]

If we want to restore to a specific commit, we can identify that commit’s id and restore the files from that commit.

Bash
1
git restore --source=[commitID] [path_to_file]

Actually, it's a very flexible command and we can use git restore towards 3 types of files:

  1. Already add and commit (git add + git commit)
    • git restore <file> can restore the file to the latest commit. (back to unstage state)
    • will discard all the changes after the latest commit.
  2. Already add but not commit yet (just git add)
    • git restore --staged <file> remove the staged files from staging area but keep the changes in the working directory.
  3. Neither add nor commit (None🤡)
    • git restore <file> can also be used for this situation.
    • actually, not really necessary😄

detailed info here

reference

see here

Important: restore does not change the commit history! Or, in other words, the safe containing our panoramic photos is entirely unaffected by the restore command.

The entire point of git is to create a log of everything that has EVER happened to our files.

In other words, if you took a panoramic photo of your room in 2014 and in 2015 and put them in a safe, then decided in 2016 to put it exactly back like it was in 2014, you would not set the panoramic photo from the year 2015 on fire. Nor would you a picture of it in 2016 magically appear inside your safe.

If you wanted to record what it looked like in 2016, you’d need to take another photo (with the appropriate -m message to remember what you just did).

remote

Format

Bash
1
git remote add [remote-name] [remote-url]

example:

Bash
1
git remote add skeleton https://github.com/Berkeley-CS61B/skeleton-sp24.git
  • The remote-name is a local nickname for the remote repository.
  • The remote-url can be seen in github remote repository.

After adding a remote, all other commands use its associated short name (nickname)

Check Remote from a local view

Bash
1
git remote -v

example:

Bash
1
2
3
4
5
 git remote -v
log-ref https://github.com/dtran24/skypilot.git (fetch) # its nickname is `log-ref`
log-ref https://github.com/dtran24/skypilot.git (push)
origin  [email protected]:root-hbx/skypilot.git (fetch) # its nickname is `origin`
origin  [email protected]:root-hbx/skypilot.git (push)

High-Level Workflow

Now we jump to this book, Using Git - UCB.

As is mentioned above, we will go on focusing on important concepts and their usage instead of 1-to-1 following.

One more thing, pro git is strongly recommended for further understanding.

branch

create a branch off of your current branch

Bash
1
git branch [new-branch-name]

switch from one branch to another by changing which branch your HEAD pointer references

Bash
1
git switch [destination-branch]

combine the previous two commands which create a new branch and then switch to it with this single command

Bash
1
git switch -c [new-branch-name]

delete branches

Bash
1
git branch -d [branch-to-delete]

easily figure out which branch you are on (locally)

Bash
1
git branch -v

example

Bash
1
2
3
4
 git branch -v
* master         62222ee5 [UX] Remove requirement to specify cloud in Resources to use labels (#4022)
  sky-serve-logs b1f78dc5 add more descriptive error message if sync down for replica does not work
  sync-down-logs b1f78dc5 add more descriptive error message if sync down for replica does not work

figure out all branches you are on (local + remote)

Bash
1
git branch -a
Bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
 git branch -a
* master
  sky-serve-logs
  sync-down-logs
  remotes/log-ref/aws/vpn
  remotes/log-ref/core/relax-cluster-name-constraint
  remotes/log-ref/master
  remotes/log-ref/remove-cluster-name-validation
  remotes/log-ref/serve/manually-terminate-replica
  remotes/log-ref/serve/print-service-yaml
  remotes/log-ref/serve/status-ordering
  remotes/log-ref/sky-serve/combine-replica-logs
  remotes/log-ref/skyserve/env-var-service-field
  remotes/log-ref/skyserve/sync-down-logs
  remotes/log-ref/ux/sky-check-select
  remotes/origin/HEAD -> origin/master
  remotes/origin/master
  remotes/origin/sky-serve-logs

merge

here

This merge command will create a new commit that joins the two branches together and change each branch’s pointer to reference this new commit.

While most commits have only one parent commit, this new merge commit has two parent commits. The commit on the main branch is called its first parent and the commit on the fixing-ai-heuristics branch is called its second parent.

alt text

rebase

Rebasing changes the parent commit of a specific commit. In doing this, it changes the commits so that it is no longer the same.

Rebase can be used as an alternative to merge for integrating changes from one branch to another. It is quite different from merge in that merge creates a new commit that has both parent branch commits as parents. Rebasing takes one set of commits from a branch and places them all at the end of the other branch.

why rebase versus merge

There are different reasons why you would want to use rebase versus merge. One of these reasons is that rebase leads to a cleaner history when working with many different branches and team members.

fetch and pull

fetch: This is analogous to downloading the commits, but it does not incorporate them into your own code.

Fetching the changes will only update your local copy of the remote code but not merge the changes into your own code.

just get it, not merge

a great example here

pull: This is equivalent to a fetch + merge. Not only will pull fetch the most recent changes, it will also merge the changes into your HEAD branch.

get it and merge automatically

fetch example:

Bash
1
2
3
$ git fetch origin
$ git branch review-ai-fix origin/fixing-ai-heuristics
$ git switch review-ai-fix

pull example:

Bash
1
2
# git pull [remote-name] [remote-branch-name]
$ git pull origin main

Git WTFS

WTFS

This part is intended to help you through frequently encountered Weird Technical Failure Scenarios (WTFS) in Git

reference here

pull then push

Bash
1
2
3
4
5
6
7
8
$ git push origin main
To https://github.com/gilbertghang/recipes.git
 ! [rejected]     main -> main (non-fast-forward)
error: failed to push some refs to 'https://github.com/gilbertghang/recipes.git"
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

What has happened here is that your remote (i.e. your online Github repository) contains commits that your local repository does not have.

Luckily, Git is very good about telling you how to fix these errors: if you read the error message carefully, you’ll see that is suggests that you git pull. Do that, fix any merge conflicts, and push. Done!

fix conflicts then pull

Bash
1
2
3
4
5
6
$ git pull origin main
From github.com:Berkeley-CS61B/course-materials-sp16
 * branch            main     -> FETCH_HEAD
Auto-merging proj/proj0/solution/canonical/Planet.java
CONFLICT (content): Merge conflict in proj/proj0/solution/canonical/Planet.java
Automatic merge failed; fix conflicts and then commit the result.
Java
1
2
3
4
5
6
7
8
    public Planet(Planet p) {
<<<<<<< HEAD
        this.xPos = p.xPos;
        this.yPos = p.yPos;
=======
        this.xxPos = p.xxPos;
        this.yyPos = p.yyPos;
>>>>>>> 27ddd0c71515e5cfc7f58a43bcf0e2144c127aed
to be specific

Everything between <<<<<<< HEAD and ======= is what was on your computer, and everything between ======= and 27ddd0c71515e5cfc7f58a43bcf0e2144c127aed is what was on the remote server.

just manually adjust the contents above :)

enter a commit message to explain why this merge is necessary

Text Only
1
2
3
4
5
6
Merge branch 'main' of https://github.com/Berkeley-CS61B/skeleton-sp24
# 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.

Git has opened a terminal text editor for you to enter a commit message. You can leave the default commit message and exit the text editor.

exit for nano / vim
  • vim: :wq
  • nano: ctrl + x (simultaneously)

does not appear to be a git repository

Bash
1
2
3
4
fatal: 'skeleton' does not appear to be a git repository
fatal: Could not read from remote repository.

Please make sure you have the correct access rights and the repository exists.

Try running git remote -v. If your repo is set up correctly, you should see:

Bash
1
2
3
4
origin  [email protected]:Berkeley-CS61B/sp24-s*** (fetch)
origin  [email protected]:Berkeley-CS61B/sp24-s*** (push)
skeleton  https://github.com/Berkeley-CS61B/skeleton-sp24.git (fetch)
skeleton  https://github.com/Berkeley-CS61B/skeleton-sp24.git (push)

If you only see the two lines corresponding to origin, and not the two lines corresponding to skeleton, then Git doesn’t know where to find the skeleton repo.

To fix this, run:

Bash
1
git remote add skeleton https://github.com/Berkeley-CS61B/skeleton-sp24.git

Then, run git remote -v again and ensure that you see two lines corresponding to origin and two lines corresponding to skeleton.

Sync Workflow

  1. fork a repository
  2. sync a fork
  3. what's a 'pr'
  4. what's an 'issue'

How to deal with Tag

We wanna clone / fork a repo with specific tag (eg. unison-3.42), what should we do in CLI?

It is super easy to find that:

alt text

We can see all packets/version with tag here, but what should we do in CLI?

1) fetch and update:

Bash
1
2
3
4
5
6
7
cd ns-3-dev
# add remote repo
git remote add unison https://github.com/NASA-NJU/UNISON-for-ns-3.git
# get whole remote repo
git fetch unison
# see all usable tags
git tag -l

2) checkout to specific tag:

Bash
1
2
3
4
# use unison-3.42 pkt to create a new branch named mtp-tcp
git checkout -b mtp-tcp tags/unison-3.42
# push for init
git push origin mtp-tcp

3) resolve conflicts and merge:

Bash
1
2
3
4
5
6
7
8
# come back to this branch
git checkout mtp-tcp
# resolve and then merge
git merge BRANCH-NAME[eg: main]
# after merge, pls push
git add .
git commit -m "Resolve merge conflicts between main and unison-3.42"
git push origin mtp-tcp