Undoing Changes and Time Travelling in Git
Tags: github, git, webdev, tutorial
Published: 2023-08-18 13:39:07

## Checkout

- The `git checkout` command is like a Git Swiss Army knife. Many developers think it is overloaded, which is what lead to the addition of the `git switch` and `git restore` commands
- We can use checkout to create branches, switch to new branches, restore files, and undo history!
- We can use `git checkout <commit-hash>` to view a previous commit. We just need the first 7 digits of a commit hash which can be obtained through `git log --oneline`. Doing so will result in a *Detached Head.* Now the `git log` will change because we have moved back in time
- `git checkout` supports a slightly odd syntax for referencing previous commits relative to a particular commit.
    - HEAD~1 refers to the commit before HEAD (parent)
    - HEAD~2 refers to 2 commits before HEAD (grandparent
    
    ```bash
    git checkout HEAD~1
    ```
    
    
    ![Image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/repqqvnlxnt6vql6cj4z.png)
    
    ### Discarding Changes
    
    - Suppose you've made some changes to a file but don't want to keep them. To revert the file back to whatever it looked like when you last committed, you can use:
        - `git checkout HEAD <filename>` to discard any changes in that file, reverting back to the HEAD.

## Restore

- `git restore` is a brand new Git command that helps with undoing operations. `git restore` was introduced alongside `git switch` as an alternative to some of the uses for `checkout`.
- Suppose you've made some changes to a file since your last commit. You've saved the file but then realize you definitely do NOT want those changes anymore!
- To restore the file to the contents in the HEAD, use `git restore <file-name>`
- `git restore <file-name>` restores using HEAD as the default source, but we can change that using the **--source** option.
- For example, `git restore --source HEAD~1 home.html` will restore the contents of home.html to its state from the commit prior to HEAD. You can also use a particular commit hash as the source.
- `git status` will always remind you what to use!
    
    ### Unstaging Files with Restore
    
    - If you have accidentally added a file to your staging area with git add and you don't wish to include it in the next commit, you can use `git restore` to remove it from staging.
    - Use the --staged option like this:
        
        ```bash
        git restore --staged <file-name>
        ```
        

## Git Reset

- Suppose you've just made a couple of commits on the master branch, but you actually meant to make them on a separate branch instead. To undo those commits, you can use `git reset`.
- `git reset <commit-hash>` will reset the repo back to a specific commit. The commits are gone but the changes will be kept in the working directory.
- If you want to undo both the commits AND the actual changes in your files, you can use the **--hard** option.
- For example, `git reset --hard HEAD~1` will delete the last commit and associated changes.

## Git Revert

- `git revert` is similar to git reset in that they both "undo" changes, but they accomplish it in different ways.
- `git reset` actually moves the branch pointer backwards, eliminating commits.
- `git revert` instead creates a brand new commit which reverses/undos the changes from a commit. Because it results in a new commit, you will be prompted to enter a commit message.
- The history of the commit is preserved but the changes are reverted
    
    ```bash
    git revert <commit-hash>
    ```
    
    
![Image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d1gdoqpli0oq4kunxkyq.png)
    
    
![Image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cefbgl0llcpkkiau71g1.png)
    

## Which Command To Use?

- Both `git reset` and `git revert` help us reverse changes, but there is a significant difference when it comes to collaboration.
- If you want to reverse some commits that other people already have on their machines, you should use **revert**.
- If you want to reverse commits that you haven't shared with others, use **reset** and no one will ever know!

## Theory of Git Checkout

- Usually, HEAD points to a specific branch reference rather than a particular commit. The HEAD is a pointer to the current branch reference and the branch reference is a pointer to the last commit made on a particular branch
- When we make a new commit, the branch reference is updated to reflect the new commit. The HEAD remains the same, because it's pointing at the branch reference. When you switch branches, HEAD is updated to point to the specific branch reference. This is all to say that HEAD usually refers to a branch NOT a specific commit.
- When we checkout a particular commit git checkout `git checkout d8194d6`, HEAD points at that commit rather than at the branch pointer
    
    
![Image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/itbp2y08s15wmucdi9e7.png)
    
    

### Detached Head
    
You have a couple of options:
    1. Stay in detached HEAD to examine the contents of the old 
       commit. Poke around, view the files, etc.
    2. Leave and go back to wherever you were before - reattach 
       the HEAD
        
        

```bash
   git switch master
```

3. Create a new branch after checking out the old commit and switch to it. You can now make and save changes since HEAD is no longer detached.
    1. Suppose you want to go back to an old commit and make some
new changes
    2. Checkout the old commit. Now in detached HEAD state.
    3. While in detached HEAD, Make a new branch and switch to it. Head is now back to pointing at a branch reference!
    4. Now on the new branch, make as many new commits as you want! It's like you time traveled! We went back to an            old commit and made a new branch based on it.

```bash
        git checkout <d8194d6>
        git switch -c newbranch
        git add .
        git commit -m "new commit"
```