Basic Concepts

  • Working Directory
  • Staging Area (.git/index)
  • .git directory

Useful Commands

  • Configuration files

    • Repository config file: .git/config

    • System config file: ~/.gitconfig

      .git\config
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      [core]
      repositoryformatversion = 0
      filemode = false
      bare = false
      logallrefupdates = true
      worktree = C:/git/myrepo
      ignorecase = true
      [submodule]
      active = .
      [remote "origin"]
      url = https://git-codecommit.ap-southeast-1.amazonaws.com/v1/repos/myrepo
      fetch = +refs/heads/*:refs/remotes/origin/*
      [branch "master"]
      remote = origin
      merge = refs/heads/master
      [branch "release/prod"]
      remote = origin
      merge = refs/heads/release/prod
      remote = origin
      merge = refs/heads/release/preprod
      [branch "release/test"]
      remote = origin
      merge = refs/heads/release/test
      [branch "release/dev"]
      remote = origin
      merge = refs/heads/release/dev

  • git remote

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    $ git remote show
    origin

    $ git remote -v
    origin https://git-codecommit.ap-southeast-1.amazonaws.com/v1/repos/myrepo (fetch)
    origin https://git-codecommit.ap-southeast-1.amazonaws.com/v1/repos/myrepo (push)

    $ git remote show origin
    * remote origin
    Fetch URL: https://git-codecommit.ap-southeast-1.amazonaws.com/v1/repos/myrepo
    Push URL: https://git-codecommit.ap-southeast-1.amazonaws.com/v1/repos/myrepo
    HEAD branch: master
    Remote branches:
    develop tracked
    feature/test tracked
    master tracked
    release/dev tracked
    release/preprod tracked
    release/prod tracked
    release/test tracked
    Local branches configured for 'git pull':
    master merges with remote master
    release/dev merges with remote release/dev
    release/preprod merges with remote release/preprod
    release/prod merges with remote release/prod
    release/test merges with remote release/test
    Local refs configured for 'git push':
    master pushes to master (up to date)
    release/dev pushes to release/dev (up to date)
    release/preprod pushes to release/preprod (up to date)
    release/prod pushes to release/prod (up to date)
    release/test pushes to release/test (up to date)
  • git push [repository] [refspec]

    1
    2
    3
    4
    5
    $ git status
    On branch release/preprod

    $ git push
    Everything up-to-date
  • git rebase (current branch is topic)

            A---B---C topic*
           /
      D---E---F---G master
    
      git rebase master
      git rebase master topic
    
                    A'--B'--C' topic*
                   /
      D---E---F---G master
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

    $ git log --oneline
    c60c0d9 (HEAD -> release/dev, origin/release/dev) Upgrade node version
    16675e8 Update oracledb version
    e5461ba Update oracledb version
    4e70188 Change Nodejs version to 14
    52cf369 Add GEO IP City Function

    52cf369 -- 4e70188 -- e5461ba -- 16675e8 -- c60c0d9

    Squash 4e70188 -- e5461ba -- 16675e8 -- c60c0d9 into one commit

    $ git rebase -i 52cf369

    pick 4e70188 Change Nodejs version to 14
    squash e5461ba Update oracledb version # meld into previous commit
    squash 16675e8 Update oracledb version # meld into previous commit
    squash c60c0d9 Upgrade node versiong # meld into previous commit

    52cf369 -- d59392d

    $ git log --oneline
    d59392d Update Nodejs version to 14 and oracledb version
    52cf369 Add GEO IP City Function
  • git merge (current branch is master)

      A---B---C topic
      /
      D---E---F---G master*
    
      git merge topic
    
      A---B---C topic
      /         \
      D---E---F---G---H master*
      
    1
    2
    3
    4
    5
    # Merge topic with current branch
    $ git merge topic
    Updating ea2980a..532a0fa
    Fast-forward
    README.md | 2 +-
  • git pull
    git fetch followed by git merge or git rebase (with --rebase)

    FETCH_HEAD is a short-lived ref, to keep track of what has just been fetched from the remote repository

        A---B---C master on origin
       /
      D---E---F---G master*
      ^
      origin/master in your repository  
    
        A---B---C origin/master
       /         \
      D---E---F---G---H master
    
    
  • git fetch
    git fetch --all Fetch all remote branches
    git fetch origin master Fetch only remote master branch

  • git commit
    Record changes to the repository
    -a Automatically stage modified and deleted files but new files are not affected (use git add for new files)

  • git add
    Add file contents to the staging area(index)

  • git checkout
    Switch branches or restore working tree files
    git checkout [<branch>]
    -b - create a new branch
    -B - create a new branch or reset the branch

  • git show
    Shows one or more objects (blobs, trees, tags and commits).

  • git log
    --oneline

  • ancestry references
    ^: the parent of that commit
    ^2: the second parent of that commit (from the branch that was merged (say, topic))
    ~: first parent
    ~2: first parent of first parent (it traverses the first parents the number of times you specify)
    ~~: first parent of first parent

Git submodules

I will use my blog site to illustrate the git submodules features. Recently, I have setup a blog site by using hexo. The blog will use another hexo theme - freemind from github. First, I have forked the project as https://github.com/pnyiu/hexo-theme-freemind:

  1. Scenario one - include other git project in existing git project
    git clone https://github.com/pnyiu/hexo-theme-freemind.git themes/freemind
    .
    └── blog
    ├── _config.yml
    ├── db.json
    ├── .deploy_git
    ├── .git
    ├── .gitignore
    ├── node_modules
    ├── package.json
    ├── public
    ├── scaffolds
    ├── source
    └── themes
    └── freemind
       ├── _config.yml
       ├── .git
       ├── .gitignore
       ├── languages
       ├── layout
       ├── LICENSE
       ├── package.json
       ├── README.md
       └── source
    The blog repository simply ignore the freemind repository stackoverflow.
  2. Scenario two - use git submodules

    Submodules allow you to keep a Git repository as a subdirectory of another Git repository. This lets you clone another repository into your project and keep your commits separate.

    It’s quite likely that if you’re using submodules, you’re doing so because you really want to work on the code in the submodule at the same time as you’re working on the code in the main project (or across several submodules). Otherwise you would probably instead be using a simpler dependency management system (such as Maven or Rubygems).

    Use git submodule add <repo_url> to add submodule as below:
    $ git submodule add https://github.com/pnyiu/hexo-theme-freemind.git themes/freemind
    Cloning into 'themes/freemind'...
    remote: Counting objects: 1390, done.
    remote: Compressing objects: 100% (22/22), done.
    remote: Total 1390 (delta 9), reused 5 (delta 0), pack-reused 1367
    Receiving objects: 100% (1390/1390), 1.91 MiB | 302.00 KiB/s, done.
    Resolving deltas: 100% (814/814), done.
    Checking connectivity... done.
    $ tree -L 1 -a
    .
    ├── _config.yml
    ├── db.json
    ├── .deploy_git
    ├── .git
    ├── .gitignore
    ├── .gitmodules
    ├── node_modules
    ├── package.json
    ├── public
    ├── scaffolds
    ├── source
    └── themes
    $ cat .gitmodules
    [submodule "themes/freemind"]
    path = themes/freemind
    url = https://github.com/pnyiu/hexo-theme-freemind.git
    • New file .gitmodules is created to keep track the submodules path and url.
    • Git would get the changes and update the files in the subdirectory but will leave the sub-repository in what’s called a detached HEAD state. This means that there is no local working branch (like master, for example) tracking changes.
    • Doesn’t track submodule contents when you’re not in that directory
    • For new project with submodules, use (git submodule init and git submodule update) or git clone --recursive to initialize and fetch all data from that project and submodules.

Conflicts with modified files when switch to another branch

It is common to work with multiple branches. For example, if we are working the file test.html:

  1. Update test.html in master branch
  2. Switch to testbranch branch, update and commit the changes to git
  3. Switch to master branch, update the test.html and do not commit the changes Then, switch to testbranch but failed
$ git init
$ git status
$ echo "Created at master branch" > test.html
$ git add test.html
$ git commit -m "Commit test.html at master branch"
$ git checkout -b test
$ echo "Modified at test branch" >> test.html
$ git commit -a -m "Commit at test branch" # Use -a to stage modified tracking files
$ git checkout master
$ echo "Modified at master branch" >> test.html
$ git checkout test
error: Your local changes to the following files would be overwritten by checkout:
test.html
Please, commit your changes or stash them before you can switch branches.
Aborting


Use ssh for authentication

GitHub

  • Generate new SSH key / use existing SSH key
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # List your existing SSH keys
    $ ls ~/.ssh -l
    total 40
    -rw-r--r-- 1 calviny calviny 172 Jul 21 11:52 config
    -rw------- 1 calviny calviny 1679 Jul 4 2019 pnyiu
    -rw-r--r-- 1 calviny calviny 404 Jul 4 2019 pnyiu.pub
    -rw------- 1 calviny calviny 25292 Jul 21 12:00 known_hosts

    # Generating a new SSH key
    ssh-keygen -t ed25519 -C "your_email@example.com"
  • Add a new SSH key to GitHub
    • Click your profile photo, then click Settings
    • Click SSH and GPG keys
    • Click New SSH key or Add SSH key
    • Copy and paste the public key in the Key field
    • Update ~/.ssh/config
      Host github.com
      User git
      IdentityFile ~/.ssh/pnyiu
    • Test SSH connection
      ssh -T git@github.com

AWS CodeCommit

  • Generate new SSH / use existing SSH key
  • Upload to AWS by Identity and Access Management (IAM)
  • Update ~/.ssh/config (refer to GitHub example)
    Host git-codecommit.*.amazonaws.com
    User <SSH key ID>
    IdentityFile ~/.ssh/pnyiu
  • Clone the repository
    git clone ssh://<SSH key ID>@git-codecommit.ap-east-1.amazonaws.com/v1/repos/my-repo
  • Check the remote configuration
    $ git remote show origin
    * remote origin
    Fetch URL: ssh://<SSH key ID>@git-codecommit.ap-east-1.amazonaws.com/v1/repos/my-repo
    Push URL: ssh://<SSH key ID>@git-codecommit.ap-east-1.amazonaws.com/v1/repos/my-repo