git

最後更新: 2024-10-30

介紹

git 係一個 source code management system

 

目錄

 


安裝

 

# Ubuntu

apt-get install git

# Version

git --version

git version 1.7.9.5

 


HEAD / master / origin

 

HEAD [branch]:

My repo currently pointing at (Most of the time HEAD points to the latest commit in your branch)

master:

"master" means "the main branch", it is considered the definitive view(website) of the repo.

# default branch that git creates for you when first creating a repo (git init)

origin:

"origin" 是預設的 remote repos 名稱

 => That remote repo is almost always called origin

設定 origin

你可以使用 "origin" 來引用它

i.e.

git push origin master         # 將 local 的 master 分支推送到 origin(它是在 remote 的)

How Git stores its data

Git doesn’t store data as a series of changesets or differences, but instead as a series of snapshots.

Element checksum: SHA-1 hash

"git commit"

會新建 3 個物件

* blob 物件 ( the contents of each of your files) [SHA-1]
* tree 物件 ( directory and specifies which file names )[SHA-1]
* commit 物件 ( metadata ) [SHA-1]

commit 1 --> commit 2 --> commit 3
  |             |           ...
 tree         tree
  |             |
 blob         blob

Fast-forward

C2 <- C4

you merged in was directly ahead of the commit C2 you’re on,
Git simply moves the pointer forward.

Workflows

With Git, you don’t have to deploy your fix along with the iss53 (for new feature)changes you’ve made,

and you don’t have to put a lot of effort into reverting those changes before you can work on applying your fix to what is in production.

All you have to do is switch back to your master branch.

為 production 建立 hotfix 先, 不在新功能上做 hotfix

 


最常用功能一覽

 

Clone (download) a new repository

* clone 一次就有齊所有 branch (whole repository)

git clone [git/https]://?????/?????.git

e.g.

# 之後會有 Folder "ngx_pagespeed"

git clone https://github.com/pagespeed/ngx_pagespeed.git

List branch

shows all

git branch -a

  2.1.3
  master
* stable
  remotes/origin/2.1.3
  remotes/origin/CDN
  remotes/origin/HEAD -> origin/master
  remotes/origin/jst
  remotes/origin/master
  remotes/origin/nginx-1.0
  remotes/origin/nginx-1.2
  remotes/origin/nginx-1.2.0
  remotes/origin/nginx-development
  remotes/origin/revert-500-robin
  remotes/origin/stable

最尾係 branch 名

查看已訂閱了的 branch

git branch

* 2.1.3                                       # "*" 代表在此 branch
  master

Show remote

Manage the set of remotes repositories whose branches you track.

git remote [show]

origin                                        # 起源

git remote -v

origin  https://git.php.net/repository/php-src.git (fetch)
origin  https://git.php.net/repository/php-src.git (push)

git remote show origin

* remote origin
  Fetch URL: https://git.php.net/repository/php-src.git
  Push  URL: https://git.php.net/repository/php-src.git
  HEAD branch: master
  Remote branches:
    PEAR_1_4DEV                               tracked
    PECL                                      tracked
    PECL_4_3                                  tracked
    PECL_OPENSSL                              tracked
    PHAR_1_2                                  tracked
    PHP-4.0                                   tracked
    PHP-4.0.5                                 tracked
    PHP-4.0.6                                 tracked
    .............................
  Local branches configured for 'git pull':
    PHP-7.0.16 merges with remote PHP-7.0.16
    PHP-7.0.17 merges with remote PHP-7.0.17
    master     merges with remote master
  Local refs configured for 'git push':
    PHP-7.0.16 pushes to PHP-7.0.16 (up to date)
    PHP-7.0.17 pushes to PHP-7.0.17 (local out of date)
    master     pushes to master     (local out of date)

Checkout a branch

git checkout 2.1.3

Revert your changes

# 比如刪除錯修改錯的 file 想 revert (新增的 File 依然存在)

git checkout .

Clone the one you already have on your hard disk

git clone /path/to/foo 

Update

cd ngx_pagespeed

git pull

 * pull = fetch + merge

e.g. ngx_pagespeed

Already up-to-date.

e.g. tengine

remote: Counting objects: 20, done.
remote: Total 20 (delta 10), reused 10 (delta 10), pack-reused 10
Unpacking objects: 100% (20/20), done.
From https://github.com/alibaba/tengine
   2069159..b2531ec  master     -> origin/master
Already up-to-date.

force “git pull” to overwrite local files

# git reset --hard origin/<branch_name>

git reset --hard

HEAD is now at 37eb1e4 prepare final versions

pull 拎的 URL

# Git stored the location of repository in the repository configuration, and that location is used for pulls:

cd testproj/

git config --get remote.origin.url

https://[email protected]/datahunter88/testproj.git

git fetch

git fetch [<options>] [<repository> [<refspec>…​]]

Fetch branches and/or tags (collectively, "refs") from one or more other repositories

When no remote is specified, by default the origin remote will be used,
unless there’s an upstream branch configured for the current branch.

# Alice can peek at what Bob did without merging first, using the "fetch" command;
# This operation is safe even if Alice has uncommitted local changes.
alice$ git fetch /home/bob/myrepo master

# -p, --patch <= Generate patch
# log use "-p" see complete diffs at each step
alice$ git log -p HEAD..FETCH_HEAD

Check Status

cd ngx_pagespeed

git status

Opts

-v, --verbose

e.g. ngx_pagespeed

On branch master
Your branch is up-to-date with 'origin/master'.

nothing to commit, working directory clean

e.g. tengine

# On branch 2.1.3
nothing to commit (working directory clean)

clean

git clean -xdf  # Remove untracked files from the working tree

-f                   # --force

-d                   # Remove untracked directories in addition to untracked files.

-x                   # Don’t use the standard ignore rules read from .gitignore
                      # ignored files are also removed (build products)

-n                   # --dry-run

Untracked files

(files that didn't originally exist in the tree, ones you created and not edited)

 

 


設置自己的身份

 

# 設定自己的名稱及E-Mail

# Global Settings

git config --global user.name "Your Name"

git config --global user.email "[email protected]"

# Per User (Per Folder) Settings

git config user.name "Your Name"

git config user.email "[email protected]"

Checking

git config user.name

git setting

git config --global user.name "x"

git config --global user.email "x@y"

 

 


Configure git

 

# Git 用此 command 設定

git config

# Configure File

/etc/gitconfig     # system

Contains values applied to every user on the system and all their repositories.

(If you pass the option "--system" to git config, it reads and writes from this file specifically.)

~/.gitconfig or ~/.config/git/config  # user(you)

Git read and write to this file specifically by passing the "--global" option

.git/config        # repository

You can force Git to read from and write to this file with the "--local" option

# Opts

  • -l, --list           # list all current config
  • -e, --edit
  • --unset            # remove a variable: name [value-regex]
  • --add              # add a new variable: name value
  • --get               # get value: name [value-regex]
  • --global           # For writing options: write to global "~/.gitconfig" file rather than the repository".git/config"

# Usage

# List all setting (--list)

# global setting

git config -l

user.name=Tim
[email protected]

P.S.

  到 repository 時會 show 埋 local setting

# local setting

cd repository

cat .git/config

# Files

~/.gitconfig

[user]
        name = Tim
        email = [email protected]

# Alias

# git ci,取代輸入git commit

$ git config --global alias.ci commit

$ git config --global alias.st status

$ git config --global alias.co checkout

$ git config --global alias.br branch

.gitconfig

[alias]
  ci = commit
  st = status
  co = checkout
  br = branch

# 常用設定

editor

git config --global core.editor vim

merge tool

git config --global merge.tool vimdiff

push.default

# 不設定 push.default 會令每次 git push 有 warning

# 'matching': git will push local branches to the remote branches that already exist with the same name.

# 'simple' (Git 2.0 default): more conservative behavior, which only pushes the current branch to the corresponding remote branch
                                         that 'git pull' uses to update the current branch.

git config --global push.default matching
 

# 自動補齊

source /etc/bash_completion.d/git-prompt

 


Save username and password(Login)

 

https 與 ssh

git 支援兩種 protocol

ssh://[email protected]/username/repo.git

https://github.com/username/repo.git

credential.helper

 * store 及 cache 都是由 push 引發保存

 helper: store

# Helper to store credentials on disk( ~/.git-credentials ) <-- unencrypted

git config credential.helper store      # per repository config

.git/config

...
[credential]
        helper = store

cat ~/.git-credentials

https://username:[email protected]

helper: cache

# stored credentials never touch the disk, and are forgotten after a configurable timeout
# accessible over a Unix domain socket

git config credential.helper 'cache [options]'

# Default options:

  • --timeout 900
  • --socket ~/.git-credential-cache/socket

保存 global 設定

git config --global credential.helper 'cache --timeout 300'

exit early

git credential-cache exit

 


Create a new repository

 

git clone https://gitlab.com/datahunter88/testproj.git

cd testproj

touch README.md

git add README.md

git commit -m "add README"

git push -u origin master

# -u, --set-upstream

# 為成功的 push 及 pull, 加 tracking

# 當沒有 set 時, 就會見到

There is no tracking information for the current branch.
Please specify which branch you want to merge with.

 * 要整個 push 動作完成後在 remote 才 display update

# set tracking only

git branch --set-upstream-to=origin/<branch> master

git add

# all *.txt files under Documentation directory and its subdirectories:

git add Documentation/\*.txt

# it does not consider subdir/git-foo.sh (lets the shell expand the asterisk)

git add git-*.sh

 


Importing a new project

 

# 把新 project 解開

$ tar xzf project.tar.gz

$ cd project

# 建立 .git/

$ git init

Initialized empty Git repository in /home/tim/myapp/.git/

.git/ 內有

branches  config  description  HEAD  hooks  info  objects  refs

# remote

git remote add origin https://gitlab.com/datahunter88/testproj.git

# 為當前的狀態建立 snapshot

# git add filename

# "." = all files & subdirectory under the current directory

$ git add .

# 保存 "git add ." 所建立的狀況 (把 diff 放入 index Folder)

# git commit [-m "string"]

$ git commit -m "Initial app setup."

 25 files changed, 19319 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 README.md

# 查看 Status (看到那 file modify 了而未 commit)

git status

# push it in master branch

git push -u origin master

# Viewing project history

# 新到舊的順序列出儲存庫的提交的歷史記錄

git log

git log --pretty=oneline --since='5 minutes ago'

git log --pretty=oneline --until='5 minutes ago'

git log v2.5..v2.6              # commits between v2.5 and v2.6

git log v2.5..                    # commits since v2.5

git log stable..master        # will list commits made in the master branch but not in the stable branch

# show: get more info

git show commit-id

git show first-few-characters-commit-id

git show HEAD        # the tip of the current branch

git show HEAD^      # to see the parent of HEAD

git show HEAD^^     # to see the grandparent of HEAD

git show v2.5:Makefile

 


git-commit

 

# all in one step

# automatically notice any modified (but not new) files, add them to the index, and commit,

git commit -a

# comment from file

# Take the commit message from the given file. Use - to read the message from the standard input.

-F <file> / --file=<file>
 


Branches

 

List, create, or delete branches.

Help: man git-branch

# view local branch 的情況

git branch

* master

# rename local repos

# -M                   Shortcut for --move(-m) --force(-f)
# --move(-m)     Move/rename a branch
# Without -f, git branch refuses to change an existing branch

git branch -M main

# 查看 remote branch 的情況

# -r, --remotes               <= List or delete (used with -d) the remote-tracking branches

git branch -r

# Create local "experimental" branch

git branch experimental

# switch to the experimental branch

git checkout experimental

Remark: Create & Switch to new branch

# "-b" a new branch to be created and then checked out

git checkout -b [name_of_your_new_branch]

# Add a new remote for your branch

$ git remote add [name_of_your_remote]

# Push the branch on new github

$ git push origin [name_of_your_new_branch]

OR

$ git push [name_of_your_new_remote] [name_of_your_branch]

# remark - 查看 branch 的對應

git remote show origin

  Remote branches:
    mybranche-v1 tracked
    mybranche-v2 tracked
    mybranche-v3 tracked
    master      tracked
  Local branch configured for 'git pull':
    master merges with remote master
  Local refs configured for 'git push':
    mybranche-v1 pushes to mybranche-v1 (up to date)
    mybranche-v2 pushes to mybranche-v2 (up to date)
    mybranche-v3 pushes to mybranche-v3 (up to date)
    master      pushes to master      (up to date)

# Go back master

git checkout master

# To merge the changes made in experimental into master

git merge experimental

# To delete the local branch use:

When you're dealing with deleting branches both locally and remotely,

keep in mind that there are 3 different branches involved:

 * The local branch X.
 * The remote origin branch X.
 * The local remote-tracking branch origin/X that tracks the remote branch X.

# -d option is an alias for --delete
# which only deletes the branch if it has already been fully merged in its upstream branch.

git branch -d the_local_branch

i.e. # Delete "2.0.21" branch

git branch -d 2.0.21

Deleted branch 2.0.21 (was cc8d8b6).

i.e. # Delete "2.0.21" master

git branch -d master

warning: deleting branch 'master' that has been merged to
         'refs/remotes/origin/master', but not yet merged to HEAD.
Deleted branch master (was f3cd80d).

# -D, which is an alias for --delete --force,
# which deletes the branch "irrespective of its merged status.

git branch -D master

# Delete Remote Branch

# --delete - All listed refs are deleted from the remote repository.

git push origin --delete <branch_name>

# # All remote-tracking branches and configuration settings for the remote are removed.

git remote rm <branch_name>

# rename remote repos

git remote rename old_name new_name

# filter

The useful --merged and --no-merged options can filter this list to branches that you have or have not yet merged into the branch you’re currently on.

git branch --merged

Branches on this list without the * in front of them are generally fine to delete with git branch -d;

 


merge

 

# To merge the changes made in experimental into master, run

$ git checkout experimental

(edit file)

$ git commit -a

$ git checkout master

$ git merge experimental

# If there are conflicts

git diff

conflicts 的 file 內有

<<<<<<<, =======, and >>>>>>>

# run git add on each file to mark it as resolved.

git add conflicts_file

# Once you’ve edited the files to resolve the conflicts

git commit -a

# publish your local commits

git push

 


checkout a file

 

# checkout by filename

git checkout test.py

# checkout by hash

# 查看 hash 的 code

git hist

# checkout 某個 hash

git checkout <hash>

 


git-rm

 

Usage

git rm test-file                # Local

git rm -r test-folder         # Remote

Opts

-n, --dry-run

-r                             # Allow recursive removal when a leading directory name is given.

--cached                   # Use this option to unstage and remove paths only from the index.
                                # Working tree files, whether modified or not, will be left alone.

 


git add

 

-v, --verbose

-n, --dry-run

 


git reset

 

Reset current HEAD to the specified state

# 回到 add / edit file

git reset [mode]

mode: --mixed | --soft | --hard

--mixed

Resets the index but not the working tree

(i.e., the changed files are preserved but not marked for commit) and reports what has not been updated.

$ edit
$ git add frotz.c filfre.c
$ mailx
$ git reset
$ git pull git://info.example.com/ nitfol

--soft

# Does not touch the index file or the working tree at all (but resets the head to <commit>,
# just like all modes do). This leaves all your changed files "Changes to be committed", as git status would put it.

git reset --soft HEAD~

--hard

# Resets the index and working tree. Any changes to tracked files in the working tree since <commit> are discarded.

git reset --hard HEAD~

# 還原 edit

checkout file

 


Tag

 

我們會使用 tag 功能去標記出發行版本( i.e. "V1.0" )

# 查看 repo 設定了什麼 tag

git tag

# Search tag in repo

git tag -l 'php-7.0.*'

# 加 tag

git tag v1

OR

git tag -a v1.4 -m 'my version 1.4'

# 查看某 tag 的有關資料

git show v1.4

# Checkout 某 tag

git checkout v1

OR

git checkout tags/<tag_name>

# Removing tag (再也去不了那 state)

git tag -d tag_name

# 分享標籤

# "git push" 指令並不會將標籤傳到遠端伺服器上

# "--tags" 一次過處理所有

git push origin [tagname]

 


To compare two tags

 

By Web

https://github.com/<user>/<repo>/compare/<beginning-tag>…<ending-tag>

e.g.

https://github.com/rustdesk/rustdesk-server/compare/1.1.11...1.1.12

By CLI

git diff tag1 tag2

# see only the list of files that were changed:
git diff tag1 tag2 --stat

# look at the differences for some particular file
git diff tag1 tag2 -- some/file/name

git log tag1..tag2

 


Undo

 

# Reset the Staging Area (add 了而未 commit)

git reset HEAD test.py

# undo commit

git revert HEAD

 


Move

 

git mv hello.rb lib

OR

mv hello.rb lib
git add lib/hello.rb
git rm hello.rb

 


.gitignore

 

Specifies intentionally untracked files to ignore

 * git doesn't store empty folders.

 * It is not possible to re-include a file if a parent directory of that file is excluded.

 * working on current folder

Rules

"#"                        # A comment

Pattern                  # Each line in a gitignore file specifies a pattern.

"backup"                # 略過名叫 backup 的檔案及目錄. 有隱藏的 ^Pattern$ 在首尾
                     
          (不會略過 Start_backup 及 backup_End)

"*.bak"                  # 所有名叫 a.bak, b.bak ... 的檔案及目錄

"_bak/"                  # 所有 _bak/ 目錄被略過

"/*.c"                     # 只略過頂層的 file.c, 不會影響 subfolder 的 file.c

"/folder/**/testfile"   # matches "a/testfile", "a/x/testfile", "a/x/y/testfile" and so on

"!"                         #  which negates the pattern

# exclude everything except directory foo/bar
/*
!/foo
/foo/*
!/foo/bar

.gitignore templates

https://github.com/github/gitignore

Remove files git ignored files from remote repository

git rm -r --cached . && \
git add . && \
git commit -m "Removing all files in .gitignore" && \
git push

git-rm

 


Export

 

git clone https://gitlab.com/datahunter88/testproj.git

cd testproj

# export "master" 到 /full/path/to/zipfile.zip
# Default 是用 tar 打包, ZIP: "--format zip"

git archive --output /full/path/to/package.tar master

git archive --format zip --output /full/path/to/package.zip master

tar -tf package.tar

 


GUI

gitk - a tcl/tk revision tree visualizer

 


Element

 

object database

It is the rather elegant system used to store the history of your project
(files, directories, and commits.)

index file

It is a cache of the state of a directory tree, used to create commits, check out working

 


Apache with git

 

.htaccess

Create a .htaccess file in the .git folder and put the following in this file:

Order allow,deny
Deny from all

.htaccess side with .git

RedirectMatch 404 /\.git
<Files README.md>
    deny from all
</Files>

Global

works for all .git directories in your site, even if there are more than one,

also hides other Git files like .gitignore and .gitmodules

# do not allow .git version control files to be issued

<Directorymatch "^/.*/\.git+/">
  Order deny,allow
  Deny from all
</Directorymatch>
<Files ~ "^\.git">
    Order allow,deny
    Deny from all
</Files>
<Files ~ README.md>
    deny from all
</Files>

 


Cleanup - git gc

 

git gc

# Cleanup unnecessary files and optimize the local repository

# Housekeeping is required if there are too many loose objects or too many packs in the repository.

 - compressing file revisions

 - removing unreachable objects

# Some git commands may automatically run git gc

# Disable this behavior permanently

git config --global gc.auto 0

# optimize the repository at the expense of taking much more time

--aggressive

# Prune(修剪) loose objects older than date (default is 2 weeks ago)

--prune=N               # Unit: day

--prune=now

Note

When git gc runs concurrently with another process,

there is a risk of it deleting an object that the other process is using but hasn’t created a reference to.

This may just cause the other process to fail or may corrupt the repository

if the other process later adds a reference to the deleted object.

Usage

du -sh .git

92M     .git

git branch

v4
v5
...
v18

# 刪除不要的 local branch

# 不影響 .git 的 size

git branch -d v4

git branch -d v5

....

git gc

Counting objects: 32727, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (16935/16935), done.
Writing objects: 100% (32727/32727), done.
Total 32727 (delta 17426), reused 28421 (delta 14687)

du -sh .git

85M     .git

 


Tools

 

Windows GUI tool - Git SCM

 


Environment Variables

 

  • GIT_AUTHOR_NAME
  • GIT_AUTHOR_EMAIL

Test

# Linux

echo %GIT_AUTHOR_NAME%

# Win

echo $GIT_AUTHOR_NAME

 


To clear out the history of a git/github repository

 

# Local git

rm -rf .git
git init
git add .
git commit -m "Initial commit"

# github git

git checkout --orphan newBranch
git add -A                        # Add all files and commit them
git commit
git branch -D master              # Deletes the master branch
git branch -m master              # Rename the current branch to master
git push -f origin master         # Force push master branch to github
git gc --aggressive --prune=all   # remove the old files

 


github raw download file

 

https://github.com/myspace-nu/jquery.fancyTable/blob/master/dist/fancyTable.min.js

的 DL Link

https://github.com/myspace-nu/jquery.fancyTable/raw/master/dist/fancyTable.min.js

 


PAT (Personal Access Token)

 

Token Format

ghp_???

建立 Token

Settings > Developer settings > Personal access tokens (classic)

https://github.com/settings/tokens

 


Workflow

 

workflow file

.github/workflows/your_file_name.yml

secrets

    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: ap-east-1

pre-written workflow by Official GitHub Actions

https://github.com/actions/checkout

...
    steps:
    - name: Check out code
      uses: actions/checkout@v2

 


Doc