Git Routine
Useful git commands
Command cheatsheet
git clone --recurse-submodules -j8 git@github.com:example/target-repo.git
git status
git diff
git diff <filename>
git diff <filename> > foo.diff # output git diff to file foo.diff with coloring.
git add --all # Stage all files
git add <filename> # Stage a file, ready to commit
git reset # Unstage all files
git reset <filename> # Unstage one file
git reset HEAD <submodule-name> # Reset the submodule head
git restore <filename> # Discard changes of the file
git commit -m "Post update"
git push -u origin <your-branch>
# run once - change origin
git remote set-url origin git@github.com:Adobe-Firefly/colligo.git
# run once, optional: keep the old corp url as backup
git remote add legacy-corp git@git.corp.adobe.com:colligo/colligo.git
# Switch to a remote branch
git fetch origin
git branch -v -a
# with -c to create a new local branch
git switch -c halin-remove-gb-cuda origin/halin-remove-gb-cuda
Github compare url example:
https://github.com/<repo-dir>/compare/<branch-name>?expand=1
You have divergent branches (remote vs local) and need to specify how to reconcile them. You can do so by running one of the following commands sometime before hint: your next pull:
git config pull.rebase false # merge (the default strategy)
git config pull.rebase true # rebase
git config pull.ff only # fast-forward only
Pull with Submodule May need to manually clean up the local .git/modules records (‘rm -rf
git pull --recurse-submodules
git submodule foreach --recursive git pull
git submodule update --remote # will only update the branch registered in the .gitmodule
git submodule sync # sync to the remote
git submodule update --remote --init # first initialize the submodule recorded in .gitmodule
git submodule update --remote --rebase
Discard local changes and force to pull the remote branch:
# Really the ideal way to do this is to not use pull at all, but instead fetch and reset:
git fetch origin <master-branch>
# force the state of the working directory to a state matching that of a particular commit.
git reset --hard FETCH_HEAD
# removes files which are not tracked by git
# the -df flags tell it to remove directories (-d) and actually do the removal (-f)
git clean -df
Revert the current repo to a previous commit (this applies to submodule too): (Note: git pull
is nothing more than git fetch
followed by git merge
)
git fetch origin <branch>
git checkout <commit-id>
git checkout -b <your-branch> # new local branch
git branch -d <your-branch> # delete the branch
Git Tools - Interactive staging
We can stage patches under interactive staging mode.
git add -i # Interactive Staging
git add -p # or --patch to start partial staging
git reset -p
Example to pick commit A from first branch to the second branch. Before:
# Example:
# [A]---B---C first branch
# /
# D---E---F---G second branch
After:
# Example:
# [A]---B---C first branch
# /
# D---E---F---G---[A] second branch
git checkout <branch-of-cherry>
# Get git reference log, keeping track of recent actions made
git reflog
# Copy the log and copy the commit hash to pick
git checkout <working-branch>
# Use -x flag when you want to append a line that remarks the original commit it was cherry-picked from.
# Use -n to just stage the picked change without commit
git cherry-pick [-x] [-n] <commit hash>
# To unstage the staged changes
git reset
Git Tools - Merge Caution: before merging, make sure there is no non-trivial uncommitted changes.
# Example:
# A---B---C topic
# /
# D---E---F---G master
git checkout master
git merge topic
# Result:
# A---B---C topic
# / \
# D---E---F---G---H master
Better practice:
git merge --no-commit [-s ort] topic
# --no-commit: permform merge but stop before creating a merge commit.
# -s: merge strategy option. By default, its `ort`.
git commit -m "msg"
# -m: message about the merge
What should we do if we run into conflicts:
-
Abort the merge to start over again?
# Abort the merge process and *try* to reconstruct the pre-merge state: git merge --abort
-
Resolve the conflicts with tools
Use your favorate editor to resolve the changes.
HEAD
: current branch headMERGED_HEAD
: other branch head# Option 1: use graphical mergetool git mergetool # Option 2: highlight diff git diff git log --merge -p <path> # show diffs first for the HEAD version and then MERGED_HEAD version git show :1:<filename> # show the common ancestor git show :2:<filename> # show the HEAD version of the file git show :3:<filename> # show the MERGED_HEAD version
Better undoing mistakes before commit:
git stash
git checkout -- <filename> # Discard file changes permanently
git checkout <branch-name> -- <filename> # Checkout file from other branch
git reset --hard # Discard all changes permanently
Undo git add
files:
Concepts:
- Working directory: where you make changes to your code;
- Staging area: intermedia step where you prepare changes for commit.
# option 1:
git reset <file> # remove a single file from staging area, i.e. undo git add
git reset # remove all files from staging area, changes are still in working directory
# option 2:
git rm --cached <file> # remove a single file from the staging area
# Caution:
git rm <file> # remove the changes from both working directory and staging area.
Undo Committed changes:
git reflog # To check the commit id.
git reset --hard <commit-id> # Discard all changes permanently
git rm -rf --cached . # remove the cache
git reset --hard HEAD # reset to the latest commit of the current branch
Undoing changes in a shared repo:
git revert [--no-commit] <commit-id> # A new commit that reverts the changes of commit-id.
git clone --recurse-submodules -j8 target_git@github.com
If we cloned the repo without recursively pull submodules, try the following:
cd <repo-dir>
git submodule update --init --recursive
To individually update a specific submodule:
cd <submodule-dir>
git pull --recurse-submodules
Submodule can be added to your current repo by:
cd <repo-dir>
git submodule add <git_url_to_the_submodule> <submodule_folder_name>
Git Tools - commit information
variations:
git show [--outline -s]
git reflog
git log -1 [--outline] # show the last commit info
git log --full-history -- file_name # show all logs related to a file
git status
Launch gitk graphic display:
git bisect visualize
git bisect view # shorter, means same thing
git stash save "changes on the current-branch"
git stash pop # unstash the changes of the top stash
git stash list # list the stash stack
git stash pop "stash@{1}" # unstash a specific stash
git stash apply # apply the top stash
git stash drop # drop the top stash
git stash show # Show the files in the most recent stash
git stash show -p # show the changes in the most recent stash
git stash show -p stash@{1} # show the changes of the specified stash
git stash show -p 1 # simplified version of the above comment
# You have divergent branches and need to specify how to reconcile them.
# You can do so by running one of the following commands sometime before
# your next pull:
git config pull.rebase false # merge (the default strategy)
git config pull.rebase true # rebase
git config pull.ff only # fast-forward only
# You can replace "git config" with "git config --global" to set a default
# preference for all repositories. You can also pass --rebase, --no-rebase,
# or --ff-only on the command line to override the configured default per
# invocation.
Git Tools - working tree TODO…
Prune git option Pruning only deletes the references in refs/remotes/ that do not point to an active branch on the remote. It works like this so that you do not delete your local changes.
# recommended command
git fetch --prune
# To set the global config on fetch: perform prune when fetch
git config --global fetch.prune true
However, if you want to delete merged branches automatically, here are some commands you can use.
git checkout master # or "main" if that's what you use
# List all the branches that has been merged:
git branch --merged
# Skip certain branches
git branch --merged | egrep -v "master|dev|main|staging|[any-other-branch-you-want-to-skip]"
# Auto deletion:
git branch --merged | egrep -v "master|dev|main|staging" | xargs git branch -d
Global settings for line endings:
git config --global core.autocrlf input
# Configure Git to ensure line endings in files you checkout are correct for Linux
git config --get core.autocrlf # Check the value
Per-repository settings:
You can configure a .gitattributes
file to manage how Git reads line endings in a specific repository. The .gitattributes
file must be created in the root of the repository and committed like any other file.
An example of the .gitattributes
file content:
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto
# Explicitly declare text files you want to always be normalized and converted
# to native line endings on checkout.
*.c text
*.h text
# Declare files that will always have CRLF line endings on checkout.
*.sln text eol=crlf
# Denote all files that are truly binary and should not be modified.
*.png binary
*.jpg binary
Reference: Customizing your git configuration
Enjoy Reading This Article?
Here are some more articles you might like to read next: