Git is a distributed revision control system with an emphasis on speed, data integrity, and support for distributed, non-linear workflows. Git was initially designed and developed by Linus Torvalds for Linux kernel development in 2005, and has since become the most widely adopted version control system for software development.

Know more, do better

If we use git more, and get more familiar with it, it really helps a lot. Let’s note some best practices down here.

Set useful git alias

Check this post to set useful git alias, making your life easier and happier when using git.

About a remote host (CRUD)

List all your remote hosts. -v shows the url for remote host.

$ git remote [-v]

Show the detailed information for remote host(such as origin). Add, Remove and Rename a host.

$ git remote show <host>                  # [R]
$ git remote add <host> <url>             # [C]
$ git remote rm <host>                    # [D]
$ git remote rename <host> <new-host>     # [U]

Fetch from remote host

Once there’re commits from remote host, we can fetch them in all branches from remote host.

$ git fetch <host>

We can also fetch a specific branch from remote host. With git branch you can get all the local branches, and with git branch -r you can get all the remote branches.

$ git fetch <host> <branch>

We can also fetch some branch which has no corresponding local branch created. We do this to create a local branch based this remote branch.

$ git checkout -b <local-branch> origin/<remote-local>

Also, if you don’t want to merge a remote branch without creating a local branch for it, do this:

$ git merge origin/master
# Or
$ git rebase origin/master

This two commands do the same to merge a remote branch(origin/master) into current branch.

Pull from remote host

The default git pull command pulls all the remote branches corresponding to local ones. The full command can pull a remote branch and merge it to a local branch.

$ git pull [--rebase] <host> <remote-branch>:<local-branch>

This command pulls <remote-branch> from <host>, and merges it to <local-branch>. With --rebase option, we can rebase the local commits to top of this branch.

Push to remote host

We should know that there’re 2 push mode: simple & matching. Before git 2.0, we use ‘matching’ as default which pushes all the matching local branches to remote. Now we use ‘simple’ as default to push only current branch to remote. But we can config it:

$ git config --global push.default matching
# Or
$ git config --global push.default simple

The full comand pushes a local branch to remote branch of a remote host.

$ git push <host> <local-branch>:<remote-branch>

If we don’t specify the <local-branch>, we just push an empty branch to remote, just like removing remote branch commits, which means git push <host> :<remote-branch> equals to git push <host> --delete <remote-branch>.

If we don’t specify the <remote-branch>, we will push <local-branch> to the matching branch of it.

If we don’t specify any branch, we will push all the branches to the matching branches of them on <host>. Just like this command without –all.

$ git push [--all] <host>

If we use --all, we could push all the branches. If some of them don’t have the matching branches on <host> will create them.

If we want to force push the local changes, usually when we update some commits already pushed, check this best practice.

Do with your submodules

Process all your submodules with this command:

git submodule [...]

You can do init/deinit, add, status, update, etc.

If you want to run git commands within each submodule, do this:

git submodule foreach [git command]

Best practices!!

Who has touched the file?

If the file is a code file, we can use git blame to check the file change.

If the file is a binary file, or we just want to find all the commits related to this file, use this command:

$ git log [-p] file

And, if this file is renamed or even deleted, we should use --follow on git log to continue listing the history of a file beyond renames:

$ git log [-p] --follow -- file

-- is used to separate paths from revisions, like this:

git <command> [<revision>...] -- [<file>...]

Rebase to an old commit

Rebase to an old commit:

$ git rebase -i HEAD~n

Edit the pick before any commit your want to base to reword or r.

If you want to continue to HEAD, use this command:

$ git rebase --continue

Amend commits locally

If this commit is HEAD commit, use this to amend it:

$ git commit --amend

Then amend your commit message!

If this commit is not HEAD, rebase it and amend.

Reset commits locally

$ git reset HEAD~n [--hard]

With the --hard option, you can reset all the commit with all its changes. Or you can save all your changes.

Move one older commit to HEAD

This is maybe a little tricky. We have to use a test branch to backup the git stack, then rebase to remove the very change:

$ git branch test
$ git rebase --onto HEAD~n HEAD~(n-1) HEAD

This way comes from the git help man page.

A range of commits could also be removed with rebase. If we have the following situation:

E—F—G—H—I—J topicA

then the command

$ git rebase –onto topicA~5 topicA~3 topicA

> would result in the removal of commits F and G:
>
> E'---H'---I'---J'  topicA

After you stash this commit, you can cherry-pick it from the test branch to master branch:

````bash
$ git cherry-pick XXXXXX

$ git branch -D test

Get the XXXXXX with git log in test branch.

Check in(push) an old commit

Use rebase to go to this very old commit, use git push, you’ll get this message:

fatal: You are not currently on a branch.
To push the history leading to the current (detached HEAD)
state now, use

    git push origin HEAD:<name-of-remote-branch>

So you can do this very command to push commits before this base. After that, you go back to continue.

Force push to update remote origin(CRITICAL!)

This may not be a good practice. But in some critical circumstances, this may be the savior.

Amend the commits you’ve all ready pushed, and force to push them to replace the repo.

$ git push -f