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

restore the original git history #10

Open
milahu opened this issue Mar 9, 2024 · 3 comments
Open

restore the original git history #10

milahu opened this issue Mar 9, 2024 · 3 comments
Assignees

Comments

@milahu
Copy link

milahu commented Mar 9, 2024

continue garycourt/uri-js#95 (comment)

PR restoring git history would be welcome

this is impossible via github


PR from milahu/uri-js fails because kibertoad/toad-uri-js is not a fork of garycourt/uri-js

I've done forking of other libraries in the past, it gives a very bad developer experience, as then all PRs default to targetting parent repositories, ending up in creating accidental PRs

main...milahu:uri-js:master

There isn’t anything to compare.
We couldn’t figure out how to compare these references, do they point to valid commits?


PR from milahu/toad-uri-js fails because the root commit is different, aka "not related git histories"

main...milahu:toad-uri-js:main

There isn’t anything to compare.
kibertoad:main and milahu:main are entirely different commit histories.


so as i said...

please help yourself

here is an updated script, to also preserve the committer data

restore-git-history.sh
#!/usr/bin/env bash

set -e
set -x

git clone https://github.com/garycourt/uri-js
mv uri-js toad-uri-js
cd toad-uri-js
git branch -M master main || true
git remote add fork https://github.com/kibertoad/toad-uri-js
git fetch fork main
git worktree add fork-main fork/main

# this is the first commit in the fork
# git log --format=fuller
cat >/dev/null <<'EOF'
commit ab2a6cab3b60120db334118640f0417d0c7a7f52
Author:     Igor Savin <[email protected]>
AuthorDate: Fri Feb 9 20:40:20 2024 +0200
Commit:     GitHub <[email protected]>
CommitDate: Fri Feb 9 20:40:20 2024 +0200

    Migrate to vitest (#1)
EOF

git_commit() {
  local an="$1"
  local ae="$2"
  local ad="$3"
  local m="$4"
  GIT_AUTHOR_NAME="$an" GIT_AUTHOR_EMAIL="$ae" GIT_AUTHOR_DATE="$ad" \
  GIT_COMMITTER_NAME="$an" GIT_COMMITTER_EMAIL="$ae" GIT_COMMITTER_DATE="$ad" \
  git commit -m "$m"
}

an="Igor Savin"
ae="[email protected]"

git rm -rf dist/
git_commit "$an" "$ae" "Fri Feb 9 20:20:00 2024 +0200" "rm -rf dist/"

git -C fork-main checkout fork/main~12
cp fork-main/.gitignore .gitignore
git add .gitignore
git_commit "$an" "$ae" "Fri Feb 9 20:30:00 2024 +0200" "up .gitignore"

# now there should be no difference
# -> ready for cherry-pick
git_diff=$(git diff main~0 fork/main~12)
if [[ "$git_diff" != "" ]]; then
  echo "error: diff is not empty:"
  echo "$git_diff"
  exit 1
fi



# git-cherry-pick-preserve-committer.sh

# bash script to modify committer after git cherry-pick

# either to preserve the original committer
# or to use author as committer
# similar to git rebase --committer-date-is-author-date

#     #echo 'format = "%an\n%ae\n%at\n%ad"' # committer is author
#     echo 'format = "%cn\n%ce\n%ct\n%cd"' # preserve committer

set -e

# preserve committer in "git cherry-pick"

function git_cherry_pick_preserve_committer() {

  # filter commits by range of the "git cherry-pick"
  local head_before_cherry_pick=$(git rev-parse HEAD)
  echo "head_before_cherry_pick: $head_before_cherry_pick"

  # -x: append "(cherry picked from commit ...)" to the original commit message
  local args=(git cherry-pick -x "$@")
  echo -n "running:"; printf " %q" "${args[@]}"; echo
  "${args[@]}"

  # run "git filter-repo" to postprocess the "git cherry-pick"

  # Python code body for processing commit objects
  commit_callback=$(
    #echo 'print("locals", locals())'

    echo 'message_lines = commit.message.split(b"\n")'
    #echo 'print("message_lines", repr(message_lines))'
    echo 'try:'
    echo '  picked_from = message_lines[-2].decode("ascii")'
    echo 'except IndexError:'
    echo '  return'
    echo 'if not picked_from.startswith("(cherry picked from commit "):'
    echo '  return'

    # print newline after "Parsed 123 commits"
    #echo 'print()'

    #echo 'print("message_lines", repr(message_lines))'
    echo 'assert len(picked_from) == 68, f"unexpected picked_from: {repr(picked_from)}"'
    echo 'picked_from = picked_from[27:-1]'

    #echo 'for a in ["author_date", "author_email", "author_name", "message", "branch", "id", "old_id", "original_id", "parents", "type"]:'
    #echo '  print(f"commit.{a}", repr(getattr(commit, a)))'

    #echo 'print("picked_from", repr(picked_from))'

    # _do_not_use_this_var is passed via callback_metadata
    # lets use it! :P
    # we only need repo_filter._repo_working_dir
    # 'commit_rename_func': <bound method RepoFilter._translate_commit_hash of <git_filter_repo.RepoFilter object at ...>>
    echo 'repo_filter = _do_not_use_this_var["commit_rename_func"].__self__'
    #echo 'print("repo_filter", repo_filter)'

    if false; then
    # filter commits by range of the "git cherry-pick"
    echo "head_before_cherry_pick = '$head_before_cherry_pick'"
    echo 'args = ["git", "merge-base", "--is-ancestor", head_before_cherry_pick, commit.original_id]'
    #echo 'print("args", repr(args))'
    echo 'proc = subproc.run(args, cwd=repo_filter._repo_working_dir)'
    echo 'if proc.returncode == 1:'
    echo '  return'
    fi

    #echo 'format = "%an\n%ae\n%at\n%ad"' # committer is author
    echo 'format = "%cn\n%ce\n%ct\n%cd"' # preserve committer

    echo 'args = ["git", "show", "-s", f"--format=format:{format}", picked_from]'
    #echo 'print("args", repr(args))'
    echo 'proc = subproc.Popen(args, stdout=subprocess.PIPE, cwd=repo_filter._repo_working_dir)'
    echo 'lines = proc.stdout.read().splitlines()'
    echo 'if len(lines) != 4:'
    echo '  print("lines", repr(lines))'
    echo '  raise Exception(f"not found picked_from commit {picked_from}")'
    echo 'commit.committer_name = lines[0]'
    echo 'commit.committer_email = lines[1]'
    echo 'commit.committer_date = lines[2] + lines[3][-6:]' # timestamp + timezone

    echo 'message_lines = message_lines[:-2]' # remove "cherry picked from" line
    echo 'commit.message = b"\n".join(message_lines)'
    #echo 'print("commit.message", repr(commit.message))'
  )

  # preserve-commit-hashes
  # fix: fatal: bad object xxx
  # git-filter-repo patches hashes in commit.message

  git filter-repo \
    --force \
    --preserve-commit-hashes \
    --commit-callback "$commit_callback" \
    --refs "$head_before_cherry_pick..HEAD"

}

#git cherry-pick fork/main~12..fork/main
git_cherry_pick_preserve_committer fork/main~12..fork/main



# use author date as committer date
# github shows only the committer date
#git rebase a1acf730b4bba3f1097c9f52e7d9d3aba8cdcaae --committer-date-is-author-date

# undo the cherry-pick
#git reset --hard main~12

git tag 5.0.0 main~4

git tag 5.0.1 main~0

echo "done. verify:"
echo "git -C toad-uri-js/ log --format=fuller"

... then git push --force

@kibertoad
Copy link
Owner

thanks, I appreciate the instructions. was too swamped to do it yet, but I will get back to it ASAP

@kibertoad kibertoad self-assigned this Mar 12, 2024
@milahu
Copy link
Author

milahu commented Apr 5, 2024

push

come on, this is low hanging fruit, this takes 5 minutes

@kibertoad
Copy link
Owner

thank you for the reminder, I will try to do this over the weekend

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants