How to Make Changes to a Previous Git Commit (Even Older Ones!)

Whether you forgot to update a file or want to clean up your commit history, Git gives you powerful tools to change past commits. Here’s how to do it safely and effectively.

There are 2 sets of instructions:

  1. How to Change the Most Recent Commit
  2. How to Change an Older Commit (Not the Latest One)

Follow whichever set of instructions makes sense for your situation.


1. How to Change the Most Recent Commit

Step 1: Make your changes to the code

Make the changes you want to make to your code then run the git add command:

# Make your code changes
git add .

Step 2: Add the changes to the latest commit

# Option 1: keeps the commit message the same
git commit --amend --no-edit


# Option 2: allows you to modify the commit message
git commit --amend

git commit --amend without the --no-edit flag opens your editor so you can modify the commit message.

⚠️ Important: Only amend if the commit hasn’t been pushed to a shared branch. Amending a pushed commit rewrites history, which can mess with other collaborators.


2. How to Change an Older Commit (Not the Latest One)

Step 1: Start an interactive rebase

To edit an earlier commit (e.g., the second one back), use interactive rebase:

git rebase -i HEAD~n

Replace n with how many commits back you want to go.

You’ll see something like:

pick a1b2c3 Fix login bug
pick d4e5f6 Update README
pick 789abc Add scraper module

Each line represents a commit.

Step 2: Change pick to edit

Change pick to edit on the line you want to modify:

pick a1b2c3 Fix login bug
edit d4e5f6 Update README
pick 789abc Add scraper module

This tells Git: “Pause at this commit so I can change it.”

❓ What if nothing happens when you try to type?

If Git opens Vim (default for many systems), here’s how to use it:

  1. Press i to enter Insert mode – now you can type.
  2. Change pick to edit as needed.
  3. Press Esc to exit insert mode.
  4. Save and exit by typing the following:
:wq

Then press Enter.


Step 3: Git Pauses the Rebase

After saving, Git will stop at the commit you marked for editing. You’ll see a message like:

Stopped at d4e5f6... Update README

Step 4: Make Your Changes

Make whatever changes you need to the code. Then:

git add .
git commit --amend

You can now update both the code and the message if you want.


Step 5: Continue the Rebase

Once you’re done:

git rebase --continue

Git will resume the rebase and replay the rest of your commits.


Made a Mistake?

To cancel the rebase and go back:

git rebase --abort

🧼 After Editing Commits: Push Carefully

If you’ve already pushed these commits to a remote branch, you’ll need to force push:

git push --force

⚠️ Use with caution – force pushing can overwrite others’ work. Only do this on branches you own or after coordinating with teammates.

Blockchain Development: Solidity Crash Course

Solidity is the programming language used to write Ethereum smart contracts. If you want to be an Ethereum blockchain developer, learning it should be one of the first things you do.

In this article, I’m going to be showing you some basic Solidity syntax and fundamental features that every smart contract must have. This article is for beginners but it assumes you have some prior knowledge in another programming language.

Versioning

At the top of any new smart contract file must be the Solidity version. You have a few options for denoting the version of your contract:

  • If the contract is for a specific Solidity version. In this case, 0.6.0:
pragma solidity 0.6.0
  • If the contract is for a version within the 0.6.0 range (0.6.0 to 0.6.12):
pragma solidity ^0.6.0
  • If the contract is for a version within the range from 0.6.0 to 0.9.0 (exclusive):
pragma solidity >=0.6.0 <0.9.0

You might be wondering: which version should I use? When deploying contracts, you should use the latest released version of Solidity. Apart from exceptional cases, only the latest version receives security fixes

Contract Declaration

Declare a new contract using the contract keyword followed by the contract’s name:

contract Bank {

} 

As you can see, the syntax for defining a new contract in Solidity is similar to the syntax for defining a class in a language like Java or Python.

This is the most simple version of a valid contract.

Types and Declaring Variables

Solidity has pretty much all of the same data types as any other programing language.

There are multiple different sizes of integers that you can create. For example,

uint256 newNumber = 6;

There are also some data types that you may not be familiar with.

For example, there is an address type for storing account addresses on the blockchain, such as a MetaMask account address:

address accountAddress = 0x29D7d1dd5B6f9C864d9db560D72a247c178aE86B;

Comments

Comments are denoted using two slashes (//)

// This is a comment in Solidity

Defining Functions

Defining functions in Solidity is similar to other languages

function storeMoney(uint256 _amount) {
}

If a function returns a value, you can use this syntax:

function storeMoney(uint256 _amount) returns (uint256) {
   return _amount;
}

Visibility

Visibility refers to where functions and variables within a Solidity contract are available. There are four types of visibility:

  1. External: Functions/variables with external visibility must be called by another contract; they can’t be called within the same contract
  2. Public: Functions/variables with public visibility can be called by anybody, including any users of the blockchain
  3. Internal: Functions/variables with internal visibility can only be accessed internally (i.e. from within the current contract or contracts deriving from it)
  4. Private: Functions/variables with private visibility are only visible for the contract they are defined in and not in derived contracts

To specify the visibility of a function:

function storeMoney(uint256 _amount) public {
}

To specify the visibility of a variable:

bool private isCheckingAccount;

View and Pure Functions

If a function updates the value of a variable in a smart contract, it is changing the contract’s state. Any state change in a smart contract is considered a transaction and thus requires a gas fee to update the contract.

There are two types of functions that do not update the state of the contract: view and pure functions. In other words, these are functions you do not have to make a transaction on and they don’t cost gas.

A view function reads some state off of the blockchain. Public variables are already technically view functions.

function retrieveBalance(uint256 _balance) public view returns (unit256) {
   return _balance;
}

A pure function is a function that purely does some type of math, but does not store the output of that math. Thus, there is no change of the blockchain’s state since no variables are being saved or updated.

function addBalances(uint256 balance) public pure {
    return balance + balance;   // balance is not being updated
}

Structs

Structs are a way to define new type in Solidity. They are structures that contain one or more native Solidity variable types.

Define a new struct:

struct Account {
   uint256 balance;
   string name;
}

Create an instance/object of the struct:

Account public myAccount = Account({ balance: 100, name: "John Doe" });

Define an array of struct objects;

Account[] public accounts;    // dynamic array (can grow to any size)

Account[3] public accounts;   // fixed array (fixed size of 3)

Memory

In Solidity, there are two main ways to store information: you can store it in memory or in storage.

When you store an object in memory, the data will only be stored during the execution of the function/contract call. When an object is stored in storage, the data will persist even after the function executes; it will persist.

Strings are actually not a variable type in Solidity. In Solidity, strings are objects– arrays of bytes. Since it’s an object, the programmer has to decide where they want to store it: memory or storage.

function addAccount(string memory _name, uint256 _balance) {
    accounts.push(Account(_balance, _name));
}

Mappings

mapping is a Solidity variable type that is similar to a dictionary in other languages. It is an array of key-value pairs (with 1 value per key). If given a key, a mapping spits out whatever variable that that key is mapped to.

mapping(string => uint256) public nametoBalance;

function addAccount(string memory _name, uint256 _balance) {
    accounts.push(Account(_balance, _name));
    nametoBalance[_name] = _balance;
}

SPDX License

Many times, the compiler will raise an error if your source code file doesn’t include an SPDX License Identifier.

The Ethereum community believes that trust in smart contract can be better established if their source code is available. For legal reasons, the SPDX License Identifier makes it easier for your source code to be accessed by others.

You should add it to the very top of your file (above the version):

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0

Now, you have a basic knowledge of Solidity code. Thanks for reading!