git-revise icon indicating copy to clipboard operation
git-revise copied to clipboard

Idea: revise the last commit that changed the files in the index

Open chris-morgan opened this issue 4 years ago • 7 comments

I often want to revise the last commit that changed the file or files in the index.

I had been doing this manually until today, but I finally got fed up with it enough to make a simple alias.

As an alias (add to .gitconfig):

[alias]
	revise-most-recent-commit-that-touched-file = "!f() { if [ $# -eq 0 ]; then REV=\"$(git status --porcelain --untracked-files=no | sed '/^ /d;s/^.. //' | xargs -n1 git rev-list -1 HEAD --)\"; NUM_REVS=\"$(echo \"$REV\" | wc -l)\"; if [ $NUM_REVS -ne 1 ]; then >&2 echo Files in the index were not all last modified in the same commit; exit 1; fi; else REV=\"$(git rev-list -1 HEAD -- \"$1\")\"; shift; fi; echo git revise \"$REV\" \"$@\"; }; f"

Reformatted as a standalone script:

#!/bin/bash
if [ $# -eq 0 ]; then
	REV="$(
		git status --porcelain --untracked-files=no |
			sed '/^ /d;s/^.. //' |
			xargs -n1 git rev-list -1 HEAD --
	)"
	NUM_REVS="$(echo "$REV" | wc -l)"
	if [ $NUM_REVS -ne 1 ]; then
		>&2 echo Files in the index were not all last modified in the same commit
		exit 1
	fi
else
	REV="$(git rev-list -1 HEAD -- "$1")"
	shift
fi
git revise "$REV" "$@"

This script is not robust (I doubt it handles things like uncommitted files properly), but it’s good enough for me.

I have created this issue because I think this would be useful functionality to upstream into git-revise, e.g. git revise --last-commit-for-file=… (with the files defaulting to all the files in the index).

A better and safer version of this would allow users to specify an acceptable range of commits to revise (I’ve hardcoded HEAD here, but things like @{u}.. and master.. would be useful).

Another power-user feature would be to be able to revise different commits for each file in the index (rather than just bailing as I’ve written here). The alternative is adding each file and revising, one by one (or by as many files as are in each commit, anyway). This functionality would definitely save me time occasionally.

chris-morgan avatar May 29 '20 11:05 chris-morgan

This is basically git absorb, I've wanted that functionality as well

Manishearth avatar May 29 '20 14:05 Manishearth

I think a good path forward here would be to make PRs to https://github.com/tummychow/git-absorb to make it possible to use to implement this functionality in git-revise (i.e. git-revise queries git-absorb to figure out what changes need to be made)

Manishearth avatar May 29 '20 16:05 Manishearth

I'd never head of git absorb, thanks for the tip! Until now my workflow has been to git add -p, add every hunk one at a time using a homegrown commit script that marks it as a fixup for the last commit that touched those line numbers, then rebasing the whole thing manually.

Looking over the usage, wouldn't it make more sense to setup git absorb to call-out to git revise than the other way around?

alerque avatar May 29 '20 16:05 alerque

That can also work

Manishearth avatar May 29 '20 16:05 Manishearth

I use git absorb && git revise --autosquash all the time – I don't see how this can be improved

odnoletkov avatar May 29 '20 23:05 odnoletkov

Oh, git absorb sets up fixup commits? Neat!

I was under the impression it directly did the rebase

Manishearth avatar May 30 '20 05:05 Manishearth

git autofixup is another tool that's very similar to git absorb

krobelus avatar May 30 '20 18:05 krobelus