top | item 41653389

(no title)

AndrewHampton | 1 year ago

FWIW, I've been using this alias for the past couple years for fixup commits, and I've been happy with it:

> gfx='git commit --fixup $(git log $(git merge-base main HEAD)..HEAD --oneline| fzf| cut -d" " -f1)'

It shows you the commits on the current branch and lets you select one via fzf. It then creates the fixup commit based on the commit you selected.

discuss

order

kccqzy|1 year ago

If it only lets you select one, that's strictly less powerful. What if I want some parts of it into one commit and another parts into another? The `hg absorb` works for this case.

AndrewHampton|1 year ago

Yeah, it's definitely less powerful that what absorb is doing. I wasn't trying to argue that it was equivalent. I just wanted to share a bash one-liner that I've had success with in case others find it helpful.

> What if I want some parts of it into one commit and another parts into another?

Looks like absorb will automatically break out every hunk into a separate fixup commit. My one-liner will create 1 fixup commit for everything that's staged. That's typically what I need, but on the occasions it's not, I use `git add -p`, as kadoban mentioned, to stage exactly what I want for each commit.

atq2119|1 year ago

Then you use `git gui`, which is part of the git distribution itself, or `tig` if TUIs are your thing. I have a key binding for `git commit --squash=%(commit)` in my tig config, so I can interactively select lines or hunks to stage and then the target commit for the squash.

kadoban|1 year ago

That sounds like what `git add -p` is for, stage part of the current changes.

k3vinw|1 year ago

Might be able to use the multimode flag in the fzf command above and it should let you select more than one using Tab and Shift+Tab.

account42|1 year ago

Couldn't you just use --patch with the alias to achieve that?

psadauskas|1 year ago

I have this one in mine: https://github.com/paul/dotfiles/blob/master/git/.gitconfig#...

    # make a fixup commit for the last time the file was modified
    cff   = "!f() { [ -n $@ ] && git add $@ && git commit --fixup $(git last-sha $@); }; f"
    # Get latest sha for file(s)
    last-sha = log -n1 --pretty=format:%h --grep 'fixup!' --invert-grep
Given a file like `git cff path/to/file.rb`, It'll find the last commit that touched that file, and make a fixup commit for it. Its great for the try-this-change-on-CI cycle: Change the Dockerfile, git cff Dockerfile, push, repeat, without it screwing up because you changed a different file while you were working on it.

mdaniel|1 year ago

It won't matter until it does, but $@ expands arguments into separate words but those expansions are themselves only word-preserved if the $@ is itself quoted. The [ will probably get away with what you want, but its use in $(git add) and $(git last-sha) almost certainly will not

  $ cat > tmp.sh <<'FOO'
  for a in $@;   do echo "a=$a"; done
  echo
  for b in "$@"; do echo "b=$b"; done
  echo
  for c in $*;   do echo "c=$c"; done
  echo
  for d in "$*"; do echo "d=$d"; done
  echo
  FOO

  $ bash tmp.sh 'alpha beta' $'charlie\ndelta'
  a=alpha
  a=beta
  a=charlie
  a=delta

  b=alpha beta
  b=charlie
  delta

  c=alpha
  c=beta
  c=charlie
  c=delta

  d=alpha beta charlie
  delta

jonS90|1 year ago

Funny that I've been doing something nearly identical, but with way more boilerplate.

    fzfCommit() {
      local FZF_PROMPT="${FZF_PROMPT:=Commit: }"
      git log --oneline | fzf --border --prompt="$FZF_PROMPT" --height=10 --preview="git show {+1} --color=always" --no-sort --reverse | cut -d' ' -f1 | tr '\n' ' ' | sed 's/[[:space:]]$//';
    }
    function gfixup {
      local commit=$(FZF_PROMPT='Fixup Commit: ' fzfCommit)
      if [[ -z "$commit" ]]; then
        return 1
      fi
      set -x
      git commit --fixup "$commit" --allow-empty > /dev/null || return 1
      git rebase --interactive "$commit"~ --autosquash || return 1
    }

johnnypangs|1 year ago

I’ve been using this:

alias gfixup="git commit -v --fixup HEAD && GIT_SEQUENCE_EDITOR=touch git rebase -i --stat --autosquash --autostash HEAD~2"

From what I understand it does the same thing as this crate for the most part. All I do after is:

git push —force-with-lease

Not sure what you get from the crate otherwise

masklinn|1 year ago

Your alias seems like a completely unecessary complexity. If you want to meld new changes into your branch head you can just alias “git commit --amend”, you don’t need that mess.

Absorb will find the commits to fix up for each change in the working copy, it doesn’t just merge everything into the head.

johnnypangs|1 year ago

I guess the crate version is easier to soft reset?

emersion|1 year ago

With a shell such as fish, one can "git commit --fixup <tab>" and a list of commits will be displayed.

mckn1ght|1 year ago

sounds like how magit lets you create fixup commits in emacs

AndrewHampton|1 year ago

This was 100% my inspiration. I used emacs+magit for years. After switching away from emacs for dev work, I still cracked it open for git interactions for another year or so. Eventually, I moved entirely to the shell with a bunch of aliases to replicate my magit workflow.

masklinn|1 year ago

Worse in fact, since magit lets you fixup, squash, or instafix.