Git introduction

Published

Tue, 10 of December, 2024

Modified

Tue, 10 of December, 2024

Caution

Web page construction in progress…

First: some useful terminal commands

  • [shift+Q] –> to exit from git dialogue
  • highlight + [cmd + D] –> to seleect all subsequent instances
  • highlight + [alt + drag] –> to edit at begin of each lines
  • highlight + [cmd + shift + L] –> to edit at the end of each lines
  • highlight + [ctr + shift + W] –> wrapping text with start and end tag

Git installation

2 recommmended options for Mac:

  1. Installer websites

  2. You should check out Homebrew, “the missing package manager for OS X”. Among many other things, it can install Git for you. Once you have Homebrew installed, do this in the shell:

# - Terminal

brew install git

Check version

# - Terminal

which git
git --version

Git configuration

Setting up your Git configs

— In terminal

# - Terminal

git config --global user.name "Jane Doe"
git config --global user.email "jane@example.com"
git config --global --list

— In R

The usethis package offers an alternative approach. You can set your Git user name and email from within R:

## install if needed (do this exactly once):
## install.packages("usethis")

library(usethis)
#usethis::use_git_config(user.name = "Jane Doe", user.email = "jane@example.org")

Managing/Verifying git credential stored

Where do I see it on Github? ? fa(name = "github") –> settings –> Developer settings –> Personal Access Tokens

WARNING: credentials::git_credential_ask("https://github.com") actually exposes the PAT password

credentials::credential_helper_get()
      # [1] "osxkeychain"

# to see all of them 
credentials::git_credential_ask("https://github.com")
      # $protocol
      # [1] "https"
      # $host
      # [1] "github.com"
      # $username
      # [1] "PersonalAccessToken"
      # $password
      # [1] "ghp_...52eR" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      # attr(,"class")
      # [1] "git_credential"

# --- other useful things to check 
#usethis::gh_token_help()
usethis::git_sitrep()
gh::gh_whoami()
# {
#   "name": "Luisa Mimmi",
#   "login": "Lulliter",
#   "html_url": "https://github.com/Lulliter",
#   "scopes": "gist, repo, user, workflow",
#   "token": "ghp_...52eR"
# } 

What are SSH keys?

Secure Shell Protocol (SSH) is a cryptographic network protocol that allows a single computer to connect with a server over the internet securely. SSH is best used for accessing remote servers.

Create an SSH

You only have to do it once. GitHub’s documentation around how to do this is great. Check out articles on generating a new SSH key and adding a new SSH key to your GitHub account to learn how to do this.

Check which ssh I already have

I have a github SSH

SSH is more secure protocol and requires a SSH key. The supported SSH public keys for GitHub Enterprise Server are ‘id_rsa.pub’, ‘id_ecdsa.pub’, ‘id_ed25519.pub’. You can check your SSH keys as follows:

# - Terminal
ls -al ~/.ssh
# - IN R 

# ------ where to see my SSH 
library(credentials)  
# Found git version 2.41.0
# Supported HTTPS credential helpers: cache, store
# Found OpenSSH_9.0p1, LibreSSL 3.3.6
# Default SSH key: /Users/luisamimmi/.ssh/id_ed25519  #(location of my SSH key)

# ------ KEY 
# credentials::ssh_key_info()

Git commands

See Figure 1

  • git status = View the state of working directory and staging area
  • git add = Stage changes for next commit
  • git commit = Commit the staged snapshot to the local repository
  • git push = Upload local repository content to a remote repository
    • 4 TEAM: it makes your local changes publicly available in a remote repository.
  • git clone = Copies an entire remote repository down to your local machine, setting up a cloned version and checks out the default branch (generally master)
    • this action is done only once.
  • git fetch = Download content from remote repository, but doesn’t force the merge
    • 4 TEAM: if a developer has pushed changes to a remote branch, those changes will be pulled down to your repository whenever fetch is performed.
      • Note: fetch won’t automatically merge any changes, only update references!
  • git merge = Join two branches together
  • git pull = Combo of git fetch and git merge
Figure 1: Git Workflow

Source: cloudstudio.com.au

Git repo setup (1st Local >> 2nd Github)

  1. Create a local git repository
# - Terminal

cd local_proj_dir
git init
git add *
git commit -am ‘Initial commit’
  1. Create a new blank repository on GitHub
  • There is option ‘add a README file’ and ‘gitignore’ in the initial setup. Keep them unclicked.🚫 🚫 ️

  • Copy repository hhtps or ssh URL
  1. Push local git repository to GitHub as instructed by Github
# - Terminal

# Change the branch to 'main'
# git branch -M main
# Connect your local repository to GitHub repository
git remote add origin hhtps://github.com/username/repo.git
# Push the local repository to GitHub
git push -u origin master

Git repo setup (1st Github >> 2nd Local)

Recommended!!! (because this method sets up the local Git repository for immediate pulling and pushing. Under the hood, we are doing git clone.)

1) On Github I create a NEW repo

[…]

2.a) In Terminal clone remote repo locally

i) position myself in the Folder ABOVE the desired git repo

# - Terminal

#  My `ParentFolder` for github repos...
cd cd ~/Github/  

ii) clone remote repo locally locally

You can only push to two types of URL addresses:

  • An HTTPS URL like https://github.com/user/repo.git
  • An SSH URL, like git@github.com:user/repo.git

Git associates a remote URL with a name, and your default remote is usually called origin

# - Terminal

# if https (Clone using the web URL.)
git clone https://github.com/Lulliter/nerd_help.git
# if SSH (Use a password-protected SSH key.)
git clone git@github.com:Lulliter/nerd_help.git

2.b) With {usethis} clone remote repo locally

In the R console (in any R session)

  • OKKIO: only need the parent folder name (~/Github/) because the actual folder name will be the repo name !
library(usethis)
usethis::create_from_github(
    # https or SSH both ok 
    repo_spec = "git@github.com:Lulliter/ideeperpavia.git",
    # destdir specifies the parent directory where the new folder (and local Git repo) will live. 
    destdir = "~/Github/"
)

This Creates a new local directory in destdir, which is all of these things:

  • a directory or folder on your computer
  • a Git repository, linked to a remote GitHub repository
  • an RStudio Project

Opens a new RStudio instance in the new Project

3) - OPTIONAL - I copy there some stuff I already had in a different folder

# - Terminal

# copy other LOCAL --> git LOCAL
cp -r ~/OtherLocalDrive/nerd_help/   ~/Github/_nerd_help 

4) I make changes in the local repo

For example, I actually wanted a quarto website, so I open TERMINAL and do

# - Terminal

quarto create project website mysite

5) Check what happened…

# - Terminal

cd ~/Github/_nerd_help 
git remote show origin 
git status

6) Add local changes to staging area

# - Terminal

git add -A # everything
git add -u # only already tracked stuff 

7) Commit desired changes

# - Terminal

# Create Std commit "message"....
msg="rebuilt on `date`"
if [ $# -eq 1 ]
  then msg="$1"
fi
# ... Commit Those changes.
git commit -m "$msg"

# or  
git commit -m "whatever message"

8) Push source and build repos.

# - Terminal

git push origin master

Git architecture

  • origin = stands for the remote repository. When we use git push -u origin local_branch, it tells the system that we want to push our local branch to the remote repository.
  • Usually there is one default remote repository and origin represents this default repository.
    • …or you can rename it
# - Terminal

#  see your remote branches listed:
git remote -v

#  rename origin it by using 
git remote rename origin new_name
  # looks like I have 2 remote branches: origin (default) and upstream
  • branch branch is a like a fork in the history of a repository. One branch represents an independent line of development, like a fork teeth.
# - Terminal

#  to check which branches I have  
git branch -a
    # * master
    #   page_col
    #   test_branch2
    #   up
    #   wkg_branch
    #   remotes/origin/HEAD -> origin/master
    #   remotes/origin/master
    #   remotes/origin/page_col
    #   remotes/origin/wkg_branch
    #   remotes/upstream/master
    #   remotes/upstream/page_col
    #   remotes/upstream/wkg_branch
  • master (or main) is a branch, the default branch, the main branch, and it’s always there.

  • HEAD = the currently active branch (the checked out one). Each repository only has one current branch, hence one HEAD as well.

    • Detached HEAD happens when a checkout command is applied to a specific historical commit, tag or remote branch.
# - Terminal

#  to check where the HEAD of a repository is pointing to
cat .git/HEAD
    # ref: refs/heads/master
  • index index is the proposed next commit, also called staging area.

Ask about latest commit

WHere:

  • --format=%cd %cd stands for “commit date.”
  • --pretty=%B Customizes the output to show the full commit message body
  • --format=%cd and the commit message subject %s of the most recent commit.
  • --pretty is a shorthand for common formatting options
# - Terminal

# 1) To find out the date and time of your last Git commit 
git log -1 --format=%cd # %cd stands for "commit date."
# 2) To find out the message of your last Git commit 
git log -1 --pretty=%B # --pretty=%B: Customizes the output to show the full commit message body

#1+2) You can get both the commit date and message in one line using the following command:
git log -1 --format="%cd %s"
# or 
git log -1 --pretty="%cd %s"

See differences b/w commits

# - Terminal

# diff between 2 latest commits (1 on branch) only in files I care 
git diff dc87ae c86edffc16 "*.qmd"

#(To view diff between next commit (HEAD) and parent commit (SHA 682bc))
git diff dc87ae..  
git diff dc87ae^..HEAD  '***.qmd' #ORQ
git diff dc87ae..HEAD   #OR

# b/w old commit on branch and HEAD 
git diff 693e61^..HEAD

Problems

When you accidentally let git track files

CASE 1) File that is Untracked but it appears in git status

🤟🏻 do this + add file to .gitignore file

💣💥 don’t do this …..

# - Terminal

# Preview the files but `-n` means it is a dry run
git clean -n 
# Remove the file (-f flag stands for "force")
git clean -f 

CASE 2) File that is Tracked by git

This command removes files from the staging area (so they won’t be in the next commit), but keeps them in the working directory!!! Useful for configuration files, build artifacts, etc.

# - Terminal

# Remove the file from the staging area

# add .env file to .gitignore
echo "accident.txt" >> .gitignore
# tell Git NOT to track this file (it gets removed from the index, but stays local system)
git rm --cached accident.txt

# or whole directory (-r recursive) 
git rm --cached -r directory/

Your branch is ahead of ‘origin/master’ by “x” commits

E.g. I had this occurring because I wanted to push a heavy PDF download button and git push couldn’t go through.

  1. make a BACKUP of local!

  2. Go back before the commit

    1. Brutal: reset your local master to the state on your remote origin (a.k.a. last pushed updates)
# - Terminal

git reset --hard origin/master
    1. Conservative option: reset to before last commit saving local changes
    • --soft = you will remove the last commit from the current branch, but the file changes will stay in your working tree & the changes will stay on your index (so it is enough to commit them)
    • --mixed = you will still keep the changes in your working tree but not on the index (you have to add and commit again)
    • --hard = you will lose all uncommited changes and all untracked files in addition to the changes introduced in the last commit
# - Terminal

git reset --soft HEAD~1   
    1. Another useful option: similar to soft
    • --keep It only resets the files which are different between the current HEAD and the given commit. It aborts the reset if one or more of these files has uncommited changes. It basically acts as a safer version of hard.
# - Terminal

# Assuming HEAD points at 7e05a95 
  # 7e05a95  (HEAD -> main) Update a
  # e62add5  Update b
  # ca9ae0a  Update a
git reset --mixed HEAD^  

Dealing with existing branches

To show details about a particular remote (e.g. origin, which is the default name when you clone a project). This command is for:

  • Inspecting Remote Details
  • Checking Remote Branches
  • Verifying Tracking Branches
  • Identifying Push and Fetch Status (ensure your local repository is up-to-date or ready for pushing changes)
# - Terminal
git remote show origin

# * remote origin
  # Fetch URL: git@github.com:Lulliter/nerd_help.git
  # Push  URL: git@github.com:Lulliter/nerd_help.git
  # HEAD branch: master
  # Remote branches:
    # master     tracked
    # page_col   tracked
    # wkg_branch tracked
  # Local branches configured for 'git pull':
    # master   merges with remote master
    # page_col merges with remote page_col
  # Local refs configured for 'git push':
    # master     pushes to master     (up to date)
    # page_col   pushes to page_col   (up to date)
    # wkg_branch pushes to wkg_branch (fast-forwardable)
  • Remote branches: tracked Indicates that these branches are being tracked locally (there are corresponding local branches).
  • Local branches configured for 'git pull': Shows how local branches are configured for pulling changes from the remote
  • Local refs configured for 'git push': Shows how local branches are configured for pushing changes to the remote
    • wkg_branch pushes to wkg_branch (fast-forwardable) meaning there are changes in the remote branch that haven’t been pulled locally
git branch   # to list local branches.
git branch -r # to list remote branches.
git branch -a # to list all branches (local + remote).

Which branches have been merged?

# To see which branches have been merged into your current branch
git branch --merged
# To check if a branch has been merged into the remote default branch (e.g., origin/master): 
git branch -r --merged origin/master 

# To check a specific branch was merged 
git log master --oneline --decorate --graph --all | grep new_sh

Visual confirmation of branches

This shows a visual representation of branch merges.

git log --graph --oneline --all
# for a specific branches
git merge-base --is-ancestor new_sh master 
  # success == no output, exit code 0
git merge-base --is-ancestor wkg_branch master   
  # failure
git merge-base --is-ancestor page_col master   
  # success == no output, exit code 0

Delete local and remote branch (e.g. new_sh)

(now not visible anumore)

# check merged 
git merge-base --is-ancestor new_sh master 
# delete local 
git branch -D new_sh
# delete remote 
git push origin --delete new_sh
# re-check 
git branch -a

## WTF remotes/upstream/new_sh ?
git remote -v
# remote also from remote upstream 
git push upstream --delete new_sh # --->>>> NOPE (but it was stale in local ref!
git remote prune upstream           # --->>>> YEP !!

# verify deletion 
git branch -r

Reference