Git proficiency has become a basic skill for programmers, although there are great client-side tools like Sourcetree that make merging code very easy. However, job interviews and some situations where you need to show your strength still require you to master enough Git commands.

Below sort out the classic operation scenarios of daily use git code, basically covering the requirements in the work.

What did I just submit?

If you commit a change with git commit -a and you are not sure what you committed. You can display the most recent commit on the current HEAD with the following command:

(main)$ git show
Copy the code

or

$ git log -n1 -p
Copy the code

My commit message was written wrong

If the commit message is incorrectly written and the commit has not been pushed, you can modify the commit message by using the following method:

$ git commit --amend --only
Copy the code

This opens your default editor, where you can edit information. On the other hand, you can do it all at once with one command:

$ git commit --amend --only -m 'xxxxxxx'
Copy the code

If the commit has already been pushed, you can modify the commit and then force push, but this is not recommended.

The username and email in my commit are not correct

If this is just a single commit, change it:

$ git commit --amend --author "New Authorname <[email protected]>"
Copy the code

If you need to modify all history, refer to the ‘Git filter-Branch’ guide page.

I want to remove a file from a commit

Remove a file from a commit using the following method:

$ git checkout HEAD^ myfile
$ git add -A
$ git commit --amend
Copy the code

This can be very useful when you have an open patch and you commit an unnecessary file to it and you need to force push to update the remote patch.

I want to delete my last commit.

If you need to delete pushed commits, you can use the following methods. However, this will irreversibly change your history and pull apart the history of everyone who’s already pulled from the warehouse. In short, don’t do it if you’re not sure.

$ git reset HEAD^ --hard
$ git push -f [remote] [branch]
Copy the code

If you haven’t pushed it to remote, you can reset Git to the state you were in before your last commit (while saving the temporary changes):

(my-branch*)$ git reset --soft HEAD@{1}
Copy the code

This only works if there is no push. If you’ve already pushed, the only safe thing to do is git Revert SHAofBadCommit, which creates a new commit to undo all the changes made to the previous commit; Or, if the branch you’re pushing is rebase-safe (for example, other developers won’t pull from it), just use Git push-f.

Delete any commit (commit)

Same warning: Don’t do this unless you have to.

$ git rebase --onto SHA1_OF_BAD_COMMIT^ SHA1_OF_BAD_COMMIT
$ git push -f [remote] [branch]
Copy the code

Or do an interactive rebase to delete rows in the commit that you want to delete.

I tried to push a amended commit to the remote but I got an error:

To https://github.com/yourusername/repo.git ! [rejected] mybranch -> mybranch (non-fast-forward) error: failed to push some refs to 'https://github.com/tanay1337/webmaker.org.git' hint: Updates were rejected because the tip of your current branch is behind hint: its remote counterpart. Integrate the remote changes (e.g. hint: 'git pull ... ') before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details.Copy the code

Ps (see below) and amending will replace the old one with a new commit, so if you’ve already pushed the former commit to the remote repository once, you’ll now have to force push (-f). Note – always make sure you specify a branch!

(my-branch)$ git push origin mybranch -f
Copy the code

In general, avoid pushing. It is better to create and push a new commit than to force a revised commit. The latter causes developers who work with that branch, or its children, to conflict with the source history.

I accidentally did a hard reset. I wanted to get my content back

If you do git reset –hard by accident, you can usually get your commit back because Git keeps a log of everything and keeps it for a few days.

(main)$ git reflog
Copy the code

You’ll see a list of your past commits, and a reset commit. Select the SHA of the commit you want to return to and reset again:

(main)$ git reset --hard SHA1234
Copy the code

And you’re done.

The Staging (Staging)

I need to add the staging to the last commit.

(my-branch*)$ git commit --amend
Copy the code

I want to temporarily save part of a new file, but not the entire file

In general, if you want to temporarily save part of a file, you can do this:

$ git add --patch filename.x
Copy the code

-p shorthand. This will turn on interactive mode, and you’ll be able to separate the commit with the S option; However, if the file is new, there will be no this option, when adding a new file, do this:

$ git add -N filename.x
Copy the code

Then, you need to manually select the rows you want to add using the e option, and git diff –cached will show you which rows are temporarily stored and which are only locally stored.

I want to add changes in one file to two commits

Git add -p allows you to interactively select the part you want to commit.

I want to change the staging to unstaging, and I want to temporarily store the staging

In most cases, you should make everything unstored and then commit the content you want. But assuming that’s what you want to do, here you can create a temporary COMMIT to save your provisioned content and then stash your unprovisioned content. And then reset, and then the last commit changes what was temporarily stored to unstored, and then stash pop comes back.

$ git commit -m "WIP"
$ git add .
$ git stash
$ git reset HEAD^
$ git stash pop --index 0
Copy the code

Note 1: POP is used here only because we want to keep it idempotent as much as possible. Note 2: if you do not add –index you will mark temporary files as stored.

Unstaged content

I want to move the unstored content to a new branch

$ git checkout -b my-branch
Copy the code

I want to move the pending content to another existing branch

$ git stash
$ git checkout my-branch
$ git stash pop
Copy the code

I want to discard locally uncommitted changes.

If you just want to reset some commits between origin and your local, you can:

# one commit
(my-branch)$ git reset --hard HEAD^
# two commits
(my-branch)$ git reset --hard HEAD^^
# four commits
(my-branch)$ git reset --hard HEAD~4
# or
(main)$ git checkout -f
Copy the code

To reset a particular file, you can use the filename as an argument:

$ git reset filename
Copy the code

I want to discard some unstored content

If you want to discard some of your working copy, but not all of it.

Checkout what you don’t need and keep what you do.

$ git checkout -p
# Answer y to all of the snippets you want to drop
Copy the code

Another way is to use Stash, stash everything you want to keep, reset the working copy, and reapply what you keep.

$ git stash -p
# Select all of the snippets you want to save
$ git reset --hard
$ git stash pop
Copy the code

Or stash the part you don’t need, and stash drop.

$ git stash -p
# Select all of the snippets you don't want to save
$ git stash drop
Copy the code

A branch (Branches)

I pulled content from the wrong branch, or pulled content into the wrong branch

This is another case of using Git reflog to find the point to the HEAD before the error pull.

(main)$ git reflog
ab7555f HEAD@{0}: pull origin wrong-branch: Fast-forward
c5bc55a HEAD@{1}: checkout: checkout message goes here
Copy the code

Desired Commit Resets the branch to the desired commit:

$ git reset --hard c5bc55a
Copy the code

To complete.

I want to drop the local commit so that my branch is consistent with the remote one

Make sure you don’t push your content to remote.

Git status will show you how many commits you are ahead of origin:

(my-branch)$ git status
# On branch my-branch
# Your branch is ahead of 'origin/my-branch' by 2 commits.
#   (use "git push" to publish your local commits)
#
Copy the code

One way is:

(main)$ git reset --hard origin/my-branch
Copy the code

I needed to submit to a new branch, but mistakenly submitted to Main

Create a new branch under main, do not switch to the new branch, still under main:

(main)$ git branch my-branch
Copy the code

Reset the main branch to the previous commit:

(main)$ git reset --hard HEAD^
Copy the code

HEAD^ is short for HEAD^1, which you can further reset by specifying the HEAD to set.

Or, if you don’t want to use HEAD^, find the commit hash you want to reset to (git log can do that) and reset to that hash. Synchronize content to remote using Git push.

For example, the submitted hash that main wants to reset to is a13b85e:

(main)$ git reset --hard a13b85e
HEAD is now at a13b85e
Copy the code

Checkout the newly created branch to continue working:

(main)$ git checkout my-branch
Copy the code

I want to keep the whole file from another ref-ish

Let’s say you’re working on a prototype solution (see note) with hundreds of things, each of which works well. Now you commit to a branch and save the work:

(solution)$ git add -A && git commit -m "Adding all changes from this spike into one big commit."
Copy the code

When you want to put it in a branch (maybe feature, or Develop), you care about keeping the entire file intact, and you want a large commit to be split into smaller ones.

Suppose you have:

  • branchsolution, with prototype solutions, leadingdevelopBranch.
  • branchdevelopHere you apply some of the elements of the prototype solution.

I can solve this problem by putting content in your branch:

(develop)$ git checkout solution -- file1.txt
Copy the code

This will take the contents of the file from branch Solution to branch Develop:

# On branch develop
# Your branch is up-to-date with 'origin/develop'.
# Changes to be committed:
#  (use "git reset HEAD <file>..." to unstage)
#
#        modified:   file1.txt
Copy the code

Then, submit as normal.

Note: Spike solutions are made to analyze or solve the problem. These solutions are used for estimation and discarded once everyone gets clear visualization of the problem.

I committed several commits to the same branch, which should be distributed in different branches

Suppose you have a main branch, execute git log, and you see that you have committed twice:

(main)$ git log

commit e3851e817c451cc36f2e6f3049db528415e3c114
Author: Alex Lee <[email protected]>
Date:   Tue Jul 22 15:39:27 2014 -0400

    Bug #21 - Added CSRF protection

commit 5ea51731d150f7ddc4a365437931cd8be3bf3131
Author: Alex Lee <[email protected]>
Date:   Tue Jul 22 15:39:12 2014 -0400

    Bug #14 - Fixed spacing on title

commit a13b85e984171c6e2a1729bb061994525f626d14
Author: Aki Rose <[email protected]>
Date:   Tue Jul 21 01:12:48 2014 -0400

    First commit
Copy the code

Let’s mark bugs with a commit hash(e3851E8 for #21, 5ea5173 for #14).

First, we reset the main branch to the correct commit (A13b85e):

(main)$ git reset --hard a13b85e
HEAD is now at a13b85e
Copy the code

Now, let’s create a new branch for Bug #21:

(main)$ git checkout -b 21
(21)$
Copy the code

Next, we cherry-pick the commit to Bug #21 into the current branch. This means that we will apply the commit, and only the commit, directly on the HEAD.

(21)$ git cherry-pick e3851e8
Copy the code

At this point, there may be a conflict here, refer to the interactive Reps Chapter Conflict Section to resolve the conflict.

Again, we created a new branch for Bug #14, also based on the main branch

(21)$ git checkout main
(main)$ git checkout -b 14
(14)$
Copy the code

Finally, execute cherry pick for Bug #14:

(14)$ git cherry-pick 5ea5173
Copy the code

I want to delete the local branch where the upstream branch has been deleted

Once you merge a pull request on Github, you can delete the merged branches in your fork. If you don’t intend to continue working on the branch, it’s much cleaner to delete the local copy of the branch, so you don’t get tangled up in working branches and a bunch of old branches.

$ git fetch -p
Copy the code

I accidentally deleted my branch

If you regularly push to remote, it should be safe most of the time, but sometimes it is possible to delete branches that have not yet been pushed to remote. Let’s create a branch and a new file:

(main)$ git checkout -b my-branch
(my-branch)$ git branch
(my-branch)$ touch foo.txt
(my-branch)$ ls
README.md foo.txt
Copy the code

Add the file and make a commit

(my-branch)$ git add .
(my-branch)$ git commit -m 'foo.txt added'
(my-branch)$ foo.txt added
 1 files changed, 1 insertions(+)
 create mode 100644 foo.txt
(my-branch)$ git log

commit 4e3cd85a670ced7cc17a2b5d8d3d809ac88d5012
Author: siemiatj <[email protected]>
Date:   Wed Jul 30 00:34:10 2014 +0200

    foo.txt added

commit 69204cdf0acbab201619d95ad8295928e7f411d5
Author: Kate Hudson <[email protected]>
Date:   Tue Jul 29 13:14:46 2014 -0400

    Fixes #6: Force pushing after amending commits
Copy the code

Now let’s go back to the main branch and ‘accidentally’ delete the my-branch

(my-branch)$ git checkout main
Switched to branch 'main'
Your branch is up-to-date with 'origin/main'.
(main)$ git branch -D my-branch
Deleted branch my-branch (was 4e3cd85).
(main)$ echo oh noes, deleted my branch!
oh noes, deleted my branch!
Copy the code

At this point you’ll remember Reflog, an updated version of the log that stores the history of all the actions in the repO.

(main)$ git reflog
69204cd HEAD@{0}: checkout: moving from my-branch to main
4e3cd85 HEAD@{1}: commit: foo.txt added
69204cd HEAD@{2}: checkout: moving from main to my-branch
Copy the code

As you can see, we have a commit hash from the deleted branch, and let’s see if we can restore the deleted branch.

(main)$ git checkout -b my-branch-help
Switched to a new branch 'my-branch-help'
(my-branch-help)$ git reset --hard 4e3cd85
HEAD is now at 4e3cd85 foo.txt added
(my-branch-help)$ ls
README.md foo.txt
Copy the code

Look! We were able to retrieve the deleted files. Git’s Reflog is just as useful if rebasing goes wrong.

I want to delete a branch

Delete a remote branch:

(main)$ git push origin --delete my-branch
Copy the code

You can also:

(main)$ git push origin :my-branch
Copy the code

Delete a local branch:

(main)$ git branch -D my-branch
Copy the code

I want to checkout a branch from the remote branch someone else is working on

First, fetch all branches from remote:

(main)$ git fetch --all
Copy the code

Suppose you want to check out from the remote Daves branch to the local Daves

(main)$ git checkout --track origin/daves
Branch daves set up to track remote branch daves from origin.
Switched to a new branch 'daves'
Copy the code

Git checkout -b [branch] [remotename]/[branch]

This gives you a local copy of the Daves branch and any updates pushed can be seen remotely.

Rebasing and Merging

I want to undo rebase/merge

You can merge or rebase a wrong branch, or fail to complete an ongoing rebase/merge. Git stores the original HEAD in a variable called ORIG_HEAD for risky operations, so it’s easy to revert branches back to their pre-rebase /merge state.

(my-branch)$ git reset --hard ORIG_HEAD
Copy the code

I already rebase, but I don’t want to force push.

Unfortunately, if you want to reflect these changes on the remote branch, you have to force push. Because you Fast forward your commit and change Git history, remote branches will not accept changes unless you force them. This is one of the main reasons why many people are using the Merge workflow instead of the Rebasing workflow, as the developer’s force push can land large teams in trouble. One way to safely use Rebase is not to reflect your changes to the remote branch, but to do the following:

(main)$ git checkout my-branch
(my-branch)$ git rebase -i main
(my-branch)$ git checkout main
(main)$ git merge --ff-only my-branch
Copy the code

I need to combine several commits.

Let’s say your work branch will do a pull-request to main. In general, you do not care about the timestamp of the commit. Instead, you just want to combine all the commits into a single one and reset them. Make sure the main branch is up to date and your changes have been committed, then:

(my-branch)$ git reset --soft main
(my-branch)$ git commit -am "New awesome feature"
Copy the code

If you want more control and want to preserve timestamps, you need to do interactive rebase:

(my-branch)$ git rebase -i main
Copy the code

If there are no other branches relative, you will have to rebase relative to your HEAD. For example, if you want to combine the last two commits, you would rebase relative to HEAD~2, combine the last three commits relative to HEAD~3, and so on.

(main)$ git rebase -i HEAD~2
Copy the code

After you execute the Interactive Rebase command, you should see something like the following in your editor:

pick a9c8a1d Some refactoring pick 01b2fd8 New awesome feature pick b729ad5 fixup pick e3851e8 another fix # Rebase 8074d12.. b729ad5 onto 8074d12 # # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit's log message # x, exec = run command (the rest of the line) using shell # # 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. # # Note that empty commits are commented outCopy the code

All lines starting with # are comments and do not affect Rebase.

You can then replace pick with any of the commands listed above, or you can delete a commit by deleting the corresponding line.

For example, if you want to keep the oldest commit separately and combine all the remaining ones into the second commit, you should edit the word before each commit after the second commit to f:

pick a9c8a1d Some refactoring
pick 01b2fd8 New awesome feature
f b729ad5 fixup
f e3851e8 another fix
Copy the code

If you want to combine these commits and rename this commit, you should add an R next to the second commit, or more simply replace f with s:

pick a9c8a1d Some refactoring
pick 01b2fd8 New awesome feature
s b729ad5 fixup
s e3851e8 another fix
Copy the code

You can rename the Commit in the text box that pops up next.

Newer, awesomer features

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# rebase in progress; onto 8074d12
# You are currently editing a commit while rebasing branch 'main' on '8074d12'.
#
# Changes to be committed:
#	modified:   README.md
#
Copy the code

If successful, you should see something like the following:

(main)$ Successfully rebased and updated refs/heads/main.
Copy the code

A merging strategy

–no-commit Performs merge but does not commit automatically, giving users a chance to check and modify the merge before committing. No-ff will provide evidence of the existence of a feature branch, keeping the history of the project consistent. .

(main)$ git merge --no-ff --no-commit my-branch
Copy the code

I need to merge a branch into a commit.

(main)$ git merge --squash my-branch
Copy the code

I just want to combine unpushed submissions.

Sometimes you have several work in progress commits before you can push the data upstream. You don’t want to include groups that have already been pushed, because someone else might already have a commit referencing them.

(main)$ git rebase -i @{u}
Copy the code

This results in an interactive rebase that lists only non-push commits. It is safe to reorder/fix/squash on this list.

Check to see if all the commits on the branch have been merged

Check that all commits on one branch have been merged into other branches, and you should do a diff between the heads of those branches or any commits:

(main)$ git log --graph --left-right --cherry-pick --oneline HEAD... feature/120-on-scrollCopy the code

This tells you a list of all the commits that are in one branch but not in another, and the commits that are not shared between branches. Another way to do this is:

(main)$ git log main ^feature/120-on-scroll --no-merges
Copy the code

Possible problems with interactive Rebase (REbase)

This rebase edit screen shows ‘noop’

If this is what you see:

noop
Copy the code

This means that your rebase branch is either on the same commit as the current branch, or ahead of the current branch. You can try:

  • Check to make sure there are no problems with the main branch
  • rebase  HEAD~2Or even earlier

There are conflicting situations

If you cannot successfully complete Rebase, you may have to resolve conflicts.

First run git status to find out which files are in conflict:

(my-branch)$ git status
On branch my-branch
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

 modified:   README.md
Copy the code

In this example, readme.md conflicts. Open the file and find something like the following:

   <<<<<<< HEAD
   some code
   =========
   some code
   >>>>>>> new-commit
Copy the code

You need to resolve the differences between the newly committed code (in the example, from the middle == line to new-commit) and the HEAD.

Sometimes these merges are very complex and you should use the Visual Diff Editor:

(main*)$ git mergetool -t opendiff
Copy the code

After you have resolved all the conflicts and tests, git adds the changed file and continues the rebase with git rebase –continue.

(my-branch)$ git add README.md
(my-branch)$ git rebase --continue
Copy the code

Git rebase –skip if, after resolving all the conflicts, you get the same result as before committing.

Any time you want to end the rebase process and return to the pre-rebase branch state, you can do this:

(my-branch)$ git rebase --abort
Copy the code

Stash

Save all changes temporarily

Temporarily save all changes in your working directory

$ git stash
Copy the code

You can use -u to exclude some files

$ git stash -u
Copy the code

Temporarily save the specified file

Suppose you just want to hold a file

$ git stash push working-directory-path/filename.ext
Copy the code

Suppose you want to temporarily store multiple files

$ git stash push working-directory-path/filename1.ext working-directory-path/filename2.ext
Copy the code

Logs messages while staging

So you can see it in the list

$ git stash save <message>
Copy the code

or

$ git stash push -m <message>
Copy the code

Use a specified staging

First you can look at your Stash record

$ git stash list
Copy the code

And then you can apply some stash

$ git stash apply "stash@{n}"
Copy the code

Here, ‘n’ is where stash is in the stack, and the top stash is going to be zero

In addition, use time markers (if you can remember).

$ git stash apply "stash@{2.hours.ago}"
Copy the code

The content that is not temporarily stored is retained when it is temporarily stored

You need to manually create a Stash commit and then use the Git Stash store.

$ git stash create
$ git stash store -m "commit-message" CREATED_SHA1
Copy the code

Miscellaneous, Miscellaneous Objects)

Clone all submodules

$ git clone --recursive git://github.com/foo/bar.git
Copy the code

If already cloned:

$ git submodule update --init --recursive
Copy the code

Delete a tag

$ git tag -d <tag_name>
$ git push <remote> :refs/tags/<tag_name>
Copy the code

Restore deleted tags

If you want to recover a deleted tag, you can follow these steps: First, you need to find the unreachable tag:

$ git fsck --unreachable | grep tag
Copy the code

Write down the hash for the tag and use Git update-ref

$ git update-ref refs/tags/<tag_name> <hash>
Copy the code

Your tag should have been restored by this time.

Deleted patch

If someone sends you a pull request on GitHub, but then deletes their own original fork, you won’t be able to clone their commit or use Git AM. In this case, it is best to manually view their commits, copy them to a new local branch, and commit.

After committing, modify the author, see Changing the Author. Then, apply the changes and launch a new pull request.

Tracking Files

I just want to change the case of a file name without changing the content

(main)$ git mv --force myfile MyFile
Copy the code

I want to delete a file from Git, but keep it

(main)$ git rm --cached log.txt
Copy the code

The Configuration (Configuration)

I want to alias some Git commands.

On OS X and Linux, your Git configuration file is stored in ~/.gitconfig. I added some quick aliases (and some that I could easily misspell) in the [Alias] section, as follows:

[alias]
    a = add
    amend = commit --amend
    c = commit
    ca = commit --amend
    ci = commit -a
    co = checkout
    d = diff
    dc = diff --changed
    ds = diff --staged
    f = fetch
    loll = log --graph --decorate --pretty=oneline --abbrev-commit
    m = merge
    one = log --pretty=oneline
    outstanding = rebase -i @{u}
    s = status
    unpushed = log @{u}
    wc = whatchanged
    wip = rebase -i @{u}
    zap = fetch -p
Copy the code

I want to cache the username and password for a repository

If you have a repository that requires authorization and you can cache usernames and passwords instead of entering them every time you push/pull, the Credential Helper can do that for you.

$ git config --global credential.helper cache
# Set git to use the credential memory cache
Copy the code
$ git config --global credential.helper 'cache --timeout=3600'
# Set the cache to timeout after 1 hour (setting is in seconds)
Copy the code

I don’t know what I did wrong

You mess up: you reset something, or you merged the wrong branches, or you pushed and couldn’t find your own commit. There will be times when you’ve been doing well, but you want to get back to a certain state.

This is the purpose of Git reflog, which records any changes made to the tip of a branch, even if that tip is not referenced by any branch or tag. Basically, every time the HEAD changes, a new record is added to the reflog. Unfortunately, this only works for the local branch, and it only tracks actions (for example, not any changes to a file that is not being logged).

(main)$ git reflog 0a2e358 HEAD@{0}: reset: moving to HEAD~2 0254ea7 HEAD@{1}: checkout: C10f740 HEAD@{2}: Checkout: moving from main to 2.2Copy the code

The reflog above shows checking out from main to 2.2, and then checking back again. There is also a hard reset to an older commit. The latest action appears at the top as HEAD@{0}.

If it turns out that you accidentally moved back a commit, reflog will contain the commit you pointed to on Main before you accidentally moved back (0254ea7).

$ git reset --hard 0254ea7
Copy the code

You can then change main back to the previous commit using Git Reset, which provides a safety net in case history is accidentally changed.