1

I cannot find a way to delete a targeted commit from the log. Documentation about deleting commits either just resets a pointer using reset (which does not delete anything, it just resets pointers), or rebase, which creates a new structure of some sort at the deleted commit. The hash of the targeted commit still appears. There may be old documentation out there related to

git rebase -i fork1~1 fork1~3

because in older messages, it states to delete a line in the editor, that is, the line corresponding to the targeted commit. When I get into the interactive editor, one of the choices is "drop", which it says removes the commit. However, I have not successfully removed any commits in the sense that they disappear from the log. I insert the word drop, and it creates some sort of fork-looking thing in the log output. But I can still see the hash of the commit I am trying to remove. Simply put, I want to identify a hash to remove and have it no longer appear in the log.

So, the idea here is to drop 1bc7112:

*   4518859 (refs/stash) WIP on fork3: 8c438a9 Added first.bsh back in
|\
| * 1bc7112 index on fork3: 8c438a9 Added first.bsh back in
|/
* 8c438a9 Added first.bsh back in
* eef828f (HEAD -> fork4) Removed using git rm
* c21cda0 Third change.
matt
  • 515,959
  • 87
  • 875
  • 1,141
Anthony Mannucci
  • 277
  • 2
  • 12
  • 1
    The fork-looking thing sounds about right, as `rebase --interactive` rewrites history, so every commit after the ones you change get a new hash. Check this out for more details on what your.iotions are: https://stackoverflow.com/a/46724280/1148483 – Andrei Mustata May 30 '20 at 06:50
  • The commits you will see in a Git repository depends on what choices you make as you run commands that look at commits in that repository. What command(s) are you using to *view* the commits? – torek May 30 '20 at 13:34
  • hist = log --all --graph --decorate --oneline – Anthony Mannucci May 30 '20 at 17:18
  • I show the history in this document. I cannot remove anything later than HEAD. [link]https://docs.google.com/document/d/1mr538-w9JnFoJzfO8UIH0AcCGAYIxurC4xPTuDfMeQ4/edit?usp=sharing For example, I have set head to the latest commit, and then executed rebase -i. I try to drop commit 1bc7. It does not go away. I put it on a branch, still no luck – Anthony Mannucci May 30 '20 at 18:00
  • See [matt's answer](https://stackoverflow.com/a/62107882/1256452) for details - what you want is to `git stash drop` the stash, which is commits `4518859` and `1bc7112`. This will also drop the only reference to commit `8c438a9` so that you will only see commits `eef828f` and `c21cda0` on back. – torek May 31 '20 at 00:39

4 Answers4

3

Now that you have posted the log (as a graph), the reason is clear: the commit you want to drop is not part of the history at all. It's being preserved by the stash. The way to delete it is to drop the stash itself.

The graph reveals what an odd duck the stash really is. It is in fact a merge commit; its first parent is the HEAD when you created the stash (because the working tree existed with regard to that HEAD) and its second parent is the entire index at that moment, and the parent of that second parent is the HEAD. The documentation draws it like this:

       .----W
      /    /
-----H----I

The dot is the stash, H is the HEAD, I is the recorded index, and W is the recorded worktree.

So as long as the stash exists, that H commit (the one that was head at the time you stashed) cannot go out of existence.

Meanwhile, the commit you are complaining about isn't even a real commit! It's the frozen snapshot of the Index at the moment you made the stash. It is integral to the stash.

matt
  • 515,959
  • 87
  • 875
  • 1,141
0

reset to older commit: git reset --hard <old commit>

Shamanou
  • 41
  • 4
0

When making a git rebase -i HEAD~X where X is the number of commits to rebase, you can rebase in interactive mode. You'll see (for example) the following options :

pick 0a3e7b9 other commit
pick 7cfa14c commit to remove

# Rebase 04ec4b7..7cfa14c onto 04ec4b7 (2 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

Type i in order to edit, next you can add d or drop, before the commit you want to remove, for example :

d 7cfa14c commit to remove 

Let pick before all other commits, then type esc in order to escape edit mode and :wq in order to save and quit.

Now commit will be removed locally, next push update on remote branch using git push --force origin <remote_branch>, note the --force option, required because of rebase.

NicoM
  • 125
  • 5
  • Thank you. Please see the history at this link. [link]https://docs.google.com/document/d/1mr538-w9JnFoJzfO8UIH0AcCGAYIxurC4xPTuDfMeQ4/edit?usp=sharing. I cannot remove anything later than HEAD, even with interactive rebasing. – Anthony Mannucci May 30 '20 at 18:32
0

That is expected behavior.

Git is basically a simple directed graph where branches are auto-advanced names (aka refs) to commits, and thus a head node in some graph subtree. A reset is one method to change which commit a branch names.

Likewise, when a rebase is performed, changes that result in a different hash calculation result in a distinct commits. Parent hashes are also part of the calculation, which is why dropping a commit affects all descendants. The branch is then updated to point to the new commit tree’s head, while the original commits themselves are not actually removed from the set of all commits and can still be found via the reflog.

After a reset or rebase these outdated (including dropped) commits are “orphans” if and only if they cannot be referenced by any refs+. The commits can still be referenced by commit hash as they still exist on disk; however, if there are no direct refs to these commits, and they are not an ancestor of any refs, they are not expected to show up in the log command.

+Git refs (aka references) include ~branches~, ~tags~, and ~stash entries~.

If commits are not “orphaned”, and thus visible in the normal log, there is a branch or tag that needs to be updated. This also includes remote tracking branches and stash entries. Update and/or remove these refs as relevant. If the branch keeping these commits from being “orphaned” is already pushed and on a mainline .. well, let’s hope that is not the case.


Removing a commit from disk, after it has been made an orphan can be done via the prune command which can delete all orphans. Git normally does periodic GC housekeeping so this is not normally required.

If the commit has already been pushed, this process must be propagated to every repository that now has the change. If this involves force-pushing mainline branches it may be "very annoying" to other developers and/or infeasible, depending on how many other commits are descendants. This should only be done as last resort as commit (and any data therein) is already leaked and a potential dependency of other remote commits.

user2864740
  • 60,010
  • 15
  • 145
  • 220
  • Give the structure at this link, I cannot remove anything later than HEAD. [link]https://docs.google.com/document/d/1mr538-w9JnFoJzfO8UIH0AcCGAYIxurC4xPTuDfMeQ4/edit?usp=sharing – Anthony Mannucci May 30 '20 at 17:54
  • (That link is not public. Might be better _in the question body_ and/or on a gist site anyway.) – user2864740 May 30 '20 at 18:17
  • I have changed priveleges to the link. Thanks for pointing this out. I cannot paste newlines into comments. I will look into gist. – Anthony Mannucci May 30 '20 at 18:26
  • That's why it's good to edit the original question with such useful details - the information will also be readily accessible to others. – user2864740 May 30 '20 at 18:34
  • Like a branch or a tag, a stash will _also_ prevent a commit from being orphaned (basically, any place that allows a commit to be accessed by some name). Remove the stash if it's not needed, or cherry-pick the changes elsewhere, and then remove the stash. This will clean up the graph and simplify the question and describing of the current issue. – user2864740 May 30 '20 at 18:36
  • 1
    Thank you! That's it. The stash was holding things up. – Anthony Mannucci May 30 '20 at 18:37
  • I usually forget all about stash.. I very rarely use it longer than a very quick push-pop (such as around a merge) :-/ My preferred method to dealing with most 'temporary' work is to drop a tag or new branch (if it's the basis for future non-temporary work) and re-base. – user2864740 May 30 '20 at 18:38
  • I would include that information in the original question (showing the log), as such up there might be helpful to others in the future with a similar situation. Then, you can even answer your own question with the specific reason and/or new knowledge :) – user2864740 May 30 '20 at 18:41