【Git】常用命令

Posted by 西维蜀黍 on 2020-11-12, Last Modified on 2022-04-10

Branch

Create a New Branch

git checkout

# create a new branch checkouted from current commit, and switch to the new branch
$ git checkout -b <new_branch_name>

# create a new branch checkouted based on a specific reference (branch, remote/branch, tag are examples of valid references)
$ git checkout -b <new_branch_name> <reference>
# e.g.,
$ git checkout -b feature-branch master

git branch

# Create new branch based on the current commit (but doesn't switch to the new branch created)
$ git branch <branch_name>

# Create new branch based on a specific commit
$ git branch <branch_name> <commit_hash>

Switch an Existing Branch

git checkout

# Checkout to a specific existing local branch
$ git checkout <branch_name>

# Switch to the previously checked out branch
$ git checkout -

# Switch to an existing remote branch
$ git checkout --track <remote_name/branch_name>

List Branches

git branch

# List local branches. The current branch is highlighted by *
$ git branch

# List all branches (local and remote):
$ git branch -a

# List all remote branches
$ git branch -r
$ git branch -r | grep <...>

# 查看本地分支及追踪的分支
$ git branch -vv

Delete a Branch

  • -D: Shortcut for --delete --force.
# Delete a local branch. The branch must be fully merged in its upstream branch
$ git branch -d <branch_name>

# Forcefully delete a local branch
$ git branch -D <branch_name>

# Delete a remote branch
$ git push <remote_name> --delete <remote_branch_name>
# e.g.,
$ git push origin --delete <remote_branch_name>

Rename a Branch

# Rename a local branch
$ git branch -m [old branch name] [new branch name]

Manage Remote Repository

# Add a remote repository
$ git remote add origin ssh://git@github.com/[username]/[repository-name].git

Merge a Branch

git merge

# [most useful] - Merge a branch into current branch and create a merge commit
$ git merge --no-ff <branch_name>

# Merge a branch into your current branch
$ git merge <branch_name>

# Edit the merge message
$ git merge -e <branch_name>

# Merge a branch into a target branch
$ git merge <source branch> <target branch>

# Abort a merge in case of conflicts
$ git merge --abort

git rebase

# Rebase the current branch on top of another specified branch:
$ git rebase new_base_branch

# Abort a rebase in progress (e.g. if it is interrupted by a merge conflict):
$ git rebase --abort

merge vs rebase

merge

# If do merge
$ git log
commit 4f00d87afb943e7f6dcd996cdecd5400a7455d8e (HEAD -> feature2)
Merge: deb6375 d63e8ae
Author: Shi Wei <wei.shi@xx.com>
Date:   Fri Jun 25 23:04:40 2021 +0800

    Merge branch 'master' into feature2

commit d63e8ae391d5f0be3f93752779e6f0e9a93be140 (origin/master, origin/HEAD, master)
Author: Shi Wei <wei.shi@xx.com>
Date:   Fri Jun 25 23:03:53 2021 +0800

    add master 2

commit deb6375401ce5ed08a6e7c4e492ef800fc98f497 (origin/feature2)
Author: Shi Wei <wei.shi@xx.com>
Date:   Fri Jun 25 23:03:17 2021 +0800

    add 1 feature2

commit 66bac5735e15ab56ab305e5f49daa68850024740
Author: Shi Wei <wei.shi@xx.com>
Date:   Fri Jun 25 23:02:21 2021 +0800

    add master -1

commit e9994724f709b903c4ccce2f5252ddb4ed561d91
Author: Shi Wei <wei.shi@xx.com>
Date:   Fri Jun 25 22:53:54 2021 +0800

    add 4
    
    
# If do rebase
$ git log
commit bc7bfd015b81df9023df8f3b18aad89ff7ca1cd9 (HEAD -> feature2)
Author: Shi Wei <wei.shi@xx.com>
Date:   Fri Jun 25 23:03:17 2021 +0800

    add 1 feature2

commit d63e8ae391d5f0be3f93752779e6f0e9a93be140 (origin/master, origin/HEAD, master)
Author: Shi Wei <wei.shi@xx.com>
Date:   Fri Jun 25 23:03:53 2021 +0800

    add master 2

commit 66bac5735e15ab56ab305e5f49daa68850024740
Author: Shi Wei <wei.shi@xx.com>
Date:   Fri Jun 25 23:02:21 2021 +0800

    add master -1

commit e9994724f709b903c4ccce2f5252ddb4ed561d91
Author: Shi Wei <wei.shi@xx.com>
Date:   Fri Jun 25 22:53:54 2021 +0800

    add 4

View Code Changes

git diff - Compare Branches

Diffing is a function that takes two input data sets and outputs the changes between them. git diff is a multi-use Git command that when executed runs a diff function on Git data sources. These data sources can be commits, branches, files and more. This document will discuss common invocations of git diff and diffing work flow patterns. The git diff command is often used along with git status and git log to analyze the current state of a Git repo.

# Preview changes before merging
$ git diff [source branch] [target branch]

Comparing files from two branches

To compare a specific file across branches, pass in the path of the file as the third argument to git diff

git diff main new_branch ./diff_test.txt

Commits

Fetch/Push/Pull Commits

git fetch

# Fetch the latest changes from the default remote upstream repository (if set)
$ git fetch

# Fetch new branches from a specific remote upstream repository
$ git fetch <remote_name>

# Fetch the latest changes from all remote upstream repositories
$ git fetch --all

# Also fetch tags from the remote upstream repository
$ git fetch --tags

git push

# Send local changes in the current branch to its remote counterpart
$ git push

# Publish tags that aren't yet in the remote repository
$ git push --tags

git pull

git pull runs git fetch with the given parameters and calls git merge to merge the retrieved branch heads into the current branch. With --rebase, it runs git rebase instead of git merge.

# Download changes from default remote repository and merge it:
$ git pull

# Download changes from default remote repository and use fast forward:
$ git pull --rebase

# Download changes from given remote repository and branch, then merge them into HEAD:
# e.g., `git pull origin master` and then need to checkout to master branch by `git checkout master`
$ git pull <remote_name> <branch>

View Commits

git show - 显示一个commit的changes

git-show is a command line utility that is used to view expanded details on Git objects such as blobs, trees, tags, and commits. git-show has specific behavior per object type.

  • Tags show the tag message and other objects included in the tag.
  • Trees show the names and content of objects in a tree.
  • Blobs show the direct content of the blob.
  • Commits show a commit log message and a diff output of the changes in the commit.
$ git show <commit_SHA>

# e.g.,
$ git show d63e8ae391d5f0be3f93752779e6f0e9a93be140
commit d63e8ae391d5f0be3f93752779e6f0e9a93be140 (origin/master, origin/HEAD, master)
Author: Shi Wei <wei.shi@aa.com>
Date:   Fri Jun 25 23:03:53 2021 +0800

    add master 2

diff --git a/spss_profile.sh b/spss_profile.sh
index f18e41a..8d06e08 100755
--- a/spss_profile.sh
+++ b/spss_profile.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 1 - master
-2
+2 - master
 3
 4
 # Usage

git log

Refer to https://swsmile.info/post/git-log/

git blame <file_path> - 查看每一行的最后修改时间

Refer to https://git-scm.com/docs/git-blame

# -L
# The -L option will restrict the output to the requested line range. Here we have restricted the output to lines 1 through 5.
git blame -L 1,5 README.md

Save Commits

git commit

# Commit staged files to the repository with a message
$ git commit -m <message>

# Auto stage all modified files and commit with a message
$ git commit -a -m <message>

# Replace the last commit with currently staged changes:
$ git commit --amend

# Commit only specific (already staged) files:
$ git commit <path/to/my/file1> <path/to/my/file2>

Revert a Commit

git revert

Revert a Commit with Committing

I commit a commit

$ git revert f5dec261b1183c8e39d7db34844df424e8cd8971
[master e6ca3ae] Revert "add a commit"
 1 file changed, 1 insertion(+), 1 deletion(-)

Revert a commit without Committing

$ git revert -n <commit's SHA-1>

Revert the most recent commit

$ git revert @

Switch to a Commit

$ git checkout <commit-B-SHA>

# If you want to create a new branch to retain commits you create, you may do so (now or later) by using -c with the switch command.
$ git switch -c <new-branch-name>
  
# Or undo this operation with
$ git switch -

Reset a Branch

git reset

Reset the Branch to a Commit

# Reset the repository to a given commit, with discarding committed, staged and uncommitted changes since this given commit
$ git reset --hard <commit SHA>

Apply a Commit to Current Branch

git cherry-pick

# Apply a commit to the current branch
$ git cherry-pick commit

Whether Contains a Commit in a Branch or not

$ Get a list of branch(es) that contains the specific commit

# To list local branches containing commit:
$ git branch --contains <commit-id>

# List all branches, including remote only, containing commit:
$ git branch -a --contains <commit-id>

Whether current branch contains a specified commit or not

$ if [ 0 -eq $(git merge-base --is-ancestor $COMMIT_ID HEAD) ]; then echo "true"; else echo "false"; fi

# or
$ git log | grep <commit_id>

Ref

Merge/Squash Commits

When we say “squash” in Git, it means to combine multiple continuous commits into one. An example can explain it quickly:

          ┌───┐      ┌───┐     ┌───┐      ┌───┐
    ...   │ A │◄─────┤ B │◄────┤ C │◄─────┤ D │
          └───┘      └───┘     └───┘      └───┘

 After Squashing commits B, C, and D:

          ┌───┐      ┌───┐
    ...   │ A │◄─────┤ E │
          └───┘      └───┘

          ( The commit E includes the changes in B, C, and D.)

In this example, we’ve squashed the commits B, C, and D into E.

Squash The Last N Commits

If you want to write the new commit message from scratch, this suffices:

git reset --soft HEAD~3 &&
git commit

Ref

Squash from A spcified Commit

# If
pick d94e78 Prepare the workbench for feature Z     --- older commit
pick 4e9baa Cool implementation 
pick afb581 Fix this and that  
pick 643d0e Code cleanup
pick 87871a I'm ready! 
pick 0c3317 Whoops, not yet... 
pick 871adf OK, feature Z is fully implemented      --- newer commit

$ git rebase --interactive [commit-hash]
pick d94e78 Prepare the workbench for feature Z     --- older commit
s 4e9baa Cool implementation 
s afb581 Fix this and that  
s 643d0e Code cleanup
s 87871a I'm ready! 
s 0c3317 Whoops, not yet... 
s 871adf OK, feature Z is fully implemented      --- newer commit

Ref

Changes

Staging Changes

git status - Check Stage Status

# Show changed files which are not yet added for commit, but which are tracked already:
$ git status

git add - Stage Untracked/Tracked/Ignored Files

Stage Tracked Files

# Add a file to the index
$ git add <path/to/file>

# Only add already tracked files:
$ git add -u

Stage Untracked Files

# Add a file to the index
$ git add <path/to/file>

Demo

$ touch pool.go
$ vim pool.go
$ git status
On branch release
Your branch is up to date with 'origin/release'.

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	pool.go

nothing added to commit but untracked files present (use "git add" to track)

$ git add .
$ git status
On branch release
Your branch is up to date with 'origin/release'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   container/tester.go
	new file:   pool.go

Stage Untracked and Tracked Files

# Add all files (tracked and untracked)
$ git add -A

Stage Untracked, Tracked and Ignored Files

# Also add ignored files
$ git add -f

Discard/Unstage Changes

Unstage Staged Files

Unstage staged files to unstaged mode (but still keep them)

# Unstage all staged files (to unstaged mode, but still keep them)
$ git restore --staged :/

# Unstage everything but keep the changes
$ git reset

Discard Unstage or Staged Files

Discard unstaged files

  • git restore
# Discard unstaged files
$ git restore path/to/file

# Discard all unstaged changes to tracked files (in the current directory)
$ git restore .
# Discard all unstaged changes to tracked files (in the working tree)
$ git restore :/

# Restore an unstaged file to the version of a specific commit
$ git restore --source commit <path/to/file>
  • git checkout
# Discard all unstaged changes in the current directory
$ git checkout .

# Discard unstaged changes to a given file
$ git checkout <filename>

Discard staged files

# Discard staged files
$ git restore --staged <file>...

Discard Unstage and Staged Files

# Discard all changes to files, both staged and unstaged
$ git restore --worktree --staged :/

# discard everything
$ git reset --hard

Ref https://git-scm.com/docs/git-restore

git clean - Discard Untracked Changes

Unstaged changes in tracked files will not be affected here, since they are trakced already.

  • -f, --force: forcefully
  • -i, --interactive: interactive mode
  • -n, --dry-run: dry run
  • -d: recursively discard changes
  • -x: Don’t use the standard ignore rules, but still use the ignore rules given with -e options from the command line.
  • -X: Remove only files ignored by Git

Normally -d should be attached.

Dry-run

# Dry-run to see what untracked files will be deleted (will not display the unstaged changes in tracked files)
$ git clean -n -d
Would remove pool.go

Recursively discard changes

# After you are sure
$ git clean -f -d
Removing pool.go

Interactive mode

# Interactively delete files that are not tracked by git:
$ git clean -id

Forcefully

# Forcefully and recusively delete directories/files that are not tracked by git:
$ git clean -fd

Remove only files ignored by Git

$ git status
On branch release
Your branch is up to date with 'origin/release'.

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	pool.go

nothing added to commit but untracked files present (use "git add" to track)
# Dry-runly remove both files ignored by Git and files untracked
$ git clean -dn -x
Would remove .idea/
Would remove log/
Would remove pool.go
# Dry-runly remove only files ignored by Git
$ git clean -dn -X
Would remove .idea/
Would remove log/

管理暂存 Changes

git stash

# Stash current changes
$ git stash

# Stash current changes, including new (untracked) files
$ git stash -u

# Apply a stash (default is the latest, named stash@{0})
$ git stash apply [<optional_stash_name_or_commit>]

# lists all stashed changesets
$ git stash list 

Demo

如果我完成了一个code change,这时我发现当前的这个branch 对应 track的 remote branch被更新了,这时候我要做的是

  1. 暂存 Not Staged Changes
  2. git pull
  3. 把刚才暂存的 Not Staged Changes 放回来
# do some code change
$ git stash
$ git pull
$ git stash apply

Replace Files By a Remote Version

Replace a file’s content with a specific version (specified by a given branch)

# Replace a file in the current directory with the version of it committed in a given branch
$ git checkout <branch_name> -- <filename>

Reference