NOT a Git manual
WARNING: This page has not been reviewed and may contains typos or conceptual mistakes.
This article supposes that readers understand basic Git operations including git init/clone/status/add/rm/stash/log
. git reset
is not mandatory but preferred.
If you have no idea about these commands, read 菜鸟教程 or any other manual before proceeding to the next part.
From ... ?
A repository can be created by git init
or git clone <git-url>
.
For example, if a local Git repository is created through cloning from GitHub, then git remote --verbose
will display something like:
(HTTPS)
➜ git remote -v
origin https://<url>/<owner>/<repo> (fetch)
origin https://<url>/<owner>/<repo> (push)
(SSH)
➜ git remote -v
origin git@<url>:<owner>/<repo>.git (fetch)
origin git@<url>:<owner>/<repo>.git (push)
(SSH, fork repository)
➜ git remote -v
origin git@<url>:<fork-owner>/<repo>.git (fetch)
origin git@<url>:<fork-owner>/<repo>.git (push)
upstream git@<url>:<owner>/<repo>.git (fetch)
upstream git@<url>:<owner>/<repo>.git (push)
But how can we manually configure remote repos?
Suppose that we have a repo with a remote repo origin
and a local branch master
.
git push -u origin master
This command will push the local branch master
to the remote branch origin/master
, and record upstream tracking master -> origin/master
(This can be checked through git status
).
Below is a workflow example. (Copied from nixpkgs/CONTRIBUTING.md)
# Add a tracked remote repo as `upstream`
git remote add upstream <git-url>
# Make sure you have the latest changes from `upstream`
# Append `--depth 1` if you only want the latest commit from upstream
git fetch upstream
# Create and switch to a new branch `update-hello` based off the master branch from `upstream`
# Same as `git checkout --branch/-b`
git switch --create update-hello upstream/master
# Or based off from a specific commit
git switch --create update-hello <the desired base commit>
Then you can start adding your changes on this branch and saved by git commit
.
# If `EDITOR` environment variable is set, this will trigger the corresponding editor executable and display current change status.
# Then you should edit commit message in editor.
# append `--message/-m "<commit message>" to commit changes directly without opening the editor
git commit
Merge branches / Resolve merge conflicts / Pull Request
TODO
Rewriting History
git stash
is very simple, RTFM plz.
So is rewriting HEAD.
# Rewrite current commit (supposed you are not in HEAD detached mode).
# append `--no-edit` if you do not want to edit commit message.
git commit --amend
If you want to rewrite multiple commits or commits far from HEAD, you can use interactive rebase. This is a powerful tool that allows you to modify multiple commits in your history. Here are the specific steps:
# Rebase interactively onto a commit in the history
# This should be the parent commit of the earliest commit you would like to edit.
# Use <TAB> button to utilize shell completion (if exists).
git rebase --interactive <commit>
For example, if you want to modify the last three commits, you need to specify the fourth most recent commit:
git rebase -i HEAD~4
This will open an editor displaying something like this:
pick f7f3f6d Change configuration file
pick 310154e Update user interface
pick a5f4a0d Fix bug
pick 368fab6 Add new feature
# Rebase 710f0f8..a5f4a0d onto 710f0f8
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
To modify commit messages, change "pick" to "edit" (or "e" for short) for the commits you want to modify. For example:
e f7f3f6d Change configuration file
e 310154e Update user interface
e a5f4a0d Fix bug
pick 368fab6 Add new feature
Then Git will rebase onto the first commit to be modified.
Once complete, run git rebase --continue
and Git will apply all changes, rewriting history and rebase onto the next commit to be modified.
You can skip changes by git rebase --skip
or quit rebase mode by git rebase --abort
.
Note: This process changes the SHA-1 values of commits, so use it with caution, especially on commits that have already been pushed to a shared repository. If you need to perform this operation on pushed commits, make sure to communicate with your team and use git push --force-with-lease
to push the changes.
See: Is git push --force-with-lease always safe?
More
Check out the official Pro Git book for advanced Git usage.