Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

git-go-patch docs: more specific editing and rebase notes #200

Merged
merged 3 commits into from
Dec 11, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 57 additions & 8 deletions cmd/git-go-patch/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ For more information about why we chose this style of fork for the Microsoft Go
Related documentation:

* [set-up-repo.md](set-up-repo.md) - How to set up your repo to work with git-go-patch.
* [microsoft/go Developer Guide](https://github.com/microsoft/go/blob/microsoft/main/eng/doc/DeveloperGuide.md) - How to use this tool as part of a microsoft/go development workflow.

## Installing

Expand All @@ -19,6 +20,7 @@ First, use Go to build and install the command:
go install github.com/microsoft/go-infra/cmd/git-go-patch@latest
```

> [!NOTE]
> Make sure `git-go-patch` is accessible in your shell's `PATH` variable. You may need to add `$GOPATH/bin` to your `PATH`. Use `go env GOPATH` to locate it.

Then, run the command to see the help documentation:
Expand All @@ -27,7 +29,8 @@ Then, run the command to see the help documentation:
git go-patch -h
```

> `git` detects that our `git-go-patch` executable starts with `git-` and makes it available as `git go-patch`. The program still works if you call it with its real name, but we think it's easier to remember and type something that looks like a `git` subcommand.
> [!NOTE]
> [`git` detects](https://git.github.io/htmldocs/howto/new-command.html) that our `git-go-patch` executable starts with `git-` and makes it available as `git go-patch`. The program still works if you call it with its real name, but we think it's easier to remember and type something that looks like a `git` subcommand.

# Subcommands

Expand All @@ -38,11 +41,53 @@ Sometimes you have to fix a bug in a patch file, add a new patch file, etc., and
1. Open a terminal anywhere within the repository containing the patch files or the submodule.
1. Use `git go-patch apply` to apply patches onto the submodule as a series of commits.
1. Navigate into the submodule.
1. Edit the commits as desired.
1. `git go-patch rebase` starts an interactive rebase, allowing you to do any normal Git rebase actions like reorder, squash, drop, and edit.
1. If it fits your workflow, use `git commit --fixup={commit}` to create fixup commits and `git go-patch rebase` to apply them.
1. Edit the commits as desired. We recommend using an **interactive rebase** ([Pro Git guide](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History#_changing_multiple)) ([Git docs](https://git-scm.com/docs/git-rebase#_interactive_mode)) started by `git go-patch rebase`. A few recommended editing workflows are:
* Commit-then-rebase:
1. Make some changes in the submodule and create commits.
1. Use `git go-patch rebase` to start an interactive rebase of the commits that include the patch changes and your changes.
* This command runs `git rebase -i` with with the necessary base commit.
* Reorder the list to put each of your commits under the patch file that it applies to.
* For each commit, choose `squash` if you want to edit the commit message or `fixup` if you don't. Use `pick` if you want to create a new patch file.
1. Follow the usual interactive rebase process.
* Interactive rebase `edit`:
* Useful if you have an exact change in mind or your commits would hit rebase conflicts.
1. Use `git go-patch rebase` to start an interactive rebase before you've made any changes.
1. Mark commits to edit with `edit` and save/close the file to continue.
1. When the rebase process stops at a commit, make your changes, use `git commit --amend` to edit the commit, then `git rebase --continue` to move on.
* Other `git rebase` features like [`git commit --fixup={commit}`](https://git-scm.com/docs/git-commit#Documentation/git-commit.txt---fixupamendrewordltcommitgt) also work as expected.
1. Use `git go-patch extract` to rewrite the patch files based on the changes in the submodule.

### Recovering from a bad rebase

It's possible to accidentally squash a commit into the wrong patch file during a rebase.
This makes the change show up in the wrong patch file.
To fix this, sometimes it's simplest to start from scratch and copy changes back in manually.
However, many [general history rewriting methods](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History) will work.
Here are a few strategies:

#### Go back to the pre-rebase commit in the submodule

You might be able to go back to the pre-rebase commit and try the `rebase` again.
The original commit might be in your terminal history: many commands log the commit hashes they operate on.
Or, try `git reflog` in the submodule to [recover the commit hash](https://git-scm.com/book/en/v2/Git-Internals-Maintenance-and-Data-Recovery#_data_recovery).

If you anticipate a challenging rebase, you can also preemptively create a temporary branch in the submodule or note down the commit hash before starting the rebase.
This way, you know for sure that you can get back to a known state if it goes wrong.

#### Reallocate your changes

Sometimes the original commits aren't worth recovering, only the sum total of all the changes you made.
Then, you can create new commits to try the rebase again.

1. In the submodule, `git checkout -B bad` to save your current state as the branch `bad`.
1. In the outer repository, check out the unchanged patch files.
1. Run `git apply -f` to apply the patch files to the submodule, changing the submodule's `HEAD`.
1. In the submodule, `git checkout bad -- .` to copy the changes from the `bad` branch into the index (and working directory).
1. Split the staged changes into your desired commits.
1. Try the rebase again.

The [Reset Demystified](https://git-scm.com/book/en/v2/Git-Tools-Reset-Demystified) chapter of the Pro Git book may be helpful to understand the state of the Git repository, the index, and the working directory during each step of the recovery process.

## Fix up patch files after a submodule update

Every so often, you need to update your submodule to the latest version of the upstream repo.
Expand All @@ -53,17 +98,20 @@ The error may look like this:
error: patch failed: src/[...].go:329
```

To fix this, follow the process to make changes to a patch file. While running `git go-patch apply`, you will see the patch failure error appear, with extra instructions about how to use `git am` to resolve it. Then:
To fix this, follow the first two steps of the process to make changes to a patch file.
While running `git go-patch apply`, you will see the patch failure error appear, with extra instructions about how to use `git am` to resolve it.
Then:

1. Make sure your terminal is inside the submodule.
1. Resolve the conflict. There are several ways:
1. Run `git am -3`. This performs a 3-way merge, and leaves merge conflict markers in the files for manual or tool-assisted fixing.
1. Run `git am --reject`. This creates a `.rej` file for each file that couldn't be patched, containing the failed chunks for you to apply manually.
1. Use your IDE, Git GUI, or another graphical merge tool to resolve the conflict. An `am` conflict behaves much like a `merge` conflict.
1. Redo the change from scratch.
1. See [`git am` documentation](https://git-scm.com/docs/git-am) for more information.
1. Stage your fixes.
1. Run `git am --continue` to create the fixed-up commit.
1. If there are more conflicts, go back to step 2.
1. If there are more conflicts, go back to step 2. (The `git am --continue` command will tell you.)
1. Run `git go-patch extract` to save the fixes to your repository's patch files.

When creating a commit with the fixed patch files, make sure not to include the submodule change.
Expand All @@ -76,7 +124,7 @@ The next dev to work on resolution can then check out the WIP branch and run `gi

## Init submodule and apply patches with a fresh clone

`git go-patch apply` understands how to set up a repo's submodules, so you can use it to make it easy for a dev to look at your fork's modifications after a fresh clone:
`git go-patch apply` understands how to set up the patched submodule, so there's no need to run `git submodule [...]` commands after a fresh clone or checkout:

```sh
git clone https://example.org/my/project proj
Expand All @@ -85,7 +133,8 @@ git go-patch apply
# Proj and proj's submodule are now ready to examine.
```

However, in build scripts, you may want to use traditional Git commands to avoid the dependency on our tool in production environments. We suggest:
However, in build scripts, you may want to use traditional Git commands to avoid the dependency on the `git-go-patch` tool in production environments.
We suggest:

```
git submodule update --init --recursive
Expand Down
Loading