# Git / GitHub usage cheatsheet
## Shallow Clone
### method 1
Carefully clone what you need (without cloning large amount of old history data).
In GIT, you can determine number of commits to download from remote repo.
```
cd NEW_FOLDER
git init
```
* Use [remote](https://git-scm.com/docs/git-remote) to specify which branch of remote repository your local codebase should synchronize with
```
git remote add -t <EXISTING_REMOTE_BRANCH> <ALIAS_NAME> <GIT_REPO_URL>
```
where
- `<EXISTING_REMOTE_BRANCH>` : branch name created at remote repo
- `<ALIAS_NAME>` : alias name of the remote git repo, referenced at local git repo
e.g.
```
git remote add -t my_remote_master local_origin_123 https://my.github.codebases/project123
```
To fetch codebase at specific commit without loading all older commits in the same branch.
* Note this command will generate [detached branch](https://stackoverflow.com/questions/10228760/how-do-i-fix-a-git-detached-head)
* If you also want to switch between different tags, ensure you have enough commits in the `git fetch` command (that means, `--depth` should be large enough so you can switch to specific commit / tag later in `git checkout` command)
```
git fetch --depth <NUM_COMMITS> <ALIAS_NAME> <COMMIT_SHA1>
git fetch --depth <NUM_COMMITS> <ALIAS_NAME> tag <EXISTING_TAG_LABEL>
```
where
- `<NUM_COMMITS>` indicates number of consecutive commits to fetch, starting from the commit represented as `<COMMIT_SHA1>`, going back to the nth. old commit
- `<ALIAS_NAME>`: name of the remote git repo, previously created on `git remote add`
- `<EXISTING_TAG_LABEL>` indicates existing specific tag label in remote git repository.
### method 2
clone number of commits from main branch of a git repository
```bash
git clone --depth <NUM-COMMITS-FROM-HEAD>
```
## Branch
### List existing branches of current repo
```
git branch
```
### Create a new local branch under current local repo
```
git branch <LOCAL_LABEL>
```
Note:
- local branches may be different from remote branches in the same repo
- For [Shallow Clone](#shallow-clone) where a default [detached branch](https://stackoverflow.com/questions/10228760/how-do-i-fix-a-git-detached-head) is created, it is a good practice to create other local branches (e.g. one for backup, others for new patches) before you move on and change the codebase.
- Once you switch from detached branch to any other branch (by `git checkout <EXISTING_LOCAL_BRANCH>`), the detached branch will disappear, it is better NOT to change the code under detached branch.
### check commit history under specific branch
```bash
git log <EXISTING_LOCAL_BRANCH>
```
### Switch between commits
Consider `commit` as single node of an arbitrary tree structure, you can switch between them back and forth using [git-checkout](https://git-scm.com/docs/git-checkout).
```
git checkout <COMMIT_LABEL>
```
where the `<COMMIT_LABEL>` could be one of followings:
|syntax|meaning|
|------|-------|
|`FETCH_HEAD`|to the latest commit of current branch|
|`<SHA1_HEX_STRING>`|SHA1 string, represent the specific commit|
|`<TAG_NAME>`|to specific tag|
|`<EXISTING_LOCAL_BRANCH>`|to specific local branch|
## Push
Update change to remote repo with the command [git-push](https://git-scm.com/docs/git-push)
Preresuisites :
- switch to the appropriate [local branch](#branch) you want to update (source)
- specify appropriate remote branch (destination)
```bash
git checkout <EXISTING_LOCAL_BRANCH>
git push -u <ALIAS_NAME> HEAD:<EXISTING_REMOTE_BRANCH>
```
where
- `<EXISTING_REMOTE_BRANCH>` : branch name created at remote repo
- `<ALIAS_NAME>`: name of the remote git repo, previously created on `git remote add`
## Cherry pick
copy one commit from source branch to destination branch within a git repository.
- possible use case
- resolve conflict between branches , by applying a specific commit from one Git branch to current `HEAD` of another branch.
- one has to ensure the commit to cherry-pick is small enough so it can be reused across branches in the repository.
```bash
git cherry-pick <SHA-HASH-OF-COMMIT>
```
Note:
- `<SHA-HASH-OF-COMMIT>` indicates SHA2 hash valud of the commit to pick.
- switch to destination branch before the cherry-pick operation, so commit can be copied to right location.
## Merge
### Rebase
```shell!
git rebase <upstream> [<target>]
```
Move base of a target branch `<target>` forked from another branch `<upstream>` in a git repository.
- `base` in this context means the common latest commit existing in both sides of the branches.
- this command requires the branch `<target>` is clean without uncommitted change , otherwise it reports error below :
```
error: cannot rebase: You have unstaged changes.
error: Please commit or stash them.
```
- one workground is to temporarily save unstaged changes to git's internal stack by `git stash`
After the commnad, the commits existing ONLY in branch `<target>` will be moved to `HEAD` of branch `<upstream>`.
**Rebase example** : assume the branch `<target>` was forked on commit `B` , and both branches advanced with a few new commits.
```markdown
A---B---C <upstream>
/
D---E---F---G <target>
```
After rebase, the commit chain `D,E,F,G` is moved to commit `C` , which is current `HEAD` of `<upstream>`
```markdown
A---B---C <upstream>
/
D---E---F---G <target>
```
Reference : `git rebase --help`
#### Resolve conflict during rebase
**TODO**
### Squash
**TODO**
## Misc
### show detail of specific commit
```bash!
git show <specific-commit> --pretty=format:""
```
- `<specific-commit>` could be hash of the commit or specific label such as `HEAD`
- `--pretty=format:""` prints file content changed excluding summary message.
### submodule
Link a sub git repository to specific path of another (main) git repository, [git submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules)
```bash
git submodule add https://URL.to.sub.repo /main-repo/path/to/dst
```
after this command, you can directly commit it, a file named `.gitmodules` will be automatically added to the main repository
### Tag
List all tags which can be switched to in the local repository (depends on `--depth` in your previous `git fetch`)
```
git tag
```
### pull partial commit history
* Alternative #1 , `--depth` works the same way, `HEAD` indicates that the git starts from the latest commit and download specific number of commits (in this case it is `3`):
```
git pull --depth 3 <REMOTE_NAME> HEAD
```
* Alternative #2 , load all histories. It is not good for large-scale repositories (e.g. with millions of commits), because it may load unecessary old commits you've never used :
```
git clone --depth 1 <GIT_REPO_URL> --branch <BRANCH_NAME>
```
### Remove local commit
To remove local commit without discarding the change :
* latest commit only
```
git reset HEAD^
```
### Stash
Temporarily save uncommitted / unstaged / dirty changes to git's internal stack , the purpose is to keep working directory clean and match `HEAD` commit of current branch, this is required for certain git commands.
```bash!
# save local dirty change temporarily
git stash --message="Work-In-Progress : before rebase"
# perform other git commands , such as rebase
# restore back at later time
git stash pop
```
## TODO
- [recover back to previous local commit status using `git reflog` and `git reset --soft`](https://chatgpt.com/share/681f074d-aa00-8003-93f8-ccbcea73b2e6)
###### tags: `Dev-tool` `Git`