Skip to main content

Git

· 14 min read

History

  1. In 2002 Linux kernel project began using a proprietary DVCS called BitKeeper.

  2. In 2005 the tool was not free any more as the commercial company of BitKeeper and the Linux kernel team broke their relationship. Then Git was developed by the Linux development community.

  3. Goals of Git:

    1. Speed
    2. Simple design
    3. Strong support for non-linear development (thousands of parallel branches)
    4. Fully distributed
    5. Able to handle large projects like the Linux kernel efficiently (speed and data size)

What is Git

  1. Distinction between Git and nearly all other VCSs.

    1. With Git, every time you commit, or save the state of your project, Git basically takes a picture of what all your files look like at that moment and stores a reference to that snapshot.

    2. To be efficient, if files have not changed, Git doesn’t store the file again, just a link to the previous identical file it has already stored. Git thinks about its data more like a stream of snapshots.

  2. All the git histories are stored in the local database -- fast and no need to be online all the time

  3. Everything in Git is checksummed before it is stored and is then referred to by that checksum. It uses a SHA-1 hash -- a 40-character string composed of hexadecimal characters (0–9 and a–f) and calculated based on the contents of a file or directory structure in Git.

  4. Only adds data to the Git database

  5. File states in Git -- modified, staged, committed

    • Modified means that you have changed the file but have not committed it to your database yet.
    • Staged means that you have marked a modified file in its current version to go into your next commit snapshot.
    • Committed means that the data is safely stored in your local database.

First-time Git setup

  1. config files:

    1. [path]/etc/gitconfig -- every user
    2. ~/.gitconfig or ~/.config/git/config -- specific user
    3. config file in the Git directory (that is, .git/config) -- specific repository
  2. git config is a command used in Git to set configuration options for your Git installation. These configurations can be set at three levels:

    1. System level: Applies to every user on the system and all their repositories.
    2. Global level: Applies to the user level, i.e., for all repositories of the current user.
    3. Local level: Applies only to a specific repository.
  3. How to use git config:

    1. List all settings: You can list all Git configuration settings with:

      git config --list --show-origin
      git config user.name
      git config --list
    2. List settings for a specific level: To list settings for a specific level, use --global, --system, or --local:

      git config --global --list
    3. Setting Configurations

      1. Set a user name and email: This is commonly used to identify the author of commits.
      git config --global user.name "Your Name"
      git config --global user.email "your_email@example.com"
    4. Set an editor: To set a default text editor for Git (e.g., Vim, Nano, or Notepad++).

      git config --global core.editor "vim"
      git config --global core.editor emacs
    5. Get a specific configuration value: If you want to check the value of a specific configuration, you can use:

      git config user.name
    6. Set color UI: To enable colored output in Git commands.

      git config --global color.ui auto
    7. Set alias: You can create shortcuts for commonly used Git commands.

      git config --global alias.st status

    Afterwards, you can use git st instead of git status.

    1. Set default branch name: For new repositories, set the default name of the initial branch (e.g., main instead of master).
      git config --global init.defaultBranch main
  4. Global Configuration File: This is typically located in your user home directory, under .gitconfig.

  5. Local Configuration File: Found in the .git/config file in a Git repository.

  6. Settings at a more specific level (local) override settings at a more general level (global/system)

  7. Getting help

$ git help <verb>
$ git <verb> --help
$ man git-<verb>

$ git help config
  1. More concise version of git help is -h, eg. git add -h

Git Basics

  1. git init

  2. git add *.c or git add LICENSE

  3. git commit -m xxxx

  4. git clone https:// or
    git clone git:// or
    git clone user@server:path/to/repo.git or
    git clone url diretory

  5. file state changes

    1. Add the file: untracked --> staged
    2. Remove the file: unmodified --> untracked
    3. Edit the file: unmodified --> modified
    4. Stage the file: modified --> staged
    5. Commit: staged --> unmodified
    6. git status or git status -s or git status --short
  6. ignore files: .gitignore

    • Blank lines or lines starting with # are ignored.
    • Standard glob patterns work, and will be applied recursively throughout the entire working tree.
    • You can start patterns with a forward slash (/) to avoid recursivity.
    • You can end patterns with a forward slash (/) to specify a directory.
    • You can negate a pattern by starting it with an exclamation point (!).
    # ignore all .a files
    *.a
    # but do track lib.a, even though you're ignoring .a files above
    !lib.a
    # only ignore the TODO file in the current directory, not subdir/TODO
    /TODO
    # ignore all files in any directory named build
    build/
    # ignore doc/notes.txt, but not doc/server/arch.txt
    doc/*.txt
    # ignore all .pdf files in the doc/ directory and any of its subdirectories
    doc/**/*.pdf
  7. git diff compares what is in your working directory with what is in your staging area

  8. git diff --staged or git diff --cached can see what you’ve staged that will go into your next commit

  9. git commit / git commit -m xxxx

  10. If don't want to use git add . before committing them, can use git commit -a -m xxx

  11. Removing files:

    1. git rm a.txt stages the removal of the file for the next commit.
    2. git rm a.txt --cached removes a file from the repository but keep it in your working directory.
    3. gir rm -r [directory] removes a directory
    4. deletion with wild cards: use a backslash () in front of it
    5. git rm -f is used when the file being added but has not been committed
    6. git rm \*.txt == git rm '*.txt'
  12. Moving files:

    git mv file-a file-b

    which is equivalent to

    mv file-a file-b
    git rm file-a
    git add file-b
  13. Viewing the commit history

    1. git log
    2. git log -p -2 or git log --patch -2 viewing the differences in the last two commits
    3. git log --stat outputs a summary at the end
    4. formatting log output:
      • git log --pretty=oneline or git log --oneline

      • git log --pretty=format:"%h - %an, %ar : %s"

      • Useful specifiers for git log --pretty=format

        specifierOutput
        %HCommit hash
        %hAbbreviated commit hash
        %TTree hash
        %tAbbreviated tree hash
        %PParent hashes
        %pAbbreviated parent hashes
        %anAuthor name
        %aeAuthor email
        %adAuthor date (format respects the --date=option)
        %arAuthor date, relative
        %cnCommitter name
        %ceCommitter email
        %cdCommitter date
        %crCommitter date, relative
        %sSubject
      • The author is the person who originally wrote the work, whereas the committer is the person who last applied the work.

      • git log --pretty=format:"%h %s" --graph

      • Common options to git log:

        • --pretty=oneline/short/full/fuller/format
        • --relative-date eg. outputs 'two weeks ago'
        • --stat / --short-stat / --name-only / --name-status / --abbrev-commit
        • git log --since=2.weeks / git log --since=2008-01-15
        • --author filters authors, grep can be used to filter certain commits with keywords
        • git log -S[string]
        • To search for changes involving function_name: git log -Sfunction_name
          • to show diffs git log -p -Sfunction_name
          • -i case insensitive
          • limit the search to a specific file git log -Sfunction_name -- [filepath]
          • -n show only the last n commits
          • --since, --after
          • --until, --before
          • --author
          • --comitter
          • --grep only shows commits with a commit message containing the string
          • -S only show commits adding or removing code matching the string
  14. Undoing things

    1. git commit --amend
    2. unstaging a staged file git reset HEAD <file>... or git restore --staged <file>…
    3. unmodifying a modified file git checkout -- <file>... or git restore <file>
  15. Working with remotes

    1. git remote / git remote -v
    2. for git remote -v, it would list all the remotes, which means we can pull/push to all the remotes
    3. Adding remote repositories: git remote add <shortname> <url>
      • git remote add pb <url>
      • git fetch pb
      • git fetch <remote>
      • git pull
      • git config --global pull.rebase "false"
      • git push <remote> <branch>
    4. inspecting a remote git remote show origin
    5. remame a remote git remote rename pb paul
    6. remove a remote gir remote remove paul
  16. Tagging

    1. list tags git tag, lists the tags in alphabetical order; the order in which they are displayed has no real importance.
    2. git tag -l "v1.8.5*" listing tag wildcards requires -l or --list option
    3. creating tags -- lightweight or annotated
      1. annotated: git tag -a v1.4 -m "my version 1.4" and git show v1.4
      2. lightweight: git tag v1.4-lw and git show v1.4-lw
      3. add a tag for a past commit: git tag -a v1.2 9fceb02 and git show v1.2
      4. git push command doesn’t transfer tags to remote servers, so we need to share tages to remote servers, git push origin <tagname>
      5. if there are many tags that need to be pushed git push origin --tags
    4. deleting local tags git tag -d v1.4-lw
    5. deleting remote tages git push origin --delete <tagname>
    6. In “detached HEAD” state, if you make changes and then create a commit, the tag will stay the same, but your new commit won’t belong to any branch and will be unreachable, except by the exact commit hash.
    7. To fix a bug in a certain version(tag), we need to use branch git checkout -b version2 v2.0.0
  17. git alias git config --global alias.gcl 'clone' , then we can use git gcl xxx

  18. To make git clone == gcl, you have to set it in the shell: alias gcl='git clone'

Git Branching

  1. A branch in Git is simply a lightweight movable pointer to one of these commits

  2. create a new branch git branch xxxx

  3. a special pointer called HEAD lets git know which branch you are on

  4. to see which branch you are on git log --oneline --decorate

  5. switching branches git checkout testing moves HEAD to point to the testing branch

  6. create a new branch and want to switch to that new branch at the same time git checkout -b <newbranchname>

  7. from git version 2.23, git switch existing-branch == git checkout existing-branch

  8. basic merging

    git checkout [target-branch]
    git merge [source-branch]
    git add [conflicted-file]
    git commit
    git push origin [target-branch]
  9. git mergetool fires up an appropriate visual merge tool and walks you through the conflicts

  10. list current branches git branch, * character that prefixes the master branch: it indicates the branch that you currently have checked out

  11. see the last commit on each branch git branch -v

  12. --merged and --no-merged options options

  13. delete a branch git branch -d, to force it, git branch -D

  14. change branch name

    git branch --move old-name new-name
    git push --set-upstream origin new-name
    git push origin --delete old-name
  15. change the master branch name from master to main

    git branch --move master main
    git push --set-upstream origin main
    git push origin --delete master
  16. branching workflow -- long running

    1. a typical workflow: the main branch only has code that has been or will be released, and have another parallel branch named develop or next that they work from or use to test stability, and when it gets to a stable state, it can be merged into main
    2. it can be done for several levels of stability
  17. banching workflow -- short lived

    1. open a few topic branches to implement any functions or fix a bug in them, then merge them into the main branch
    2. it can be done with several levels as well
  18. remote branches git ls-remote <remote> or git remote show <remote>

    1. remote-tracking branches are references to the state of remote branches
    2. Remote-tracking branch names take the form <remote>/<branch>.
    3. when doing git clone, in your local repository will have a pointer that points to the remote main branch, which is origin/main, and also have a pointer points to the local main branch, which is main, after you made some changes and commits on the main branch, your local main pointer moves, while the remote origin/main pointer still remains in the old location.
    4. “origin” is the default name for a remote when you run git clone. If you run git clone -o booyah instead, then you will have "booyah/main" as your default remote branch.
  19. adding multiple remote servers

    git remote add teamone xxxxx
    git fetch teamone

    git fetch origin
  20. share a local branch to remotes git push <remote> <branch>, then others can fetch it and see the new branch while running git fetch orgin / git fetch teamone

    git push origin a-new-local-branch-name
    git push teamone a-new-local-branch-name
  21. tracking branches

    1. When Creating a New Local Branch:

      1. git checkout -b [local-branch] [remote-name]/[remote-branch]
      2. git switch -c [local-branch] [remote-name]/[remote-branch]
    2. Setting an Existing Local Branch to Track a Remote Branch:

      1. git branch -u [remote-name]/[remote-branch] [local-branch]
      2. if you are currently checked out in the local branch: git branch -u [remote-name]/[remote-branch]
    3. benefits:

      • Simplified Push and Pull: When you have a tracking relationship set up, you can use git push and git pull without specifying the remote and branch name.

      • Status Information: Running git status on a tracking branch shows how many commits the local branch is ahead or behind the remote branch.

      • Automatic Remote Branch Updates: Running git fetch automatically updates the status of your remote-tracking branches.

    4. see the tracking relationships: git branch -vv -- it shows info from the local database

    5. to hav up-to-date info, fetch from all your remotes right before running this git fetch --all; git branch -vv

  22. git pull

  23. delete remote branches git push origin --delete serverfix

  24. git rebase

    1. if using merging to merge experient to main : git merge
    2. if using rebase:
    git checkout experiment
    git rebase main
    git checkout main
    git merge experiment
  25. img.png

    git rebase --onto master server client
    git checkout master
    git merge client

    img_1.png

    git rebase master server  // equivalent to git checkout server and git rebase master
    git checkout master
    git merge server

    git branch -d server
    git branch -d client

    img_2.png

  26. Do not rebase commits that exist outside your repository and that people may have based work on.

Git on the Server

  1. Git can use four distinct protocols to transfer data: Local, HTTP, Secure Shell (SSH) and Git.

  2. Putting the Bare Repository on a Server:

    scp -r my_project.git user@git.example.com:/srv/git

    ssh user@git.example.com
    cd /srv/git/my_project.git
    git init --bare --shared
  3. Setting up the Server:

sudo adduser git
su git
cd
mkdir .ssh && chmod 700 .ssh
touch .ssh/authorized_keys && chmod 600 .ssh/authorized_keys

cd /srv/git
mkdir project.git
cd project.git
git init --bare
  1. on a client

    cd myproject
    git init
    git add .
    git commit -m 'Initial commit'
    git remote add origin git@gitserver:/srv/git/project.git
    git push origin master
  2. then others can do: git clone git@gitserver:/srv/git/project.git

  3. Git Daemon / Smart HTTP / GitWeb / GitLab

Miscellaneous

  1. git reset --hard 1a410efbd13591db07496601ebc7a059dd55cfe9

  2. git reflog

  3. git log -g

  4. $ git fsck --full
    Checking object directories: 100% (256/256), done.
    Checking objects: 100% (18/18), done.
    dangling blob d670460b4b4aece5915caf5c68d12f560a9fe3e4
    dangling commit ab1afef80fac8e34258ff41fc1b867c702daa24b
    dangling tree aea790b9a58f6cf6f2804eeac9f0abbe9631e4c9
    dangling blob 7108f7ecb345ee9d0084193f147cdad4d2998293
  5. $ git gc
    Counting objects: 17, done.
    Delta compression using up to 8 threads.
    Compressing objects: 100% (13/13), done.
    Writing objects: 100% (17/17), done.
    Total 17 (delta 1), reused 10 (delta 0)
  6. $ git count-objects -v
    count: 11
    size: 4904
    in-pack: 15
    packs: 1
    size-pack: 8
    prune-packable: 0
    garbage: 0
    size-garbage: 0