Reputation: 4335
This question may be duplicate but I didn't find an exactly same one.
In our QA team's git repository I often find the test cases I added before was lost. and from the main branch's histroy I cannot find my commit anymore.
The root cause was once found when I compare my personal branch's log and the main branch's log, and it was someone's force push, and the guy admitted that he's not very familiar with git merge but hurried to push so used force option.
But what if there's no such branch that backed up these commit history? and every team member has pulled after some days so that commit history disappears forever.
And even if there's such a backup branch, it is very time consuming to compare and get to know who did the force push.
Is there some ways to get the force push log? please note as a normal employee I'm not the owner/admin of the git server, but I care about my commits and want the ones who delete them to be warned.
Upvotes: 3
Views: 9922
Reputation: 4679
This rather "hacky" solution may be helpful in finding force-pushed amend commits, though I am not sure whether it would work in all possible situations.
Assuming that you are on the remote (bare) repository, you could print out all commits stored in the reflog of a particular branch and compare them to the commits of a normal git log
. The difference should give you the force push commits.
Note that for bare repos, reflogs must be enabled.
As an example, assume that you have committed to master, pushed, then amended and force pushed - twice. Then you would have four commits in total (as seen by the reflog), but only two in your actual log:
$ git log -g master | grep ^commit # Show reflog of master
commit 3f52cea357aaa6ba9db86c1526b025a7ee2906c1 (refs/remotes/origin/master, refs/heads/master)
commit 5afa0cfe6e16d4d45088aeb226ed052a5ad72b87
commit 0334c6f8ba13c1465c855cf0b7cf6c79df487740
commit 8bb40a9d6da838e151c8653b8d6be2b7afeb1902
$ git log master | grep ^commit # Show log of master
commit 3f52cea357aaa6ba9db86c1526b025a7ee2906c1 (refs/remotes/origin/master, refs/heads/master)
commit 0334c6f8ba13c1465c855cf0b7cf6c79df487740
$ git reflog # for reference - HEAD@{0, 2} were force pushes
3f52cea (HEAD -> refs/heads/master) HEAD@{0}: push
5afa0cf HEAD@{1}: push
0334c6f HEAD@{2}: push
8bb40a9
In bash, I can then show the diff between the two (using process substitution):
$ diff <(git log -g master | grep ^commit) <(git log master | grep ^commit) | grep "^<"
< commit 5afa0cfe6e16d4d45088aeb226ed052a5ad72b87
< commit 8bb40a9d6da838e151c8653b8d6be2b7afeb1902
I am diff'ing the two outputs above and piping to grep
, such that I can see the commits that were amended.
Upvotes: 1
Reputation: 14030
You won't be able to get the force push history, but you will at least be able to spy your own commits that were clobbered. From your local clone, use git fsck
:
(master) :~/repo$ git fsck --lost-found
Checking object directories: 100% (256/256), done.
dangling blob 6edc1e217eaab8f72f67bcec2e4d1dfde299971e
dangling commit 9847c5942bf477989112ece202988bc3f8caad05
(master) :~/repo$ git merge 9847c59
// ... conflicts likely appear ... //
From here, you could resolve conflicts and push back your changes where appropriate. This doesn't work if you're on a different system from where you made the commit, and even then, your local commits may be lost due to pruning if enough time has passed.
Upvotes: 1
Reputation: 45679
There is no really reliable way in git
itself to retrieve that sort of information. (It is possible that some git hosting software might preserve reflog-like records of force pushes, but I'm not aware of any; if you use a particular hosting package you could consult its documentation.)
Apart from finding a clone that hasn't accepted the new history, you also might be able to get the info you need from the reflogs of a clone even after it has accepted the new history - but reflogs are local and temporary, so this is not guaranteed.
(Depending how your remote is hosted, you might also be able to refer to its reflogs, if it retains them and if you can access them. But even when all those ifs break your way, there's no guarantee, because reflogs are temporary.)
This is why git push -f
is a dangerous tool; and at the risk of being blunt, if a developer's understanding of git has not progressed to the point where they understand how dangerous it is, then that developer should not be granted access to force push to refs that are shared with other developers.
You can configure a git remote to reject all non-fast-forward pushes (even if forced); see receive.denyNonFastForwards
in the git config
docs.
If you need finer-grained control, you again would have to rely on the hosting software to provide it.
Upvotes: 4