Basics



git is client source-control software that runs locally on your machine, and also a protocol and server for source-control.

GitHub is a git-compatible or git-based cloud service that does source-control, plus issue-tracking, collaboration, project management, public access etc. Other git-compatible services include GitLab, SourceForge, Bitbucket, Codeberg, more. article1, article2



Git is decentralized; many people can have modified copies of the same file at the same time, and the changes will be merged later. A centralized system would have each file checked-out to only one person at a time.

Git tracks and manages changes, not files. So for example you could have 5 changes in a single file in your working directory, and choose to commit only 3 of them into a particular branch, commit the other 2 later into a different branch.



WARNING: Unless/until you are VERY fluent with git, make a good backup before doing any major operation. A couple of times, some operation has gone the opposite direction from what I expected, or deleted the entire history of my repo. Backups have saved me.

xkcd 1597 git

Apparently GitHub has changed the meaning of "fork". Usually a "fork" is a major copy from an existing project, to make a new permanent competing project. On GitHub, a "fork" can be a clone of the code so you can make changes that someone then will merge back into the project.

Two project models

  • Shared repository: Lots of well-known contributors with read, write, or administrator access. Many devs can do merges into main branch. Typical for a corporate project.

  • Fork and pull: Some central contributors/leaders with read, write, or administrator access. Only they can do merges into main branch. Any random person can fork the whole project, create a branch with changes, then commit that branch and create a pull request asking for it to be merged into main branch. Typical for an open-source project.




Note: The name "master" is deprecated; now other names such as "main" or "primary" are being used. I'll use "main". GitHub is retaining "master" for old repos, using "main" for new ones.



Resources

+/-
git:
Aaron Kili's "How to Use Git Version Control System in Linux"
Dolamu Asipa's "A Git Workflow Guide for Code Newbies"
Git Immersion
Rapid7's "Git cheatsheet"
giteveryday(7) Manual Page
Scott Chacon and Ben Straub's "Pro Git" book
gittutorial(7) Manual Page
Matt Neuburg's "Picturing Git: Conceptions and Misconceptions"
Git - Documentation
Oh Shit, Git!?!
Marcin Wosinek's "Why Is Git So Complicated"
Mark Dominus's "Things I wish everyone knew about Git (Part I)"
Dwayne McDaniel's "Git concepts in less than 10 minutes"

git and GitHub:
GitHub Guides' "Hello World"
GitHub Docs' "Using Git"
Meghan Nelson's "An Intro to Git and GitHub for Beginners (Tutorial)"
Adam Dachis' "How the Heck Do I Use GitHub?"
Lauren Orsini's "GitHub For Beginners: Don't Get Scared, Get Started"
Aayushi Johari's "How To Use GitHub - Developers Collaboration Using GitHub"
Bobby Iliev's "Introduction to Git and GitHub"
Matthew Setter's "A Beginner's Git and GitHub Tutorial"
GitHub's "Set up Git"
GitHub Help's "Fork a repo"

Santosh Yadav's "How GitHub is Improving Developer Experience"
Hillel Wayne's "GitHub has too many hidden features"
Roadrunner Twice's "Why Git is hard"
tef's "things i just don't like about git"

Galtzo's "I'm leaving GitHub"

GUIs:
James Quick's "How to use Git Integration in Visual Studio Code"
Microsoft's "Visual Studio and GitHub better together"
codeSTACKr's "Learn Git in 30 Minutes" (video) (git and VS Code)
Aaron Kili's "11 Best Graphical Git Clients and Git Repository Viewers for Linux"

reddit's /r/git
reddit's /r/github
Chris Coyier's "The GitHub Profile Trick"

Patricia Johnson's "Top 5 Git Security Mistakes"
William Le's "Taking a Look at the GitHub CLI Tool" (GitHub-specific CLI to manage issues/PRs/repos on GitHub)

Drew DeVault's "Tips for a disciplined git workflow"
Mikkel Paulson's "Effective Git as a solo developer"
Hynek Schlawack's "Don't Start Pull Requests from Your Main Branch"

Rajeev Bera's "Don't ignore .gitignore"

Swimm's "How to Avoid Git Disasters - Part 1: Git Reset"
SoByte's "Git Undo"
mohsen's "How to fix the most common mistakes in Git"

Vladimir Kaplarevic's "How to Install and Use Git on Windows"

Humor: "Handmade Hero Day 523 - Introduction to Git" (video)





Workflows



Single dev working directly on main branch in remote repository

Working
Directory
Staging Local
Repository
(.git dir)
Remote
Repository
< ---------------------- clone ---------------------- <
[edit files]      
> --- add --- >    
   > -- commit -- >
      > --- push origin main --- >


Each commit should be an atomic change, not several unrelated changes bundled together.

Commit is a local operation; push publishes to a remote repo. You could do several edit-add-commit cycles followed by one push.


Multiple devs working directly on main branch in remote repository

Working
Directory
Staging Local
Repository
(.git dir)
Remote
Repository
< ---------------------- clone ---------------------- <
[edit files]      
> --- add --- >    
   > -- commit -- >
      < --- pull --- <
      [check for conflicts]  
      > --- push origin main --- >


Multiple devs working on separate branches

Working
Directory
Staging Local
Repository
(.git dir)
Remote
Repository
< ---------------------- clone ---------------------- <
      branch X
(create branch X)
 
      checkout X
(or)
  switch X
(start using X)
 
[edit files]      
> --- add --- >    
   > -- commit -- >
      > --- push origin X --- >
      [now others can get X
to review the code,
or run tests]


Dev who made branch merges branch into main

Working
Directory
Staging Local
Repository
(.git dir)
Remote
Repository
      checkout main
(or)
  switch main
(start using main)
 
      < ------ pull (main) ------ <
      merge X
(may have to deal
with any conflicts
and try again)
 
      > --- push origin main --- >
      [now others can get
the merged code]
      branch -d X
(delete X locally)
 
      > --- push origin --delete X --- >
(delete X in remote repo)


A "pull request" is not a git thing, it's a GitHub (or other system) thing. It asks someone to merge branch X into the main branch, in the remote repository.
GitHub Docs' "About pull requests"

Branch name "master/main" is just a default used by "git init"; you could use a different name.

Repo name "origin" is just a default used by "git clone"; you could use a different name.



SoByte's "Three git flows and the version release model"





Getting Started



Basics to get started

+/-

sudo apt install git
git config --global user.name "Your Name Here"
git config --global user.email "your_email@youremail.com"
git config --list

git-credential-manager-core configure   # ???

Clone existing repo to disk

+/-

# In browser, log in to GitHub, go to a project you want to copy.
# copy the URL ending in ".git"

git clone URL

Create new project from scratch

+/-
  1. On GitHub web page, create new repository P in my account.
  2. Set description.
  3. Turned off Wiki and Projects. Turned on "Restrict editing to collaborators only", but I think it only applies to the Wiki ?

mkdir P
cd P
git init
# edit README.md file
git add README.md
git commit -m "first commit"
git remote add origin https://github.com/BillDietrich/P.git
git push -u origin main
# Had to turn off 2FA for login to work.
# 2022 GitHub: had to create a "personal access token" to use as password.

Enable SSH access to GitHub/GitLab/etc

+/-
  1. "ssh-keygen -t ed25519 -C 'for GitHub'"
  2. Set no passphrase.
  3. Save to file named "/home/USER/.ssh/id_ed25519GitHub".
  4. "ssh-add $HOME/.ssh/id_ed25519GitHub"
  5. "cat /home/USER/.ssh/id_ed25519GitHub.pub"
  6. Copy public key (except trailing "for GitHub") from screen into clipboard.

  7. On GitHub/GitLab/etc web page, go to settings or profile, and create new SSH key.
  8. Paste public key from clipboard.

  9. "cd PROJECT"
  10. "git remote rm origin"
  11. Get SSH link from web page of repo in browser.
  12. "git remote add origin 'git@github.com:YOURNAME/PROJECT.git'"

Making changes in my personal project

+/-

# Edit source files.

git add filename (for each file edited)
git commit -m "message"
git push -u origin main
# 2022 GitHub: had to use a "personal access token" as password.

When you operate this way, there is only one branch ("main").

To see status at any time, do "git status".

If you stage (git add) a file, then decide that was a mistake, do "git rm --cached filename".

If you do a commit, then decide you forgot some changes or the message was wrong, stage more changes and then do "git commit --amend". This doesn't remove the commit, it modifies it, using the (new) contents of the staging area and the new message. Only do this before you do any push to a remote repo.

To delete a file completely, do "git rm filename", then commit and push.

If you edit a file locally and then want to discard the edits and get the last-committed version of the file again, do "git checkout -- filename".



Note: "git add" adds a complete snapshot of a file to the staging area, not just the filename. So if you edit a file, "git add" it, then edit the file some more, you have to "git add" it again to stage the second set of edits.



In a bigger, multi-person project

+/-
From a project-owner on GitHub:
"Forking" is just Github's name for making your own clone of someone else's repo on Github. It is a weird name and completely different from forking an open source project (into a new project).

[After pushing changes to a branch on your repo on GitHub] it doesn't matter, you can open a pull request between the original repo's main and your issue branch in your Github repo, or between original repo's main and your repo's main branch.

If you fork an original repo on GitHub to make your own repo on GitHub, then clone your repo on GitHub to your local disk, you now have three repo's. Your files on disk are a repo.

There are two cases for project management:
  • Shared repository, you have write access to the original project repo:
    +/-
    [This mixes GUI and CLI operations, probably not best style:]

    1. Clone the original main branch files on GitHub to disk: login to GitHub web site, go to repo, click big green "Clone or download" button near upper-right. Easiest to click on "Download ZIP".
    2. Build the project on disk, test.
    3. Create a branch (on project's main page in GitHub, click "Branch: Main" pull-down, and type new branch's name; or "git branch issue857").
    4. Have to "checkout" to the branch on disk. Do "git status" to see that you're on branch, not main.
    5. Edit files on disk, test, repeat.
    6. Commit changed files to the branch as you go along, and push them to the GitHub repo, or after it's all working ("git add FILENAMES" and "git commit -a -m 'whatever'" and "git push -u origin issue857").
    7. Get whole thing into a finished state.
    8. When all changes are done and committed and pushed to the branch on GitHub, open a pull request for the branch.
    9. Get approval of the pull request (the changes).
    10. On disk, go back to main branch.
    11. Merge branch into main branch.


  • Fork and pull, you don't have write access to the original project repo:
    +/-
    [This mixes GUI and CLI operations, probably not best style:]

    1. Fork the whole original repo on GitHub to make your own repo on GitHub: login to GitHub web site, go to repo, click "fork" button near upper-right.
    2. From your repo on GitHub, clone the (main branch) files to disk: login to GitHub web site, go to repo, click big green "Clone or download" button near upper-right. Easiest to click on "Download ZIP".
    3. Build the project on disk, test.
    4. Create a branch (on project's main page in GitHub, click "Branch: Main" pull-down, and type new branch's name; or "git branch issue857").
    5. Have to "checkout" to the branch on disk. Do "git status" to see that you're on branch, not main.
    6. Edit files on disk, test, repeat.
    7. Commit changed files to the branch as you go along, and push them to the GitHub repo, or after it's all working ("git add FILENAMES" and "git commit -a -m 'whatever'" and "git push -u origin issue857").
    8. Get whole thing into a finished state.
    9. When all changes are done and committed to the branch, open a pull request for the branch but to the original GitHub repo.
    10. Owner will approve and merge the pull request (the changes).





"git fetch" fetches all the changes on the server that you don't have yet, and doesn't modify your working directory. Maybe first "git fetch --dry-run" to see if any changes are available for fetching.

"git pull" is essentially a git fetch immediately followed by a git merge.





Miscellaneous



Picking a package to use from GitHub

+/-
  • What language(s) does it use ?
  • Look at how recently parts were updated. If it hasn't been updated in several years, maybe find something fresher.
  • Look at open issues.
  • Look at forks. Maybe one of them is newer/better.



2FA in GitHub

+/-
When I turned on 2FA (TOTP) on my GitHub account, I could no longer log in through the CLI.

Found out later: log in to GitHub web page, go to Settings / Security and enable 2FA. Back to Settings, go to Developer settings, then Personal access tokens. Click on Generate new token button. Check only the "repo" item, to do just that stuff through the CLI; do all other stuff through the web UI. Click Generate new token button. Copy the token value and save it.

Then when you do operations through the CLI, use the value of your personal access token instead of your account password.

Also, if you have a "secret service" storing your GitHub password (on a keyring or in a password manager), you could edit ~/.gitconfig to contain "[credential] helper = libsecret" (two lines).



GitHub Copilot

+/-
60-day free trial, then $10/month or $100/year.

Paraphrased from Linux Downtime 51 7/2022:
+/-
  • It was trained on everyone's code from GitHub, regardless of license or source, but the code it produces for you is mostly based on your project's code plus the training. It's not just giving you other people's code.

  • It works quite well.

  • It is very valuable for producing comments, and for starting with a comment and producing code.

  • You can install it into VS Code.

  • It can work on build files such as Ansible files.


Matt Rickard's "How to Use GitHub Copilot Effectively"
Christian Heilmann's "GitHub Copilot for the Command Line is amazing!"

Similar products: Tabnine, mutable.ai, Fauxpilot ?



Count lines in files in git project on disk

+/-

# cd into project directory
git ls-files | xargs wc -l
# or:
git ls-files | grep -P ".*(js|html)$" | xargs wc -l
# or:
git ls-files | grep -vE ".*(png|jpg|ico)$" | xargs wc -l
# or:
sudo apt install cloc
cloc $(git ls-files)
#or:
cloc --vcs git

Count lines in files from git repository

+/-

# clone latest commit of project to disk, count, then remove it from disk
git clone --depth 1 https://github.com/OWNERNAME/PROJECTNAME.git
cd PROJECTNAME
cloc --vcs git
cd ..
rm -fr PROJECTNAME
Or use Chrome extension "GLOC" ? Shows only files in current directory, no recursion ?

Diff files on disk with committed files in main branch in repo

+/-

# Diff a single file on disk with same file in main branch:
git diff main -- FILENAME

# Diff all files on disk with same files in main branch:
git diff main --

If you ever wipe out the .git tree, and then want to commit source changes

+/-

# make a good backup

# in the overall projects directory:
git clone https://github.com/BillDietrich/linkcheckerhtml.git

git init
git remote add origin https://github.com/BillDietrich/linkcheckerhtml.git
git remote -v   # see repos linked to local repo

# maybe:
git config --global user.name "Your Name Here"
git config --global user.email "your_email@youremail.com"

# copy backed-up files to working dir

# do add, commit, push

If you delete a single file from local disk, how do you get a copy of it again ?



Egidio Docile's "How to backup your git repositories with gickup"