How to check if upstream's HEAD/latest commit is present in forked repo? - bash

My thought is that, in order to automatically fetch updates only if upstream has pushed some commits, I should check its hashes.
2 ways, I could do is that to check the logs or use rev-list something like below:
# this fetches top 30 commits from forked repo
git rev-list -n 30 main
# this also does the same but not limited to 30
git log --format='%H'
I'm finding it difficult to compare the hashes as I'm failing to fetch more than 1 commit from forked repo.
Explained my approach below:
git remote add upstream https://github.com/upstream/upstream.git
git fetch upstream --tags
upstream_commit="$(git rev-parse upstream/main)"
echo "Upstream commit: ${upstream_commit}"
# This should store 30 recent commit hashes as an array AFAIK
forked_commits=($(git rev-list -n 30 main))
# another I tried to put forloop is this:
# for forked_commit in "$forked_commits[#]"; do
for forked_commit in $(git log --format='%H'); do
# but prints only the top most element and exits the loop
echo "$forked_commit"
if [ "$upstream_commit" == "$forked_commit" ]; then
has_new_commits=false
else
# since I've added my commits on top, if condition fails and this always returns true
has_new_commits=true
fi
done
if [ "${has_new_commits}" ]; then
git checkout main
git rebase upstream/main
git push -f origin main
echo "Rebase successful!"
else
echo "No commits to be synced!"
fi

Ok, I did many mistake that were minor.
Array stuff didn't work. I was supposed to put them directly within the forloop.
Next mistake I never validated them properly. i.e., even if the hash was found, it never exited.
Using [ $has_new_commits ]; then is wrong. I should be using [ $has_new_commits == "true"]; then instead.
Corrected code:
git remote add upstream https://github.com/upstream_repo/upstream.git
git fetch upstream --tags
upstream_commit="$(git rev-parse upstream/main)"
for forked_commit in $(git rev-list -n 20 main); do
if [ $upstream_commit != $forked_commit ]; then
has_new_commits=true
continue
else
has_new_commits=false
break
fi
done
if [ $has_new_commits == "true" ]; then
echo "New commits found!"
else
echo "No commits to be synced!"
fi

Related

How can I tweak this git log command / bash script to include deleted commits from deleted branches that git reflog should still know about?

So I have this little bash script to output a csv file that shows all my commit history from a specific month.
function make-git-report() {
if [ "$1" != "" ]
then
local month=$1
else
local month=$(date +%m)
fi
local year=$(date +%Y)
local nextYear=$year
local nextMonth=$((month+1))
if [ "$nextMonth" = "13" ]
then
local nextMonth="01"
local nextYear=$((year+1))
fi
local start="$year-$month-01"
local end="$nextYear-$nextMonth-01"
rm -f log.csv
git --no-pager log \
--author="Evert" \
--since="$start" \
--before="$end" \
--branches --remotes --tags --no-decorate --no-merges \
--pretty=format:'§"%ch";"%an";"%s";' --stat | \
grep -v \| | tr -s "\n\n" | tr "\n" '"' | tr "§" "\n" > templog.csv
echo "\nDate;Author;Message;Changes" >> templog.csv
tac templog.csv > log.csv
rm -f templog.csv
}
But I just realized that if a branch is deleted during that month, and it was only merged using a squash merge, then a lot of commits will not show up in my csv file.
I've understood that git reflog will somehow still contain that missing data, but I'm not sure how to merge that information into the output from git log while graciously avoiding things like duplicate entries and maybe more unwanted results that I now can't think of.
Can anybody give me a little hint, a push in the right direction, on how to solve this?
You can't use the reflog to reliably get information about deleted branches :
the log gets updated only if you see the commit at all
e.g : if you take 2 days off, your local repo will have no trace of what happened during those two days ...
two clones of the same repo will not have the same reflog
the reflog will also contain information about rebased/cherry-picked commit (and possibly add duplicate information on the log you are trying to build ?)
the reflog for HEAD will stay around, but reflog for specific branches/remote branches will get deleted if said branch is deleted too
etc ...
I guess you describe a workflow based around a known git central service (github ? gitlab ? azure devops ? ...) where your branches get merged via pull requests.
Each of these services keep a link to the branch of its pull requests :
a generic way to see that is to run git ls-remote, and see what refs are listed (you should see a list of refs/pull/xxx/... or refs/merge-requests/xxx/... or ...)
and read the documentation for said service
You can fetch these pull requests :
# with this refspec : all pull requests will be stored under origin/pull/*,
# as if they were remote branches
git fetch origin +refs/pull/*:refs/remotes/origin/pull/*
# or you may choose to store them in a different set of refs :
git fetch origin +refs/pull/*:refs/pull/*
You may also use the API of said service to check the state of a pull request.
Combining the information above, you may choose, pull request by pull request, whether you should add pull/xyz/head to the list of refs in your git log command or not.
note that, if your branch are squash merged, the "merge commits" will actually not be merge commits, so you would have to choose another way than --no-merges to exclude them from your log (for example : print the commits sha and skip the ones that are known to be a merge request result)

How to get branch name in a Github Action Shell script

I'm trying to create an output to use later in the job.
However, for some reason, the BRANCH env variable which I'm getting to be the GITHUB_REF_NAME is an empty string, which according to the docs, should be the branch.
Also using the variable directly produces the same result.
- name: Set Terraform Environment Variable
id: set_tf_env
env:
BRANCH: ${{env.GITHUB_REF_NAME}}
run: |
if [ "$BRANCH" == "dev" ]; then
run: echo "::set-output name=TF_ENV::dev"
elif [ "$BRANCH" == "prod" ]; then
run: echo "::set-output name=TF_ENV::prod"
else
echo "Branch has no environment"
exit 1
fi
So after a bit of more research and thanks to the comments, I discovered the reason why it wasn't working.
It was because I was triggering a GitHub action in a Pull Request, something I failed to mention.
So what I ended up using was:
github.event.pull_request.head.ref

How do I write a hook around mercurial's "push creates new remote head"?

I want to make a hook that when someone is pushing to the remote, if they get the abort: push creates new remote head error message, the hook will try to merge the remote and local head (if easy merge i.e. no conflicting files) and push again.
How can I do this? I tried adding a hook on pre-push, but I don't know how to get just the remote's head hash for the current branch.
Here is what I have been trying, though it is not polished.
currbranch=$(hg branch)
hg pull
numheads=$(hg heads --template "." $currbranch)
if test ${#numheads} -gt 1; then
echo "Merge needed."
head1=$(hg heads --template "{node}\n" $currbranch | head -n 1)
head2=$(hg heads --template "{node}\n" $currbranch | tail -n 1)
overlap=$((hg status --change $head1 --no-status ; hg status --change $head2 --no-status) | sort | uniq --repeated)
if [ -z "$overlap" ]; then
echo "Attempting automatic merge..."
hg merge "$head1" # Fails when merging the wrong head
hg merge "$head2" # But how do we know which one is wrong?
hg commit -m "Merge"
echo "Completed."
else
echo "Cannot automatically merge"
exit 1
fi
fi
To be clear, what doesn't work ahead is merging both heads. How can I know which head is local and which head is remote?
Also, is this the right hook to use?
You can try to add and use remotenames extension (it's rather old and not actively maintained since 2018, but may work) in order to have all remote peers named in your repo (in this case you'll know names of remote head(s) after pull)
You can (before pull) check presence of head in incoming set of changesets, smth. like
hg in -r "head()" -T "{node|short}\n" (TBT!)

Git mirroring with bash scripting stuck in 3 for loop

git1 ---> git3 (must use path1)
git2 ---> git4 (must use path2)
git1 can't clone to git4, or git2 can't clone to git3.Everytime it should work as above way.Script start to take git1 it has to be continue and hold next values with this way git1-git3-path1,when first loop finished it should be start second one like that git2-git4-path2
My scratch
A_sources=(git1 git2)
B_destinations=(git3 git4)
C_filename=(path1 path2)
workdir="/home/"
for A in "${A_sources[#]}"; do
for B in "${B_destinations[#]}"; do
for C in "${C_filename[#]}"; do
git clone --mirror "${A}"
cd "${workdir}/${C}"9
git remote set-url --push origin "${B}"
done
done
done
one loop over indexes instead of three nested loops over elements, for example
# ensure the size are equal
(( ${#A_sources[#]} == ${#B_destinations[#]} && ${#B_destinations[#]} == ${#C_filename[#]})) || { echo "arrays sizes are not equals"; exit 1;}
for ((i=0;i<${#A_sources[#]};i+=1)); do
git clone --mirror "${A_sources[i]}"
cd "${workdir}/${C_filename[i]}"9
git remote set-url --push origin "${B_destinations[i]}"
done

Travis-Ci: Check if build is off push or pull request

I want to run a section of the script only when the build is off a push and not a PR. But on build it doesn't go. How can I only run the section when the build is off a push?
if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then
setup_git
commit_website_files
publish_gh_pages
fi
Just use secure environment variables to determine if PR or push. Secure environment variables aren't available in push
if [ "${ghToken:-false}" != "false" ]; then
setup_git
commit_website_files
publish_gh_pages
fi

Resources