我有一个用作文件夹同步系统的git存储库:每当我在便携式计算机,个人计算机或移动设备中更改文件中的内容时,更改都会自动提交。没有分支,单个用户。
这会导致大量提交,例如每天50次。我想编写一个bash cron脚本来自动执行历史记录压缩,每天只提交一次,与评论无关,但保留日期。
我尝试了git-rebase -i SHA~count
,但是我不知道如何自动执行该过程,即选择第一个提交并压缩其他计数提交。
有什么建议吗?
我写关于查找日期的第一个SHA的bash并合并提交的计数没有问题,对此进行一些循环将达到目的:
git log --reverse|grep -E -A3 ^commit| \
grep -E -v 'Merge|Author:|--|^$'|paste - -| \
perl -pe 's/commit (\w+)\s+Date:\s+\w+\s+(\w+)\s+(\d+).+/\2_\3 \1/'
答案 0 :(得分:2)
根据我的理解,您打算按照以下方式做些事情:
#!/bin/bash
FIRST_COMMIT_HASH_TODAY="$(git log --since="1 days ago" --pretty=format:%H | tail -n 1)"
git reset --soft ${FIRST_COMMIT_HASH_TODAY}^
git commit -m "Squashed changes for $(date +%F)"
即。
一个警告语 ...请注意,现在您正在有效地重写历史记录。您不能再只是git pull
同步更改,因为如果客户端存储库仍具有原始提交历史记录,而服务器具有重写的历史记录,
您将得到类似:
Your branch and 'origin/master' have diverged,
and have 50 and 1 different commit(s) each, respectively.
如果要处理整个历史记录,一种方法是使用git filter-branch的某些变体。我在下面放了一个示例方法,但是这种方法有很多缺点,因此您可能需要对其进行一些改进。
弱点/特征:
示例命令:
LATEST_TREE=$(git rev-parse HEAD^{tree}) git filter-branch --commit-filter '
# $3 = parent commit hash (if commit has at least one parent)
if [ -z "$3" ]
then
# First commit. Keep it.
git commit-tree "$@"
elif [ "$1" == "$LATEST_TREE" ]
then
# Latest commit. Keep it.
git commit-tree "$@"
else
PREVIOUS_COMMIT_COMMITTER_DATE="$(git log -1 --date=raw --pretty=format:%cd $3)"
PREVIOUS_COMMIT_COMMITTER_DATE_NO_TIMEZONE="$(echo $PREVIOUS_COMMIT_COMMITTER_DATE | egrep -o "[0-9]{5,10}")"
GIT_COMMITTER_DATE_NO_TIMEZONE="$(echo $GIT_COMMITTER_DATE | egrep -o "[0-9]{5,10}")"
SECONDS_PER_DAY="86400"
if [ $(expr $GIT_COMMITTER_DATE_NO_TIMEZONE - $PREVIOUS_COMMIT_COMMITTER_DATE_NO_TIMEZONE) -gt $SECONDS_PER_DAY ]
then
# 24 hours elapsed since previous commit. Keep this commit.
git commit-tree "$@"
else
skip_commit "$@"
fi
fi' HEAD
如果您有一个命令要提取要保留的提交的提交哈希,也许您可以获取所有这些提交的根树哈希,并将它们存储到单独的文件中。然后,您可以更改提交筛选条件,以检查“当前的根树哈希是否存在于所需的根树哈希文件中?”而不是“自上一次提交以来已经过了24小时?”。 (不过,这会放大我上面提到的“通过根树哈希识别提交”问题,因为它适用于所有提交,而不仅仅是最新提交)
答案 1 :(得分:0)
如果您有想要返回的提交数量,则可以使用git reset --soft
然后进行新的提交,例如
COMMIT_COUNT=$(git log --pretty=oneline --since="1 days" | wc -l)
git reset --soft HEAD~$COMMIT_COUNT
git commit -m "Today's work"
答案 2 :(得分:0)
我分享基于Alderath建议的结果:我使用git filter-branch
来解析历史记录并保留当天的最后一次提交。 git log
上的第一个循环将需要保留的提交时间戳(一天中的最后一个)写入临时文件;然后使用git filter-branch
,我只保留文件中包含时间戳的提交。
#!/bin/bash
# extracts the timestamps of the commits to keep (the last of the day)
export TOKEEP=`mktemp`
DATE=
for time in `git log --date=raw --pretty=format:%cd|cut -d\ -f1` ; do
CDATE=`date -d @$time +%Y%m%d`
if [ "$DATE" != "$CDATE" ] ; then
echo @$time >> $TOKEEP
DATE=$CDATE
fi
done
# scan the repository keeping only selected commits
git filter-branch -f --commit-filter '
if grep -q ${GIT_COMMITTER_DATE% *} $TOKEEP ; then
git commit-tree "$@"
else
skip_commit "$@"
fi' HEAD
rm -f $TOKEEP