-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcg-commit
More file actions
executable file
·707 lines (651 loc) · 24.4 KB
/
cg-commit
File metadata and controls
executable file
·707 lines (651 loc) · 24.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
#!/usr/bin/env bash
#
# Commit changes in the working tree to the repository
# Copyright (c) Petr Baudis, 2005
#
# Commits your changes to the GIT repository. Accepts the commit message
# from `stdin`. If the commit message is not modified the commit will be
# aborted.
#
# Note that you can undo a commit by the `cg-admin-uncommit` command,
# but that is possible only under special circumstances. See the CAVEATS
# section in its documentation.
#
# Commit author
# ~~~~~~~~~~~~~
# Each commit has two user identification fields - commit author and committer.
# By default, it is recorded that you authored the commit, but it is considered
# a good practice to change this to the actual author of the change if you are
# merely applying someone else's patch. It is always recorded that you were the
# patch committer.
#
# The commit author is determined by examining various sources in this order:
#
# * '--author' (see OPTIONS)
#
# * 'GIT_AUTHOR_*' (see ENVIRONMENT)
#
# * Configuration file: you can insert this to '.git/config' or '~/.gitconfig':
#
# [user]
# name = "Your Name"
# email = "your@email.address.xz"
#
# * System information: The author name defaults to the GECOS field of your
# '/etc/passwd' entry, which is taken almost verbatim. The author email
# defaults to your 'username@hostname.domainname' (but you should change this
# to the real email address you use if it is any different).
#
# OPTIONS
# -------
# --amend:: Amend the last commit (dangerous: see `cg-admin-uncommit`)
# Amend the last commit with some additional stuff; this will use your
# current working copy as the new commit "contents" and otherwise
# have similar effects as -c HEAD; the new commit will _replace_ the
# current HEAD - which means that you should read `cg-admin-uncommit`
# caveats section. If you want to adjust the log message or authorship
# information, use it with combination with the '-e' option.
#
# --author AUTHOR_STRING:: Set the author information according to the argument
# Set the commit author information according to the argument instead
# of your environment, .git/author, or user information.
#
# The 'AUTHOR_STRING' format is `Author Name <author@email> Date`. The
# author name and date is optional, only the email is required to be
# always present (e.g. '--author "<pasky@ucw.cz>"' will use the current
# date and the real name set for your system account (usually in
# the GECOS field), but a different email address).
#
# -c COMMIT_ID:: Copy author info and commit message from COMMIT_ID
# Copy the commit metainformation from a given commit ID (that is, only
# the author information and the commit message - NOT committer
# information and NOT the commit diff). This option is typically used
# when replaying commits from one lineage or repository to another - see
# also `cg-patch -C` (if you want to apply the diffs as well).
#
# -m MESSAGE:: Specify commit message
# Specify the commit message, which is used instead of starting
# up an editor (if the input is not `stdin`, the input is appended
# after all the '-m' messages). Multiple '-m' parameters are appended
# to a single commit message, each as separate paragraph.
#
# -M FILE:: Read commit message from a file
# Include commit message from a file (this has the same effect as if
# you would cat it to stdin).
#
# -e:: Force message editing of messages given with -m
# Force the editor to be brought up even when '-m' parameters were
# passed to `cg-commit`.
#
# -E:: Force message editing and commit the result
# Force the editor to be brought up and do the commit even if
# the default commit message is not changed.
#
# -f:: Force commit when no changes has been made
# Force the commit even when there's "nothing to commit", that is
# the tree is the same as the last time you committed, no changes
# happened. This also forces the commit even if committing is blocked
# for some reason.
#
# -N:: Only update the cache
# Don't add the files to the object database, just update the caches
# and the commit information. This is for special purposes when you
# might not actually _have_ any object database. This option is
# normally not interesting.
#
# --no-hooks:: Do not call any commit hooks
# Do not call any commit hooks during the commit.
#
# -p, --review:: Show and enable editing of changes being committed
# Show changes being committed as a patch appended to the commit message
# buffer. Changes made to the patch will be reapplied before completing
# the commit. This implies '-e'.
#
# --push[=BRANCH]:: Immediately push the commit to a remote branch
# Push the new commit to a remote branch (defaults to 'origin') right
# after commiting it. Furthermore, the push is done in a transactional
# way so that in case it fails, nothing gets committed locally either.
# Note that you need to update your branch against the remote branch
# before committing so that the remote branch contains no commits
# not contained in your branch.
#
# The preferred workflow is that you first commit your changes, then
# do an update from the remote branch, then push to the remote branch.
# This has the advantage that the act of merging is explicitly recorded,
# reducing the danger of inadverent loss or damage of some changes during
# the merge and making the history reflect the reality more accurately.
# Also, it makes for nicer gitk diagrams. ;-) In this workflow, this
# '--push' switch does not come into play. Use it only if you know
# exactly why you do not want to do the above.
#
# This flag is not supported when committing merges since the recovery
# in case of push failure would be too complicated. Please resort to
# the commit-before-update workflow in that case - you are already doing
# a merge anyway.
#
# -q:: Be very very quiet
# Be quiet in case there's "nothing to commit", and silently exit
# returning success. In a sense, this is the opposite to '-f'.
#
# -s, --signoff[=STRING]:: Automatically append a sign off line
# Add Signed-off-by line at the end of the commit message.
# Optionally, specify the exact name and email to sign off with by
# passing: `--signoff="Author Name <user@example.com>"`.
#
# FILES
# -----
# $GIT_DIR/commit-template::
# If the file exists it will be used as a template when creating
# the commit message. The template file makes it possible to
# automatically add `Signed-off-by` line to the log message.
#
# $GIT_DIR/hooks/commit-post::
# If the file exists and is executable it will be executed upon
# completion of the commit. The script is passed two arguments.
# The first argument is the commit ID and the second is the
# branchname. A sample `commit-post` script might look like:
#
# #!/bin/sh
# id=$1
# branch=$2
# echo "Committed $id in $branch" | mail user@host
#
# $GIT_DIR/hooks/post-commit::
# If the file exists and is executable it will be executed upon
# completion of the commit. It is passed the same arguments and
# called at exactly the same time as the 'commit-post' hook; it
# exists for compatibility with `git-commit`(1). The default
# 'post-commit' hook, when enabled, demonstrates how to send out
# a commit notification e-mail. (Note that `git-commit`(1) calls
# the hook with no arguments.)
#
# ENVIRONMENT VARIABLES
# ---------------------
# See the 'Commit author' section above for details about the name/email/date
# environment variables meaning and default values.
#
# GIT_AUTHOR_NAME::
# Author's name.
#
# GIT_AUTHOR_EMAIL::
# Author's e-mail address.
#
# GIT_AUTHOR_DATE::
# Date, useful when applying patches submitted over e-mail.
#
# GIT_COMMITTER_NAME::
# Committer's name.
#
# GIT_COMMITTER_EMAIL::
# Committer's e-mail address. The recommended policy is not to change
# this, though - it may not be necessarily a valid e-mail address, but
# its purpose is more to identify the actual user and machine
# where the commit was done. However, it is obviously ultimately
# a policy decision of a particular project to determine whether
# this should be a real e-mail or not.
#
# GIT_COMMITTER_DATE::
# This is the date of the commit itself. It should be never
# overridden, unless you know you absolutely need to override it
# (to ensure the commit gets the same ID as another or when
# migrating history around).
#
# EDITOR::
# The editor used for entering revision log information.
#
# CONFIGURATION VARIABLES
# -----------------------
# The following GIT configuration file variables are recognized:
#
# user.author, user.email::
# User credentials. See the "Commit author" section for details.
#
# cogito.hooks.commit.post.allmerged::
# If set to "true" and you are committing a merge, the post-hook will
# be called for all the merged commits in sequence (the earliest first).
# Otherwise, the hook will be called only for the merge commit.
# Developer's documentation:
#
# -C:: Ignore cache
# Make `cg-commit` ignore the cache and just commit the thing as-is.
# Note, this is used internally by 'Cogito' when merging, and it is
# also useful when you are performing the initial commit. This
# option does not make sense when files are given on the command line.
#
# -w FILE:: Do not update ref but save commit id to FILE
# Do not update the HEAD ref with the new commit id, but just
# save the newly created commit id to FILE. Implies '--no-hooks'.
# Testsuite: Partial (used in many tests but a dedicated testsuite is missing)
USAGE="cg-commit [-m MESSAGE]... [-e] [-c COMMIT_ID] [OTHER_OPTIONS] [FILE]... [< MESSAGE]"
. "${COGITO_LIB}"cg-Xlib || exit 1
### XXX: The spaghetti code below got rather messy and convoluted over
### the time. Someone should clean it up. :/ --pasky
load_author()
{
local astr="$1" force="$2"
if [ "$force" -o -z "$GIT_AUTHOR_NAME" ] && echo "$astr" | grep -q '^[^< ]'; then
export GIT_AUTHOR_NAME="$(echo "$astr" | sed 's/ *<.*//')"
fi
if [ "$force" -o -z "$GIT_AUTHOR_EMAIL" ] && echo "$astr" | grep -q '<.*>'; then
export GIT_AUTHOR_EMAIL="$(echo "$astr" | sed 's/.*<\(.*\)>.*/\1/')"
fi
if [ "$force" -o -z "$GIT_AUTHOR_DATE" ] && echo "$astr" | grep -q '[^> ]$'; then
export GIT_AUTHOR_DATE="$(echo "$astr" | sed 's/.*> *//')"
fi
}
if [ -s "$_git/author" ]; then
warn ".git/author is obsolete, use .git/config instead (see the cg-commit docs)"
load_author "$(cat "$_git/author")"
fi
if [ -z "$GIT_AUTHOR_NAME" -o -z "$GIT_AUTHOR_EMAIL" ]; then
# Always pre-fill those so that the user can modify them in the
# commit template.
idline="$(git-var GIT_AUTHOR_IDENT)"
[ -z "$GIT_AUTHOR_NAME" ] && export GIT_AUTHOR_NAME="$(echo "$idline" | sed 's/ *<.*//')"
[ -z "$GIT_AUTHOR_EMAIL" ] && export GIT_AUTHOR_EMAIL="$(echo "$idline" | sed 's/.*<\(.*\)>.*/\1/')"
fi
force=
forceeditor=
ignorecache=
infoonly=
commitalways=
missingok=
amend=
review=
signoff=
copy_commit=
msgs=()
msgfile=
quiet=
no_hooks=
writeref=
push=
push_branch=
while optparse; do
if optparse --author=; then
load_author "$OPTARG" force
elif optparse -C; then
ignorecache=1
elif optparse -N; then
missingok=--missing-ok
infoonly=--info-only
elif optparse -e; then
forceeditor=1
elif optparse -E; then
forceeditor=1
commitalways=-f
elif optparse -f; then
force=1
elif optparse -q; then
quiet=1
elif optparse --amend; then
amend=1
copy_commit="$(cg-object-id -c HEAD)" || exit 1
elif optparse -p || optparse --review; then
review=1
forceeditor=1
elif optparse -s || optparse --signoff; then
[ "$signoff" ] || signoff="$(git-var GIT_AUTHOR_IDENT | sed 's/> .*/>/')"
elif optparse --signoff=; then
signoff="$OPTARG"
elif optparse -m=; then
msgs[${#msgs[@]}]="$OPTARG"
elif optparse -M=; then
msgfile="$OPTARG"
elif optparse -c=; then
copy_commit="$(cg-object-id -c "$OPTARG")" || exit 1
elif optparse --no-hooks; then
no_hooks=1
elif optparse -w=; then
writeref="$OPTARG"
elif optparse --push; then
push=1
elif optparse --push=; then
push=1
push_branch="$OPTARG"
else
optfail
fi
done
if [ -s "$_git/blocked" ] && [ ! "$writeref" ]; then
if [ "$force" ]; then
warn "committing to a blocked repository. Assuming you know what are you doing."
else
die "committing blocked: $(cat "$_git/blocked")"
fi
fi
# Deprecated as of 2006-11-17
[ -s "$_git/merging" ] && die "old-style merge state detected, panicking; you upgraded cogito in the middle of a merge! redo the merge, cg-reset will bring you back to the starting line"
mstatedir="$_git/cg-merge-state"
if [ ! "$ignorecache" ]; then
cg-object-id HEAD >/dev/null 2>&1 || ignorecache=1
fi
editor=
[ "$forceeditor" ] && editor=1
no_custom_messages=
[ ! "$msgs" ] && [ ! "$msgfile" ] && no_custom_messages=1
[ "$no_custom_messages" ] && [ ! "$copy_commit" ] && editor=1
tmpdir="$(mktemp -d -t gitci.XXXXXX)"
cleanup () { rm -rf "$tmpdir"; }
cleanup_trap "cleanup"
trap "cleanup" EXIT
if [ "$review" ]; then
PATCH="$tmpdir/patch.diff"
PATCH2="$tmpdir/patch2.diff"
editor=1
fi
if [ "$amend" ]; then
[ "$merging" ] && die "cannot amend previous commit in the middle of a merge"
# Recommit even with no changes to the content; meta might change
force=1
fi
[ "$push" ] && [ "$merging" ] && die "no support for auto-pushing merge commits"
if [ "$ARGS" -o "$_git_relpath" ]; then
[ "$ignorecache" ] && die "you cannot list files for the initial commit"
[ -s "$mstatedir/merging" ] && die "cannot commit individual files when merging"
filter="$tmpdir/filter"
[ "$_git_relpath" -a ! "$ARGS" ] && echo "$_git_relpath" >>"$filter"
for file in "${ARGS[@]}"; do
echo "${_git_relpath}$file" >>"$filter"
done
eval "commitfiles=($(cat "$filter" | path_xargs git-diff-index --name-status -z -r -m HEAD -- | \
perl -n0e 'chomp; if (defined $meta) { s/([\"\\])/\\\1/; print "\"$meta $_\"\n"; $meta=undef } else { $meta = $_ }'))"
customfiles=1
[ "$review" ] && cat "$filter" | path_xargs git-diff-index -r -m -p HEAD -- > "$PATCH"
rm "$filter"
else
# We bother with added/removed files here instead of updating
# the cache at the time of cg-(add|rm), since we want to
# have the cache in a consistent state representing the tree
# as it was the last time we committed. Otherwise, e.g. partial
# conflicts would be a PITA since added/removed files would
# be committed along automagically as well.
if [ ! "$ignorecache" ]; then
# \t instead of the tab character itself works only with new
# sed versions.
eval "commitfiles=($(git-diff-index --name-status -z -r -m HEAD | \
perl -n0e 'chomp; if (defined $meta) { s/([\"\\])/\\\1/; print "\"$meta $_\"\n"; $meta=undef } else { $meta = $_ }'))"
if [ -s "$mstatedir/commit-ignore" ]; then
newcommitfiles=()
for file in "${commitfiles[@]}"; do
fgrep -qx "${file:2}" "$mstatedir/commit-ignore" && continue
newcommitfiles[${#newcommitfiles[@]}]="$file"
done
commitfiles=("${newcommitfiles[@]}")
fi
fi
[ "$review" ] && git-diff-index -r -m -p HEAD > "$PATCH"
merging=
[ -s "$mstatedir/merging" ] && merging="$(cat "$mstatedir/merging" | sed 's/^/-p /')"
fi
if [ "$review" ]; then
LOGMSG="$tmpdir/logmsg.diff"
LOGMSG2="$tmpdir/logmsg2.diff"
else
LOGMSG="$tmpdir/logmsg"
LOGMSG2="$tmpdir/logmsg2"
fi
written=
if [ "$merging" ] && [ ! "$editor" ]; then
warn "suppressing default merge log messages in favour of the custom -m passed to me."
elif [ "$merging" ]; then
echo -n 'Merge with ' >>"$LOGMSG"
[ -s "$mstatedir/merging-sym" ] || cp "$mstatedir/merging" "$mstatedir/merging-sym"
for sym in $(cat "$mstatedir/merging-sym"); do
uri="$(cat "$_git/branches/$sym" 2>/dev/null)"
[ "$uri" ] || uri="$sym"
echo "$uri" >>"$LOGMSG"
done
echo >>"$LOGMSG"
if [ -s "$mstatedir/squashing" ]; then
# We are squashing all the merged commits to a single one.
# Therefore, helpfully pre-fill the commit message with
# the messages of all the merged commits.
git-rev-list --pretty "$(cat "$mstatedir/merging")" ^HEAD >>"$LOGMSG"
fi
written=1
fi
for msg in "${msgs[@]}"; do
[ "$written" ] && echo >>"$LOGMSG"
echo "$msg" | fmt -s >>"$LOGMSG"
written=1
done
if [ "$copy_commit" ]; then
[ "$written" ] && echo >>"$LOGMSG"
eval "$(git-cat-file commit "$copy_commit" | pick_author)"
# --amend -m _replaces_ the original message
if [ ! "$amend" ] || [ "$editor" ] || [ "$no_custom_messages" ]; then
git-cat-file commit "$copy_commit" | sed -e '1,/^$/d' >>"$LOGMSG"
written=1
fi
fi
if [ "$msgfile" ]; then
[ "$written" ] && echo >>"$LOGMSG"
cat "$_git_relpath$msgfile" >>"$LOGMSG" || exit 1
written=1
fi
add_signoff() {
local logmsg="$1"
if [ "$signoff" ] && ! grep -q -i "signed-off-by: $signoff" $logmsg; then
grep -q -i signed-off-by $logmsg || echo
echo "Signed-off-by: $signoff"
fi >>"$logmsg"
}
if editor_shalluse "$forceeditor"; then
# Always have at least one blank line, to ease the editing for
# the poor people whose text editor has no 'O' command.
[ "$written" ] || echo >>"$LOGMSG"
# Also, add the signoff line _now_ before spewing out CG: lines.
# (In case of non-tty input we do it later after taking the actual
# log message from stdin.)
add_signoff "$LOGMSG"
fi
# CG: -----------------------------------------------------------------------
editor_comment_start commit
if [ "$GIT_AUTHOR_NAME" -o "$GIT_AUTHOR_EMAIL" -o "$GIT_AUTHOR_DATE" ]; then
echo "CG:" >>"$LOGMSG"
[ "$GIT_AUTHOR_NAME" ] && echo "CG: Author: $GIT_AUTHOR_NAME" >>"$LOGMSG"
[ "$GIT_AUTHOR_EMAIL" ] && echo "CG: Email: $GIT_AUTHOR_EMAIL" >>"$LOGMSG"
[ "$GIT_AUTHOR_DATE" ] && echo "CG: Date: $GIT_AUTHOR_DATE" >>"$LOGMSG"
echo "CG:" >>"$LOGMSG"
fi
if [ ! "$ignorecache" ] && [ ! "$review" ]; then
if [ ! "$merging" ]; then
if [ ! "$force" ] && [ ! "${commitfiles[*]}" ]; then
rm "$LOGMSG"
[ "$quiet" ] && exit 0 || die 'Nothing to commit'
fi
echo "CG: By deleting lines beginning with CG:F, the associated file" >>"$LOGMSG"
echo "CG: will be removed from the commit list." >>"$LOGMSG"
fi
echo "CG:" >>"$LOGMSG"
echo "CG: Modified files:" >>"$LOGMSG"
for file in "${commitfiles[@]}"; do
# TODO: Prepend a letter describing whether it's addition,
# removal or update. Or call git status on those files.
echo "CG:F $file" >>"$LOGMSG"
[ ! "$editor" ] && echo "$file"
done
if [ -s "$mstatedir/commit-ignore" ]; then
echo "CG:" >>"$LOGMSG"
echo "CG: I have kept back the $(wc -l "$mstatedir/commit-ignore" | cut -d ' ' -f 1) file(s) containing your local changes." >>"$LOGMSG"
echo "CG: You need not worry, the local changes will not interfere with the merge." >>"$LOGMSG"
fi
fi
if [ "$review" ]; then
echo "CG: Changes summary:"
echo "CG:"
git-apply --stat --summary < "$PATCH" | sed 's/^/CG: /'
echo "CG:"
fi >>"$LOGMSG"
# CG: -----------------------------------------------------------------------
editor_comment_end $commitalways commit
ftdiff=
if [ "$review" ]; then
{
echo "CG:"
echo "CG: The patch being committed:"
echo "CG: (You can edit it; your tree will be modified accordingly and"
echo "CG: the modified patch will be committed.)"
echo "CG:"
cat "$PATCH"
} >>"$LOGMSG"
fi
editor_msg_end
cp "$LOGMSG" "$LOGMSG2"
if editor_shalluse "$forceeditor"; then
if [ "$editor" ] && ! editor $commitalways commit c; then
rm "$LOGMSG" "$LOGMSG2"
[ "$review" ] && rm "$PATCH"
echo "Commit message not modified, commit aborted" >&2
if [ "$merging" ]; then
cat >&2 <<__END__
Note that the merge is NOT aborted - you can cg-commit again, cg-reset will abort it.
__END__
[ -s "$mstatedir/commit-ignore" ] && cat >&2 <<__END__
(But note that cg-reset will remove your pending local changes as well!)
__END__
fi
exit 1
fi
if [ ! "$ignorecache" ] && [ ! "$merging" ] && [ ! "$review" ]; then
eval "newcommitfiles=($(grep ^CG:F "$LOGMSG2" | sed -e 's/\"/\\&/g' -e 's/^CG:F *\(.*\)$/"\1"/'))"
if [ ! "$force" ] && [ ! "${newcommitfiles[*]}" ]; then
rm "$LOGMSG" "$LOGMSG2"
[ "$quiet" ] && exit 0 || die 'Nothing to commit'
fi
if [ "${commitfiles[*]}" != "${newcommitfiles[*]}" ]; then
commitfiles=("${newcommitfiles[@]}")
customfiles=1
fi
fi
editor_parse_setif GIT_AUTHOR_NAME Author
editor_parse_setif GIT_AUTHOR_EMAIL Email
editor_parse_setif GIT_AUTHOR_DATE Date
else
cat >>"$LOGMSG2"
add_signoff "$LOGMSG2"
fi
if [ ! "$review" ]; then
editor_parse_clean
else
sed '/^CG: Changes summary:/,$d' < "$LOGMSG2" > "$LOGMSG"
sed -n '/^CG: Changes summary:/,$p' < "$LOGMSG2" | grep -v ^CG: > "$PATCH2"
mv "$LOGMSG" "$LOGMSG2"; editor_parse_clean
fi
rm "$LOGMSG2"
if [ "$review" ]; then
if ! cmp -s "$PATCH" "$PATCH2"; then
echo "Reverting the original patch..."
if ! cg-patch -R < "$PATCH"; then
die "unable to revert the original patch; the original patch is available in $PATCH, your edited patch is available in $PATCH2, your log message is in $LOGMSG, your working copy is in undefined state now and the world is about to end in ten minutes, have a nice day"
fi
echo "Applying the edited patch..."
if ! cg-patch < "$PATCH2"; then
# FIXME: Do something better to alleviate this situation.
# At least restore the tree to the original state.
die "unable to apply the edited patch; the original patch is available in $PATCH, your edited patch is available in $PATCH2, your log message is in $LOGMSG, your working copy is in undefined state now and the world is about to end in five minutes, have a nice day"
fi
fi
fi
precommit_update()
{
queueN=(); queueD=(); queueM=();
for file in "$@"; do
op="${file%% *}"
fname="${file#* }"
[ "$op" = "N" ] && op=A # N is to be renamed to A
[ "$op" = "A" ] || [ "$op" = "D" ] || [ "$op" = "M" ] || op=M
eval "queue$op[\${#queue$op[@]}]=\"\$fname\""
done
oldIFS="$IFS"
IFS=$'\n'
# XXX: Do we even need to do the --add and --remove update-caches?
[ "$queueA" ] && { ( echo "${queueA[*]}" | path_xargs git-update-index --add ${infoonly} -- ) || return 1; }
[ "$queueD" ] && { ( echo "${queueD[*]}" | path_xargs git-update-index --force-remove -- ) || return 1; }
[ "$queueM" ] && { ( echo "${queueM[*]}" | path_xargs git-update-index ${infoonly} -- ) || return 1; }
IFS="$oldIFS"
return 0
}
if [ ! "$ignorecache" ]; then
if [ "$customfiles" ]; then
precommit_update "${commitfiles[@]}" || die "update-cache failed"
export GIT_INDEX_FILE="$tmpdir/index"
git-read-tree HEAD
fi
precommit_update "${commitfiles[@]}" || die "update-cache failed"
fi
oldhead=
oldheadname="$(git-symbolic-ref HEAD)"
if [ -s "$_git/$oldheadname" ]; then
oldhead="$(get_ref "$oldheadname")"
oldheadstr="-p $oldhead"
fi
if [ "$amend" ]; then
oldheadstr="$(cg-object-id -p "$oldhead" | sed 's/^/-p /')"
fi
treeid="$(git-write-tree ${missingok})"
[ "$treeid" ] || die "git-write-tree failed"
if [ ! "$force" ] && [ ! "$merging" ] && [ "$oldhead" ] &&
[ "$treeid" = "$(cg-object-id -t)" ]; then
echo "Refusing to make an empty commit - the tree was not modified" >&2
echo "since the previous commit. If you really want to make the" >&2
echo "commit, pass cg-commit the -f argument." >&2
exit 2;
fi
[ -s "$mstatedir/squashing" ] && merging=" " # viciously prevent recording a proper merge
newhead=$(git-commit-tree $treeid $oldheadstr $merging <"$LOGMSG")
rm "$LOGMSG"
if [ "$customfiles" ]; then
rm "$GIT_INDEX_FILE"
export GIT_INDEX_FILE=
fi
commit_over()
{
echo "Committed as $newhead"
commit_cleanup
}
commit_cleanup()
{
rm -rf "$mstatedir"
}
if [ "$push" ]; then
pushargs=()
[ "$push_branch" ] && pushargs[${#pushargs[@]}]="$push_branch"
if ! cg-push -r "$newhead" "${pushargs[@]}"; then
commit_cleanup
die "push failed, you probably need to cg-update and try again (use cg-commit -c $newhead ... to reuse the log message)"
fi
fi
if [ "$newhead" ] && [ "$writeref" ]; then
echo "$newhead" >"$writeref" || die "unable to move to the new commit $newhead inside $writeref"
commit_over
elif [ "$newhead" ]; then
git-update-ref HEAD $newhead $oldhead || die "unable to move to the new commit $newhead"
commit_over
# Trigger the postcommit hook
branchname=
if [ -s "$_git/branch-name" ]; then
warn ".git/branch-name is deprecated and support for it will be removed soon."
warn "So please stop relying on it, or complain at pasky@suse.cz. Thanks."
branchname="$(cat "$_git/branch-name")"
fi
[ -z "$branchname" ] && [ "$_git_head" != "master" ] && branchname="$_git_head"
if [ -x "$_git/hooks/commit-post" -o -x "$_git/hooks/post-commit" ] && [ ! "$no_hooks" ]; then
if [ "$(git-repo-config --bool cogito.hooks.commit.post.allmerged)" = "true" ]; then
# We just hope that for the initial commit, the user didn't
# manage to install the hook yet.
for merged in $(git-rev-list $newhead ^$oldhead | tac); do
[ -x "$_git/hooks/commit-post" ] && "$_git/hooks/commit-post" "$merged" "$branchname"
[ -x "$_git/hooks/post-commit" ] && "$_git/hooks/post-commit" "$merged" "$branchname"
done
else
[ -x "$_git/hooks/commit-post" ] && "$_git/hooks/commit-post" "$newhead" "$branchname"
[ -x "$_git/hooks/post-commit" ] && "$_git/hooks/post-commit" "$newhead" "$branchname"
fi
fi
exit 0
else
commit_cleanup
die "error during commit (oldhead $oldhead, treeid $treeid)"
fi