How to manage your local changes with git
Tags: git, productivity
Published: 2022-01-30 05:32:23

When we are working a project, often we need to make changes specific only to the local development environment we are working in. For example, point to some development or even personal database, or plug in our own credentials. Those are truly local only changes that we don't want to push to the remote repo or merge to any team level branches. On the other hand, we don't want to have to manually make these changes every time when we start working on a new feature branch, or even when we have just pulled from the remote repo.

That is not a problem if the changes can be isolated to a local-only small file, or externalized into environment variables, because we can simply ignore the local configuration file in git.

However, when circumstances don't allow local changes to be isolated or ignored, e.g. when it's a couple lines of changes in a large config file that's always tracked, or the project does not have the infrastructure to support environment specific configuration files, here is the workflow I often use:

First I create the feature branch that will contain the commits implementing the feature, and will be pushed to the remote repo:

```
$ git checkout -b my-feature
```

Then I create the local branch I will actually be working on. It will always be the feature branch plus the commit containing my local changes.

```
$ git checkout -b my-feature-local
```

Assuming `A` is the current tip of `master`, so this is the commit graph we are starting with:
`A(master,my-feature,my-feature-local,HEAD)`

I make whatever local changes necessary.

```
$ git commit -am "LOCAL ONLY, DO NOT MERGE"
```

Now the graph looks like (where L is the "LOCAL ONLY" commit):
`A(master,my-feature) - L(my-feature-local,HEAD)`

I start hacking away at the actual task, to a good saving point. I may have created a couple more commits, B and C, containing actual coding for the new feature by now.
`A(master,my-feature) - L - B - C(my-feature-local,HEAD)`

I'm ready to push my work to the remote repo. But I don't want to push my local changes, so I do:

```
$ git rebase -i my-feature
```
During the interactive rebase, I move the "LOCAL ONLY" commit to the top, so now the graph looks like:
`A(master,my-feature) - B - C - L(my-feature-local,HEAD)`

Now I have moved the commits for implementing the feature to before the local commit, and onto the my-feature branch from which I'll actually do the push:
```
$ git rebase my-feature-local~ my-feature
```

The graph at this point:
`A(master) - B - C(my-feature,HEAD) - L(my-feature-local)`

I'm ready to push:
```
$ git push -u my-feature
$ git checkout my-feature-local
```

Now I'm back on my local branch. After I make some more commits, I just repeat the rebase-and-push process above.

When I am working with other people on a feature, and we all push code to the `my-feature` branch, there is just one extra step after every time I have pulled `my-feature` from the remote repo:

```
$ git rebase my-feature my-feature-local
```

At the cost of a couple of extra steps, this workflow has some advantages, compared to manual changes and/or git-ignore the files locally changed:

- Changes, even though local, are still tracked and controlled properly by git. If the same files are changed as part of the implementation, by you or the rest of the team, git will merge them with your local changes during the rebase.
- No need to make the same manual changes again and again. Simply create a "local" branch on top of whichever branch you need to work on, cherry pick the "local only" commit over, and you are good to go.
- Local changes don't have to be limited to one commit. They can be organized into a series of "local" commits and allow more advanced use cases by manipulating the series in git.